如何修改动态库符号表
如何修改動態(tài)庫符號表
??? 一、ELF 文件和有關術語
Unix 系統(tǒng)的可執(zhí)行文件和動態(tài)庫文件是以 ELF 格式存放的。為使下面的敘述
清晰而沒有伎義,先簡要介紹一下 ELF 文件格式,并約定一些術語。關于ELF
文件格式的詳細情況請參看有關文獻。
ELF 文件中代碼、連接信息和注釋是以節(jié)(section)為單位存放的,并存有一
個節(jié)頭表(section header)。對每一節(jié),在節(jié)頭表中都有一個表項(節(jié)頭表項)
與之對應,表項記錄了該節(jié)的一些信息,例如該節(jié)在文件中的位置信息和該節(jié)
的字節(jié)長度信息。
程序運行讀入內(nèi)存時,是以程序段(program segment)為單位讀入的。在 ELF
文件中有一個程序頭表(program header table),每個程序段在程序頭表中有
一個表項(程序頭表項)與之對應,表項記錄了該程序段的有關信息,例如該程
序段在文件中的位置信息和該程序段的字節(jié)長度信息。程序段的內(nèi)容由若干節(jié)
組成,節(jié)的內(nèi)容組合在一起連成一片構成程序段的內(nèi)容。
在所有這些節(jié)中,有一節(jié)的內(nèi)容由字符串構成,這些字符串是各節(jié)的名稱,叫
節(jié)名。下面稱這一節(jié)為節(jié)名表。另有一節(jié),節(jié)名為".dynsym",它的內(nèi)容為符
號表,符號表的每一表項記錄了一個符號的有關信息,例如該符號對應的代碼
的地址值。還有一節(jié),節(jié)名為".dynstr",它的內(nèi)容由字符串構成。大多數(shù)符
號在該節(jié)中有一個字符串與之對應,這個字符串是該符號的符號名。而每一函
數(shù)對應一個符號,函數(shù)名即為符號名。下面稱被某一函數(shù)對應的符號為函數(shù)符
號。
ELF 文件開始處的一段叫 ELF 文件頭。它記錄了程序頭表在文件中的偏移、
程序頭表的表項數(shù)目、程序頭表每一表項的字節(jié)長度、節(jié)頭表在文件中的偏移、
節(jié)頭表的表項數(shù)目、節(jié)頭表每個表項的字節(jié)長度。它還記錄了節(jié)名表所在的節(jié)
的索引序號。
二、動態(tài)庫符號表修改方法
修改動態(tài)庫符號表的方法和步驟如下:
第一步:
讀取 ELF 文件頭,取出
??? (1) 程序頭表在文件中的偏移,獲取程序頭表在文件中的位置;
??? (2) 程序頭表的表項數(shù)目和程序頭表每一表項的字節(jié)長度;
??? (3) 節(jié)頭表在文件中的偏移,獲取節(jié)頭表在文件中的位置;
??? (4) 節(jié)頭表的表項數(shù)目和節(jié)頭表每個表項的字節(jié)長度;
??? (3) 節(jié)名表所在的節(jié)的索引序號。
ELF 文件頭在文件中的偏移為零,即起始于 ELF 文件開頭的第一字節(jié),它的
數(shù)據(jù)結構為:
#define EI_NIDENT (16)
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Word;
typedef uint32_t Elf32_Addr;
typedef uint32_t Elf32_Off;
typedef uint16_t Elf32_Section;
typedef struct
{
?? unsigned char e_ident[EI_NIDENT];? /* Magic number及其他信息 */
?? Elf32_Half??? e_type;????????????? /* ELF 文件類型 */
?? Elf32_Half??? e_machine;?????????? /* 機器型號 */
?? Elf32_Word??? e_version;?????????? /* 版本 */
?? Elf32_Addr??? e_entry;???????????? /* 程序入口虛地址 */
?? Elf32_Off???? e_phoff;???????????? /* 程序頭表在文件中的偏移 */
?? Elf32_Off???? e_shoff;???????????? /* 節(jié)頭表在文件中的偏移 */
?? Elf32_Word??? e_flags;???????????? /* 處理器標志 */
?? Elf32_Half??? e_ehsize;??????????? /* ELF 文件頭長度 */
?? Elf32_Half??? e_phentsize;???????? /* 程序頭表每個表項長度 */
?? Elf32_Half??? e_phnum;???????????? /* 程序頭表的表項總數(shù) */
?? Elf32_Half??? e_shentsize;???????? /* 節(jié)頭表每個表項長度 */
?? Elf32_Half??? e_shnum;???????????? /* 節(jié)頭表的表項總數(shù) */
?? Elf32_Half??? e_shstrndx;????????? /* 節(jié)名表所在的節(jié)的表項索引號 */
} Elf32_Ehdr;
第二步:
依據(jù)節(jié)頭表在文件中的偏移和節(jié)名表所在的節(jié)的索引序號,定出節(jié)名表在節(jié)頭
表中對應的表項的文件偏移,即定出該表項在文件中的位置。讀取該表項,取
出節(jié)名表在文件中的偏移和該節(jié)在文件中的字節(jié)長度。節(jié)頭表由若干表項組成,
每個表項的內(nèi)容按下面的數(shù)據(jù)結構來組織:
typedef struct
{
?? Elf32_Word??? sh_name;???????????? /* 節(jié)名索引號 */
?? Elf32_Word??? sh_type;???????????? /* 節(jié)類型 */
?? Elf32_Word??? sh_flags;??????????? /* 節(jié)標志 */
?? Elf32_Addr??? sh_addr;???????????? /* 執(zhí)行時該節(jié)虛地址 */
?? Elf32_Off???? sh_offset;?????????? /* 在文件中的偏移 */
?? Elf32_Word??? sh_size;???????????? /* 節(jié)長度 */
?? Elf32_Word??? sh_link;???????????? /* 到其他節(jié)的連接 */
?? Elf32_Word??? sh_info;???????????? /* 其他信息 */
?? Elf32_Word??? sh_addralign;??????? /* alignment */
?? Elf32_Word??? sh_entsize;????????? /* 如內(nèi)容為表,每個表項的長度 */
} Elf32_Shdr;
第三步:
按節(jié)名表在文件中的偏移和該節(jié)的長度讀取節(jié)名表,并緩存在一個緩沖區(qū)中。
第四步:
依據(jù)節(jié)頭表在文件中的偏移、節(jié)頭表的表項總數(shù)、以及節(jié)頭表每個表項長度搜
索節(jié)頭表。對每個節(jié)頭表項,讀出節(jié)名索引號,由節(jié)名索引號從上面緩存在緩
沖區(qū)中節(jié)名表得出該節(jié)頭表項對應的節(jié)的名字。如果名字為".dynsym",記錄
該節(jié)的在文件中的偏移和字節(jié)長度。名字為 ".dynsym" 的節(jié)的內(nèi)容是符號表,
除了記錄它在文件中的偏移和字節(jié)長度外,還要記下它的每個表項的長度。每
個表項即是對一個符號所記錄的信息,表項的數(shù)據(jù)結構為:
typedef struct
{
?? Elf32_Word??? st_name;?????? /* 符號名索引號 */
?? Elf32_Addr??? st_value;????? /* 符號地址值 */
?? Elf32_Word??? st_size;?????? /* 符號對應的代碼長度 */
?? unsigned char st_info;?????? /* 符號類型和梆定信息 */
?? unsigned char st_other;????? /* 未用,值為 0 */
?? Elf32_Section st_shndx;????? /* 所在節(jié)的節(jié)索引號 */
} Elf32_Sym;
在搜索節(jié)頭表時,除了找 ".dynsym" 節(jié)外,還要找到名字為 ".dynstr" 的節(jié),
記下它的在文件中的偏移和字節(jié)長度。由該結在文件中的偏移和字節(jié)長度讀取
它的內(nèi)容,并緩存在一個緩沖區(qū)中。
第五步:
按第四步中得到的 ..dynsym節(jié)的字節(jié)長度和符號表的表項的長度算出符號表表
項數(shù)目,也即符號的數(shù)目。然后依據(jù)第四步中得到的符號表(即.dynsym節(jié))在
文件中的偏移把文件指針打到符號表所在的位置,檢索符號表找到要修改的符
號。方法是從符號表表項中讀出符號名索引號(st_name)的值,這個值即是該
表項記錄其信息的符號的符號名字符串在 .dynstr 節(jié)中的偏移,由這個值在
第四步中緩存 .dynstr 節(jié)的緩沖區(qū)中取出符號名,把符號名和要找的符號的
符號名進行比較。
第六步:
第五步中找到了要修改的符號,現(xiàn)在可以進行修改了。所謂修改符號就是修改
該符號在符號表(.dynsym 節(jié))中表項,因為表項的內(nèi)容是對該符號的有關信
息的記錄。hook 時需要關注的是符號地址值(st_value)和符號對應的代碼長
度(st_size)。可以把符號地址值(st_value)和符號對應的代碼長度(st_size)
修改為動態(tài)庫中另一符號的相應的 st_value 和 st_size 值。通常修改的是
函數(shù)符號。如果是函數(shù)符號,那么修改后當調(diào)用該函數(shù)時,實際調(diào)用的是上面
修改時取其 st_value 和 st_size 值的另一符號所對應的函數(shù)。也可以向ELF
文件中加入的一段幾十字節(jié)的 shellcode 或其他代碼,修改符號表時把所修
改的符號在符號表中的表項的 st_value 值指向這段 shellcode 或其他代碼,
st_size 的值置為這段代碼的字節(jié)長度。那么,程序調(diào)用被修改的符號所對應
的函數(shù)時,實際調(diào)用的是這段 shellcode 或其他代碼。
三、示例程序
為對上面所說的進行解釋,下面的給出一個示例程序。它打印出 ELF 文件的
有關信息,然后通過修改符號表把動態(tài)庫的函數(shù)1 hook 到函數(shù)2。這樣做以后,
如果某程序編譯時與該動態(tài)庫連接了,它調(diào)用函數(shù)1時,程序運行時實際調(diào)用
的是函數(shù)2。函數(shù)2可以是動態(tài)庫本身就有的函數(shù),也可以是你向 ELF 文件中
偷偷加入的一段幾十字節(jié)的 shellcode。這是向系統(tǒng)置入后門的一個方法,特
別是 hook 經(jīng)常被調(diào)用的動態(tài)庫。
測試時做了一個小動態(tài)庫,它僅有兩個函數(shù) haha() 和 huhu():
________________________________________________________
/* haha.c */
#include <stdio.h>
void haha(void)
{
?? printf(" --- haha/n");
?? return;
}
________________________________________________________
/* huhu.c */
#include <stdio.h>
void huhu(void)
{
?? printf(" --- huhu/n");
?? return;
}
________________________________________________________
[wangdb@redhat62 exploit]$ gcc -c -fPIC -O3 haha.c huhu.c
[wangdb@redhat62 exploit]$ gcc -shared haha.o huhu.o -o libtst.so.1.0
[wangdb@redhat62 exploit]$ ln -s libtst.so.1.0 libtst.so
程序 m.c 調(diào)用 huhu() 和 haha():
________________________________________________________
/* m.c */
int main()
{
?? haha();
?? huhu();
?? return 0;
}
________________________________________________________
[wangdb@redhat62 exploit]$ gcc m.c -L. -ltst -o ttt
[wangdb@redhat62 exploit]$ gcc -O3 hook_elf.c -o elf_hook
[wangdb@redhat62 exploit]$ ./ttt
--- haha
--- huhu
[wangdb@redhat62 exploit]$ ./elf_hook libtst.so huhu haha
? .
? .
? .
[wangdb@redhat62 exploit]$ ./ttt
--- haha
--- haha
[wangdb@redhat62 exploit]$
下面是 hook_elf.c 程序:
_______________________________________________________________________
_________
/*
* C Program File: hook_elf.c? ---
*
* Description: This program read and print relevant information of ELF
*????????????? File, then hook function fun1 to fun2. After hooking,
when
*????????????? some program call function fun1, actually it is fun2
being
*????????????? called.
* Usage:
*???????? hook_elf <lib***.so> <dst_sym> <src_sym>
*???????? (Note: when dst_sym == src_sym, ELF file is not changed.)
*
* Author: wangdb (wangdb@nsfocus.com)
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#define EI_NIDENT (16)
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Word;
typedef uint32_t Elf32_Addr;
typedef uint32_t Elf32_Off;
typedef uint16_t Elf32_Section;
/* 下面的數(shù)據(jù)結構定義取自 elf.h 頭文件 */
/* The ELF file header. This appears at the start of every ELF file. */
typedef struct
{
?? unsigned char e_ident[EI_NIDENT];? /* Magic number and other info */
?? Elf32_Half??? e_type;????????????? /* Object file type */
?? Elf32_Half??? e_machine;?????????? /* Architecture */
?? Elf32_Word??? e_version;?????????? /* Object file version */
?? Elf32_Addr??? e_entry;???????????? /* Entry point virtual address */
?? Elf32_Off???? e_phoff;???????????? /* Program header table file
offset */
?? Elf32_Off???? e_shoff;???????????? /* Section header table file
offset */
?? Elf32_Word??? e_flags;???????????? /* Processor-specific flags */
?? Elf32_Half??? e_ehsize;??????????? /* ELF header size in bytes */
?? Elf32_Half??? e_phentsize;???????? /* Program header table entry
size */
?? Elf32_Half??? e_phnum;???????????? /* Program header table entry
count */
?? Elf32_Half??? e_shentsize;???????? /* Section header table entry
size */
?? Elf32_Half??? e_shnum;???????????? /* Section header table entry
count */
?? Elf32_Half??? e_shstrndx;????????? /* Section header string table
index */
} myElf32_Ehdr;
/* Program segment header. */
typedef struct
{
?? Elf32_Word??? p_type;????????????? /* Segment type */
?? Elf32_Off???? p_offset;??????????? /* Segment file offset */
?? Elf32_Addr??? p_vaddr;???????????? /* Segment virtual address */
?? Elf32_Addr??? p_paddr;???????????? /* Segment physical address */
?? Elf32_Word??? p_filesz;??????????? /* Segment size in file */
?? Elf32_Word??? p_memsz;???????????? /* Segment size in memory */
?? Elf32_Word??? p_flags;???????????? /* Segment flags */
?? Elf32_Word??? p_align;???????????? /* Segment alignment */
} myElf32_Phdr;
/* Section header. */
typedef struct
{
?? Elf32_Word??? sh_name;???????????? /* Section name (string tbl
index) */
?? Elf32_Word??? sh_type;???????????? /* Section type */
?? Elf32_Word??? sh_flags;??????????? /* Section flags */
?? Elf32_Addr??? sh_addr;???????????? /* Section virtual addr at
execution */
?? Elf32_Off???? sh_offset;?????????? /* Section file offset */
?? Elf32_Word??? sh_size;???????????? /* Section size in bytes */
?? Elf32_Word??? sh_link;???????????? /* Link to another section */
?? Elf32_Word??? sh_info;???????????? /* Additional section information
*/
?? Elf32_Word??? sh_addralign;??????? /* Section alignment */
?? Elf32_Word??? sh_entsize;????????? /* Entry size if section holds
table */
} myElf32_Shdr;
/* Symbol table entry. */
typedef struct
{
?? Elf32_Word??? st_name;???????????? /* Symbol name (string tbl index)
*/
?? Elf32_Addr??? st_value;??????????? /* Symbol value */
?? Elf32_Word??? st_size;???????????? /* Symbol size */
?? unsigned char st_info;???????????? /* Symbol type and binding */
?? unsigned char st_other;??????????? /* No defined meaning, 0 */
?? Elf32_Section st_shndx;??????????? /* Section index */
} myElf32_Sym;
/* The syminfo section if available contains additional information
about
?? every dynamic symbol. */
typedef struct
{
?? Elf32_Half si_boundto;???????????? /* Direct bindings, symbol bound
to */
?? Elf32_Half si_flags;?????????????? /* Per symbol flags */
} myElf32_Syminfo;
/* Main routine */
int main(int argc, char *argv[])
{
?? myElf32_Ehdr *e_hdr_ptr;
?? myElf32_Phdr *p_hdr_ptr;
?? myElf32_Shdr *s_hdr_ptr;
?? myElf32_Sym? *symptr;
?? myElf32_Syminfo *HashSymPtr;
?? int fd, i;
?? unsigned char buf[256];
?? unsigned int ProHdrFileOffset;
?? unsigned int SecHdrFileOffset;
?? unsigned int NamStrSecTblIndex;
?? unsigned int ProHdrTblEntrNum;
?? unsigned int SecHdrTblEntrNum;
?? unsigned int ProHdrTblEntrSize;
?? unsigned int SecHdrTblEntrSize;
?? unsigned int SecNamStrTblFileOffset = 0;
?? char SecNameStrTable[1024];
?? unsigned int SecNameIndex = 0;
?? unsigned char SymTblEntry[16];
?? unsigned int DebugInfoFileOffset = 0;
?? int DebugInfoSymTblNum = 0;
?? unsigned int DebugInfoStrTblFileOffset = 0;
?? char DebugInfoStrTable[4096];
?? unsigned int DebugInfoStrTblSize = 0;
?? unsigned int SymTblFileOffset = 0;
?? int SymTblNum = 0;
?? unsigned int SymNamStrTblFileOffset = 0;
?? char SymNamStrTable[2048];
?? unsigned int SymNamStrTblSize = 0;
?? unsigned int HashOffset = 0;
?? int HashTblNum = 0;
?? unsigned char src_sym[16], dst_sym[16];
?? unsigned char tmp_sym_addr[4];
?? unsigned char tmp_sym_size[4];
?? unsigned int src_sym_tbl = 0, dst_sym_tbl = 0;
?? if (argc < 4) {
????? fprintf(stderr, "Usage: %s <object_file> <dst_sym> <src_sym>/n",
argv[0]);
????? exit(1);
?? }
?? if ( (fd = open(argv[1], O_RDONLY)) == -1 ) {
????? fprintf(stderr, "Can't open file /"%s/"./n", argv[1]);
????? exit(1);
?? }
?? fprintf(stdout, "Dump content of the ELF file '%s'/n", argv[1]);
?? fprintf(stdout, "Part I: ELF File Header.../n");
?? /* 讀取 ELF 文件頭 */
?? if ( read(fd, buf, 52) != 52 ) {
????? fprintf(stderr, "read error/n");
????? close(fd); exit(1);
?? }
?? e_hdr_ptr = (myElf32_Ehdr *)buf;
?? fprintf(stdout, "(Magic number and other info)e_ident: %s/n",
??????????????????? e_hdr_ptr->e_ident);
?? fprintf(stdout, "(Object file type)e_type: 0x%04X/n",
??????????????????? e_hdr_ptr->e_type);
?? fprintf(stdout, "(Architecture)e_machine: 0x%04X/n",
??????????????????? e_hdr_ptr->e_machine);
?? fprintf(stdout, "(Object file version)e_version: 0x%08X/n",
??????????????????? e_hdr_ptr->e_version);
?? fprintf(stdout, "(Entry point virtual address)e_entry: 0x%08X/n",
??????????????????? e_hdr_ptr->e_entry);
?? fprintf(stdout, "(Program header table file offset)e_phoff: 0x%
08X/n",
??????????????????? e_hdr_ptr->e_phoff);
?? fprintf(stdout, "(Section header table file offset)e_shoff: 0x%
08X/n",
??????????????????? e_hdr_ptr->e_shoff);
?? fprintf(stdout, "(Processor-specific flags)e_flags: 0x%08X/n",
??????????????????? e_hdr_ptr->e_flags);
?? fprintf(stdout, "(ELF header size in bytes)e_ehsize: 0x%04X/n",
??????????????????? e_hdr_ptr->e_ehsize);
?? fprintf(stdout, "(Program header table entry size)e_phentsize: 0x%
04X/n",
??????????????????? e_hdr_ptr->e_phentsize);
?? fprintf(stdout, "(Program header table entry count)e_phnum: 0x%
04X/n",
??????????????????? e_hdr_ptr->e_phnum);
?? fprintf(stdout, "(Section header table entry size)e_shentsize: 0x%
04X/n",
??????????????????? e_hdr_ptr->e_shentsize);
?? fprintf(stdout, "(Section header table entry count)e_shnum: 0x%
04X/n",
??????????????????? e_hdr_ptr->e_shnum);
?? fprintf(stdout, "(Section header string table index)e_shstrndx: 0x%
04X/n",
??????????????????? e_hdr_ptr->e_shstrndx);
?? /* 記下程序頭表在文件中的偏移、節(jié)頭表在文件中的偏移、
????? 節(jié)名表所在的節(jié)的索引序號、程序頭表表項字節(jié)長度、程序頭表表項數(shù)目
、
????? 節(jié)頭表表項字節(jié)長度、節(jié)頭表表項數(shù)目。*/
?? ProHdrFileOffset? = (unsigned int)e_hdr_ptr->e_phoff;
?? SecHdrFileOffset? = (unsigned int)e_hdr_ptr->e_shoff;
?? NamStrSecTblIndex = (unsigned int)e_hdr_ptr->e_shstrndx;
?? ProHdrTblEntrNum? = (unsigned int)e_hdr_ptr->e_phnum;
?? SecHdrTblEntrNum? = (unsigned int)e_hdr_ptr->e_shnum;
?? ProHdrTblEntrSize = (unsigned int)e_hdr_ptr->e_phentsize;
?? SecHdrTblEntrSize = (unsigned int)e_hdr_ptr->e_shentsize;
?? fprintf(stdout, "Part II: Program Header Table.../n");
?? if ( lseek(fd, (off_t)ProHdrFileOffset, SEEK_SET) !=
ProHdrFileOffset ) {
????? fprintf(stderr, "lseek to program header error./n");
????? close(fd); exit(1);
?? }
?? for (i = 0; i < (int)ProHdrTblEntrNum; i++) {
????? if ( read(fd, buf, (size_t)ProHdrTblEntrSize) !=
?????????? (ssize_t)ProHdrTblEntrSize ) {
???????? fprintf(stderr, "read error/n");
???????? close(fd); exit(1);
????? }
????? fprintf(stdout, "Program Header Entry for Segment %d:/n", i + 1);
????? p_hdr_ptr = (myElf32_Phdr *)buf;
????? fprintf(stdout, "(Segment type)p_type: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_type);
????? fprintf(stdout, "(Segment flags)p_flags: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_flags);
????? fprintf(stdout, "(Segment file offset)p_offset: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_offset);
????? fprintf(stdout, "(Segment virtual address)p_vaddr: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_vaddr);
????? fprintf(stdout, "(Segment physical address)p_paddr: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_paddr);
????? fprintf(stdout, "(Segment size in file)p_filesz: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_filesz);
????? fprintf(stdout, "(Segment size in memory)p_memsz: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_memsz);
????? fprintf(stdout, "(Segment alignment)p_align: 0x%08X/n",
?????????????????????? p_hdr_ptr->p_align);
?? }
?? fprintf(stdout, "Part III: Section Header Table.../n");
?? /* 定出節(jié)名表所在的節(jié)在節(jié)頭表中對應的表項的文件偏移。*/
?? SecNamStrTblFileOffset = SecHdrFileOffset + NamStrSecTblIndex * 40;
?? if ( lseek(fd, (off_t)SecNamStrTblFileOffset, SEEK_SET) !=
??????? SecNamStrTblFileOffset || SecNamStrTblFileOffset == 0 ) {
????? fprintf(stderr,
??????? "lseek to Section Table Entry for Section Name String Table
error./n");
????? close(fd); exit(1);
?? }
?? if ( read(fd, buf, (size_t)SecHdrTblEntrSize) != (ssize_t)
SecHdrTblEntrSize ) {
????? fprintf(stderr, "read error/n");
????? close(fd); exit(1);
?? }
?? s_hdr_ptr = (myElf32_Shdr *)buf;
?? SecNamStrTblFileOffset = (unsigned int)s_hdr_ptr->sh_offset;
?? /* 讀取節(jié)名表,并緩存在一個緩沖區(qū)中。*/
?? if ( lseek(fd, (off_t)SecNamStrTblFileOffset, SEEK_SET) !=
??????? SecNamStrTblFileOffset || SecNamStrTblFileOffset == 0 ) {
????? fprintf(stderr, "lseek to Section Name String Table error./n");
????? close(fd); exit(1);
?? }
?? if ( read(fd, SecNameStrTable, (size_t)s_hdr_ptr->sh_size) !=
??????? (ssize_t)s_hdr_ptr->sh_size ) {
????? fprintf(stderr, "read error/n");
????? close(fd); exit(1);
?? }
?? if ( lseek(fd, (off_t)SecHdrFileOffset, SEEK_SET) !=
SecHdrFileOffset ||
??????? SecHdrFileOffset == 0 ) {
????? fprintf(stderr, "lseek to section header error./n");
????? close(fd); exit(1);
?? }
?? /* 記錄符號表(即.dynsym節(jié))在文件中的偏移,由它的字節(jié)長度和每個表項
的
????? 長度算出符號表的表項數(shù)目。同時記下.dynstr節(jié)在文件中的偏移和字節(jié)長
度。*/
?? for (i = 0; i < (int)SecHdrTblEntrNum; i++) {
????? if ( read(fd, buf, (size_t)SecHdrTblEntrSize) !=
?????????? (ssize_t)SecHdrTblEntrSize ) {
???????? fprintf(stderr, "read error/n");
???????? close(fd); exit(1);
????? }
????? s_hdr_ptr = (myElf32_Shdr *)buf;
????? /*if ( s_hdr_ptr->sh_type == 0x3 && s_hdr_ptr->sh_name == 0x11 )
{
???????? SecNamStrTblFileOffset = (unsigned int)s_hdr_ptr->sh_offset;
????? }*/
????? if ( strcmp(SecNameStrTable + s_hdr_ptr->sh_name, ".symtab") == 0
) {
???????? DebugInfoFileOffset = (unsigned int)s_hdr_ptr->sh_offset;
???????? DebugInfoSymTblNum = (int)((s_hdr_ptr->sh_size)/(s_hdr_ptr-
>sh_entsize));
????? }
????? if ( strcmp(SecNameStrTable + s_hdr_ptr->sh_name, ".strtab") == 0
) {
???????? DebugInfoStrTblFileOffset = (unsigned int)s_hdr_ptr-
>sh_offset;
???????? DebugInfoStrTblSize = (unsigned int)s_hdr_ptr->sh_size;
????? }
????? if ( strcmp(SecNameStrTable + s_hdr_ptr->sh_name, ".dynsym") == 0
) {
???????? SymTblFileOffset = (unsigned int)s_hdr_ptr->sh_offset;
???????? SymTblNum = (int)((s_hdr_ptr->sh_size)/(s_hdr_ptr-
>sh_entsize));
????? }
????? if ( strcmp(SecNameStrTable + s_hdr_ptr->sh_name, ".dynstr") == 0
) {
???????? SymNamStrTblFileOffset = (unsigned int)s_hdr_ptr->sh_offset;
???????? SymNamStrTblSize = (unsigned int)s_hdr_ptr->sh_size;
????? }
????? if ( strcmp(SecNameStrTable + s_hdr_ptr->sh_name, ".hash") == 0 )
{
???????? HashOffset = (unsigned int)s_hdr_ptr->sh_offset;
???????? HashTblNum = (int)((s_hdr_ptr->sh_size)/(s_hdr_ptr-
>sh_entsize));
????? }
?? }
?? if ( lseek(fd, (off_t)SecHdrFileOffset, SEEK_SET) !=
SecHdrFileOffset ) {
????? fprintf(stderr, "lseek to section header error./n");
????? close(fd); exit(1);
?? }
?? for (i = 0; i < (int)SecHdrTblEntrNum; i++) {
????? if ( read(fd, buf, (size_t)SecHdrTblEntrSize) !=
?????????? (ssize_t)SecHdrTblEntrSize ) {
???????? fprintf(stderr, "read error/n");
???????? close(fd); exit(1);
????? }
????? s_hdr_ptr = (myElf32_Shdr *)buf;
????? fprintf(stdout, "Section %d:/n", i);
????? SecNameIndex = (unsigned int)s_hdr_ptr->sh_name;
????? fprintf(stdout, "(Section name (string tbl index))sh_name: 0x%08X
-> %s/n",
?????????????????????? s_hdr_ptr->sh_name, SecNameStrTable +
SecNameIndex);
????? fprintf(stdout, "(Section type)sh_type: 0x%08X/n",
?????????????????????? s_hdr_ptr->sh_type);
????? fprintf(stdout, "(Section flags)sh_flags: 0x%08X/n",
?????????????????????? s_hdr_ptr->sh_flags);
????? fprintf(stdout, "(Section virtual addr at execution)sh_addr: 0x%
08X/n",
?????????????????????? s_hdr_ptr->sh_addr);
????? fprintf(stdout, "(Section file offset)sh_offset: 0x%08X/n",
?????????????????????? s_hdr_ptr->sh_offset);
????? fprintf(stdout, "(Section size in bytes)sh_size: 0x%08X/n",
?????????????????????? s_hdr_ptr->sh_size);
????? fprintf(stdout, "(Link to another section)sh_link: 0x%08X/n",
?????????????????????? s_hdr_ptr->sh_link);
????? fprintf(stdout, "(Additional section information)sh_info: 0x%
08X/n",
?????????????????????? s_hdr_ptr->sh_info);
????? fprintf(stdout, "(Section alignment)sh_addralign: 0x%08X/n",
?????????????????????? s_hdr_ptr->sh_addralign);
????? fprintf(stdout, "(Entry size if section holds table)sh_entsize:
0x%08X/n",
?????????????????????? s_hdr_ptr->sh_entsize);
?? }
?? fprintf(stdout,
"**********************************************************************
**/n");
?? if ( lseek(fd, (off_t)DebugInfoStrTblFileOffset, SEEK_SET) !=
??????? DebugInfoStrTblFileOffset || DebugInfoStrTblFileOffset == 0 ) {
????? fprintf(stderr, "lseek to Debug Info String Table error./n");
????? goto next;
?? }
?? read(fd, DebugInfoStrTable, (size_t)(DebugInfoStrTblSize + 1));
?? if ( lseek(fd, (off_t)DebugInfoFileOffset, SEEK_SET) !=
??????? DebugInfoFileOffset || DebugInfoFileOffset == 0 ) {
????? fprintf(stderr, "lseek to Debug Info Symbol Table error./n");
????? goto next;
?? }
?? for (i = 0; i < DebugInfoSymTblNum; i++) {
????? read(fd, SymTblEntry, (size_t)16);
????? symptr = (myElf32_Sym *)SymTblEntry;
????? fprintf(stdout, "Debug Infomation -> Symbol ID: %d/n", i);
????? fprintf(stdout, "Symbol_index_and_name: 0x%08X -> %s/n",
??????????????????? symptr->st_name, DebugInfoStrTable + symptr-
>st_name);
????? fprintf(stdout, "Symbol_value: 0x%08X/n", symptr->st_value);
????? fprintf(stdout, "Symbol_size: 0x%08X/n", symptr->st_size);
????? fprintf(stdout, "Symbol_type_and_binding: 0x%02X/n", symptr-
>st_info);
????? fprintf(stdout, "Section_index: 0x%04X/n", symptr->st_shndx);
????? fprintf(stdout,
???????? "--------------------------------------------------------/n");
?? }
?? fprintf(stdout,
"**********************************************************************
**/n");
next:
?? /* 讀取 .dynstr 節(jié)的內(nèi)容,并緩存在一個緩沖區(qū)中。*/
?? if ( lseek(fd, (off_t)SymNamStrTblFileOffset, SEEK_SET) !=
??????? SymNamStrTblFileOffset || SymNamStrTblFileOffset == 0 ) {
????? fprintf(stderr, "lseek to Dynamical symbol name string
error./n");
????? close(fd); exit(1);
?? }
?? read(fd, SymNamStrTable, (size_t)(SymNamStrTblSize + 1));
?? if ( lseek(fd, (off_t)SymTblFileOffset, SEEK_SET) !=
SymTblFileOffset ||
??????? SymTblFileOffset == 0 ) {
????? fprintf(stderr, "lseek to Dynamical symbol Table error./n");
????? close(fd); exit(1);
?? }
?? for (i = 0; i < SymTblNum; i++) {
????? read(fd, SymTblEntry, (size_t)16);
????? symptr = (myElf32_Sym *)SymTblEntry;
????? fprintf(stdout, "Symbol ID: %d/n", i);
????? fprintf(stdout, "Symbol_index_and_name: 0x%08X -> %s/n",
?????????????????????? symptr->st_name, SymNamStrTable + symptr-
>st_name);
????? fprintf(stdout, "Symbol_value: 0x%08X/n", symptr->st_value);
????? fprintf(stdout, "Symbol_size: 0x%08X/n", symptr->st_size);
????? fprintf(stdout, "Symbol_type_and_binding: 0x%02X/n", symptr-
>st_info);
????? fprintf(stdout, "Section_index: 0x%04X/n", symptr->st_shndx);
????? fprintf(stdout,
???????? "--------------------------------------------------------/n");
?? }
?? fprintf(stdout,
"**********************************************************************
**/n");
?? if ( lseek(fd, (off_t)HashOffset, SEEK_SET) != HashOffset ||
??????? HashOffset == 0 ) {
????? fprintf(stderr, "lseek to hash table error./n");
????? close(fd); exit(-1);
?? }
?? for (i = 0; i < HashTblNum; i++) {
????? fprintf(stdout, "Hash Table ID: %d/n", i);
????? read(fd, SymTblEntry, (size_t)4);
????? HashSymPtr = (myElf32_Syminfo *)SymTblEntry;
????? fprintf(stdout, "Direct_bindings, symbol_bound_to: 0x%04X/n",
?????????????????????? HashSymPtr->si_boundto);
????? fprintf(stdout, "Per_symbol_flags: 0x%04X/n", HashSymPtr-
>si_flags);
????? fprintf(stdout,
???????? "--------------------------------------------------------/n");
?? }
?? close(fd);?? /* End of Printing */
? /* Change symbol value, hook it */
?? if ( (fd = open(argv[1], O_RDWR)) < 0 ) {
????? fprintf(stderr, "Can't open object file '%s'./n", argv[1]);
????? exit(-1);
?? }
?? /* 檢索符號表搜索要修改的符號。*/
?? if ( lseek(fd, (off_t)SymTblFileOffset, SEEK_SET) !=
SymTblFileOffset ) {
????? fprintf(stderr, "lseek error./n");
????? close(fd); exit(-1);
?? }
?? for (i = 0; i < SymTblNum; i++) {
????? read(fd, SymTblEntry, (size_t)16);
????? symptr = (myElf32_Sym *)SymTblEntry;
????? if ( strcmp(argv[2], SymNamStrTable + symptr->st_name) == 0 ) {
???????? memcpy(dst_sym, SymTblEntry, 16);
???????? dst_sym_tbl = (unsigned int)lseek(fd, (off_t)0, SEEK_CUR) -
16;
????? }
????? if ( strcmp(argv[3], SymNamStrTable + symptr->st_name) == 0 ) {
???????? memcpy(src_sym, SymTblEntry, 16);
???????? src_sym_tbl = (unsigned int)lseek(fd, (off_t)0, SEEK_CUR) -
16;
????? }
?? }
?? /* 修改符號表中要修改的符號所對應的表項的 st_value 和 st_size 值。*/
?? symptr = (myElf32_Sym *)src_sym;
?? memcpy(tmp_sym_addr, &symptr->st_value, 4);
?? memcpy(tmp_sym_size, &symptr->st_size, 4);
?? symptr = (myElf32_Sym *)dst_sym;
?? memcpy(&symptr->st_value, tmp_sym_addr, 4);
?? memcpy(&symptr->st_size, tmp_sym_size, 4);
?? if ( dst_sym_tbl == 0 || src_sym_tbl == 0 ||
??????? lseek(fd, (off_t)dst_sym_tbl, SEEK_SET) != dst_sym_tbl ) {
????? fprintf(stderr, "lseek error./n");
????? close(fd); exit(-1);
?? }
?? if ( write(fd, dst_sym, (size_t)16) != (ssize_t)16 ) {
????? fprintf(stderr, "write error/n");
????? close(fd); exit(-1);
?? }
?? close(fd);
?? return 0;
}
/* EOF */
總結
以上是生活随笔為你收集整理的如何修改动态库符号表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ethernet调试工具_开发者分享 |
- 下一篇: DirectSound