如何修改动态库符号表

如何修改动态库符号表


    一、ELF 文件和有关术语

Unix 系统的可执行文件和动态库文件是以 ELF 格式存放的。为使下面的叙述
清晰而没有伎义,先简要介绍一下 ELF 文件格式,并约定一些术语。关于ELF
文件格式的详细情况请参看有关文献。

ELF 文件中代码、连接信息和注释是以节(section)为单位存放的,并存有一
个节头表(section header)。对每一节,在节头表中都有一个表项(节头表项)
与之对应,表项记录了该节的一些信息,例如该节在文件中的位置信息和该节
的字节长度信息。

程序运行读入内存时,是以程序段(program segment)为单位读入的。在 ELF
文件中有一个程序头表(program header table),每个程序段在程序头表中有
一个表项(程序头表项)与之对应,表项记录了该程序段的有关信息,例如该程
序段在文件中的位置信息和该程序段的字节长度信息。程序段的内容由若干节
组成,节的内容组合在一起连成一片构成程序段的内容。

在所有这些节中,有一节的内容由字符串构成,这些字符串是各节的名称,叫
节名。下面称这一节为节名表。另有一节,节名为".dynsym",它的内容为符
号表,符号表的每一表项记录了一个符号的有关信息,例如该符号对应的代码
的地址值。还有一节,节名为".dynstr",它的内容由字符串构成。大多数符
号在该节中有一个字符串与之对应,这个字符串是该符号的符号名。而每一函
数对应一个符号,函数名即为符号名。下面称被某一函数对应的符号为函数符
号。

ELF 文件开始处的一段叫 ELF 文件头。它记录了程序头表在文件中的偏移、
程序头表的表项数目、程序头表每一表项的字节长度、节头表在文件中的偏移、
节头表的表项数目、节头表每个表项的字节长度。它还记录了节名表所在的节
的索引序号。

二、动态库符号表修改方法

修改动态库符号表的方法和步骤如下:

第一步:

读取 ELF 文件头,取出

    (1) 程序头表在文件中的偏移,获取程序头表在文件中的位置;
    (2) 程序头表的表项数目和程序头表每一表项的字节长度;
    (3) 节头表在文件中的偏移,获取节头表在文件中的位置;
    (4) 节头表的表项数目和节头表每个表项的字节长度;
    (3) 节名表所在的节的索引序号。

ELF 文件头在文件中的偏移为零,即起始于 ELF 文件开头的第一字节,它的
数据结构为:

#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;             /* 节头表在文件中的偏移 */
   Elf32_Word    e_flags;             /* 处理器标志 */
   Elf32_Half    e_ehsize;            /* ELF 文件头长度 */
   Elf32_Half    e_phentsize;         /* 程序头表每个表项长度 */
   Elf32_Half    e_phnum;             /* 程序头表的表项总数 */
   Elf32_Half    e_shentsize;         /* 节头表每个表项长度 */
   Elf32_Half    e_shnum;             /* 节头表的表项总数 */
   Elf32_Half    e_shstrndx;          /* 节名表所在的节的表项索引号 */
} Elf32_Ehdr;

第二步:

依据节头表在文件中的偏移和节名表所在的节的索引序号,定出节名表在节头
表中对应的表项的文件偏移,即定出该表项在文件中的位置。读取该表项,取
出节名表在文件中的偏移和该节在文件中的字节长度。节头表由若干表项组成,
每个表项的内容按下面的数据结构来组织:

typedef struct
{
   Elf32_Word    sh_name;             /* 节名索引号 */
   Elf32_Word    sh_type;             /* 节类型 */
   Elf32_Word    sh_flags;            /* 节标志 */
   Elf32_Addr    sh_addr;             /* 执行时该节虚地址 */
   Elf32_Off     sh_offset;           /* 在文件中的偏移 */
   Elf32_Word    sh_size;             /* 节长度 */
   Elf32_Word    sh_link;             /* 到其他节的连接 */
   Elf32_Word    sh_info;             /* 其他信息 */
   Elf32_Word    sh_addralign;        /* alignment */
   Elf32_Word    sh_entsize;          /* 如内容为表,每个表项的长度 */
} Elf32_Shdr;

第三步:

按节名表在文件中的偏移和该节的长度读取节名表,并缓存在一个缓冲区中。

第四步:

依据节头表在文件中的偏移、节头表的表项总数、以及节头表每个表项长度搜
索节头表。对每个节头表项,读出节名索引号,由节名索引号从上面缓存在缓
冲区中节名表得出该节头表项对应的节的名字。如果名字为".dynsym",记录
该节的在文件中的偏移和字节长度。名字为 ".dynsym" 的节的内容是符号表,
除了记录它在文件中的偏移和字节长度外,还要记下它的每个表项的长度。每
个表项即是对一个符号所记录的信息,表项的数据结构为:

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;      /* 所在节的节索引号 */
} Elf32_Sym;

在搜索节头表时,除了找 ".dynsym" 节外,还要找到名字为 ".dynstr" 的节,
记下它的在文件中的偏移和字节长度。由该结在文件中的偏移和字节长度读取
它的内容,并缓存在一个缓冲区中。

第五步:

按第四步中得到的 ..dynsym节的字节长度和符号表的表项的长度算出符号表表
项数目,也即符号的数目。然后依据第四步中得到的符号表(即.dynsym节)在
文件中的偏移把文件指针打到符号表所在的位置,检索符号表找到要修改的符
号。方法是从符号表表项中读出符号名索引号(st_name)的值,这个值即是该
表项记录其信息的符号的符号名字符串在 .dynstr 节中的偏移,由这个值在
第四步中缓存 .dynstr 节的缓冲区中取出符号名,把符号名和要找的符号的
符号名进行比较。

第六步:

第五步中找到了要修改的符号,现在可以进行修改了。所谓修改符号就是修改
该符号在符号表(.dynsym 节)中表项,因为表项的内容是对该符号的有关信
息的记录。hook 时需要关注的是符号地址值(st_value)和符号对应的代码长
度(st_size)。可以把符号地址值(st_value)和符号对应的代码长度(st_size)
修改为动态库中另一符号的相应的 st_value 和 st_size 值。通常修改的是
函数符号。如果是函数符号,那么修改后当调用该函数时,实际调用的是上面
修改时取其 st_value 和 st_size 值的另一符号所对应的函数。也可以向ELF
文件中加入的一段几十字节的 shellcode 或其他代码,修改符号表时把所修
改的符号在符号表中的表项的 st_value 值指向这段 shellcode 或其他代码,
st_size 的值置为这段代码的字节长度。那么,程序调用被修改的符号所对应
的函数时,实际调用的是这段 shellcode 或其他代码。

三、示例程序

为对上面所说的进行解释,下面的给出一个示例程序。它打印出 ELF 文件的
有关信息,然后通过修改符号表把动态库的函数1 hook 到函数2。这样做以后,
如果某程序编译时与该动态库连接了,它调用函数1时,程序运行时实际调用
的是函数2。函数2可以是动态库本身就有的函数,也可以是你向 ELF 文件中
偷偷加入的一段几十字节的 shellcode。这是向系统置入后门的一个方法,特
别是 hook 经常被调用的动态库。

测试时做了一个小动态库,它仅有两个函数 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 调用 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;

/* 下面的数据结构定义取自 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);

   /* 记下程序头表在文件中的偏移、节头表在文件中的偏移、
      节名表所在的节的索引序号、程序头表表项字节长度、程序头表表项数目


      节头表表项字节长度、节头表表项数目。*/
   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");

   /* 定出节名表所在的节在节头表中对应的表项的文件偏移。*/
   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;

   /* 读取节名表,并缓存在一个缓冲区中。*/
   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节)在文件中的偏移,由它的字节长度和每个表项


      长度算出符号表的表项数目。同时记下.dynstr节在文件中的偏移和字节长

度。*/
   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 节的内容,并缓存在一个缓冲区中。*/
   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 */

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值