一步一步走进Linux HOOK API(三)

经过前两篇的教程,我很郁闷,CSDN的博客发布出来之后,跟我的排版完全不一样了,等这一系列的内容全部完成完成之后,我会发布该系列的全部doc文件,如果觉得本系列还不错的话,欢迎大家下载收藏..谢谢支持~~~

下面进入正题,今天主要讲述的是ELF 文件的另一个大块叫节头(Section Headers),那么什么叫节头呢.节头里面分散着不同的段,.bss .text .init .data .got .shstrtab 等等.节头表主要是在连接的角度看待ELF.每一个节都保存着该节特有的数据,由于节中数据的用途不同,节被分为不同的类型,每种类型都又自己组织数据的方式.有的节储存着一些字符串,例如前面提过的.shstrtab 这个节,就专门储存节对应名词的字符串.今天这一节内容,我们就用使用这个节,获取节的名字.

下面按照我们每一次的惯例,先看一下结构体说明,然后再逐一介绍每一个成员,在前面几节中,我们主要是对ELF进行一个全面的了解,为以后进行HOOK做充分的准备.因为那部分得在ELF文件的基础上去实施的,好了.加油吧~~~

详细说明请参阅 elf.h

[cpp]  view plain copy
  1. /* Section header.  */  
  2. typedef struct  
  3. {  
  4.   Elf32_Word    sh_name;     /* Section name (string tbl index) */  
  5.   Elf32_Word    sh_type;     /* Section type */  
  6.   Elf32_Word    sh_flags;    /* Section flags */  
  7.   Elf32_Addr    sh_addr;     /* Section virtual addr at execution */  
  8.   Elf32_Off sh_offset;   /* Section file offset */  
  9.   Elf32_Word    sh_size;     /* Section size in bytes */  
  10.   Elf32_Word    sh_link;     /* Link to another section */  
  11.   Elf32_Word    sh_info;     /* Additional section information */  
  12.   Elf32_Word    sh_addralign;    /* Section alignment */  
  13.   Elf32_Word    sh_entsize;  /* Entry size if section holds table */  
  14. } Elf32_Shdr;  


sh_name: 该成员是字符串表中的一个索引

通过该索引就可以获取这个节所对应的节的名字.通常同节的类型(sh_type)来判断当前是属于什么节.

sh_type: 节的类型

这个成员可以告诉我们这个节里面存放的到底是什么数据,对于不同的数据,我们再通过不同的数据结构去获取数据

sh_flags: 节的属性

这个成员指定该节的内容是否可读可写等属性,具体定义如下:

[cpp]  view plain copy
  1. #define SHF_WRITE        (1 << 0)  
  2. /* Writable */  
  3. #define SHF_ALLOC        (1 << 1)  
  4. /* Occupies memory during execution */  
  5. #define SHF_EXECINSTR    (1 << 2)  
  6. /* Executable */  
  7. #define SHF_MERGE        (1 << 4)  
  8. /* Might be merged */  
  9. #define SHF_STRINGS  (1 << 5)  
  10. /* Contains nul-terminated strings */  
  11. #define SHF_INFO_LINK    (1 << 6)  
  12. /* `sh_info' contains SHT index */  
  13. #define SHF_LINK_ORDER(1 << 7)  
  14. /* Preserve order after combining */  
  15. #define SHF_OS_NONCONFORMING (1 << 8)  
  16. /* Non-standard OS specific handling required */  

sh_addr: 指向进程空间内的虚拟地址

如果这个节需要被加载到进程中,那么该字段就指向内存中的虚拟地址


sh_offset: 指向文件空间内的绝对偏移(相对整个文件的起始地址的)

该地址可以获取到很多关于节内容的信息.


sh_size: 节的内容大小

如果此节在文件中占用一定的字节,那么这个字段给出了该节所占用的字节大小,

如果此节不存在于文件却在内存中,那么这个字段给出了该节在内存中的字节大小


sh_link:  如果这个节于别的节相连,那么这个字段给出了相关的节在节头中的索引


sh_info: 额外的信息

对于部分节来说,还有一些额外的信息.


sh_addralign: 地址对齐

对于双字节等数据格式,很多时候必须对数据进行必要的对齐,来保证数据的准确存储,这个数是2的整数次幂,对齐只能有2字节对齐,4字节对齐,8字节对齐等,如果是0或者1表示这个节不用对齐.


sh_entsize: 指定节内部数据的大小

这个字段代表字节大小的数,对于某些字节才有意义,例如动态符号节来说,这个字段就给出动态符号表中每一个符号结构的字节大小.


上面说到,要获取节的名字要怎么做呢.sh_name字段只是保存了一个值,并不是字符串地址,那要怎么才能获取字符串呢.在前面讲述的第一个ELF Head的时候有这样一个字段e_shstrndx这个成员就是指向字符串表的索引,就可以知道找到节点中的字符串节表了.

同样在遍历节头的时候,如果字段类型等于SHT_STRTAB,那么对应的也就是字符串表.但是为了方便,ELF Head中已经指出了他所对应的索引了.在字符串表中是以一系列的'\0'结尾的字符串,在这个节的第一个字节也是0,为什么第一个字节会是0,其实这就是空字符串.在这个节的最后一个字节也是0. 因为字符串的最后一个都市'\0'.

既然找到了字符串表,那怎么获取他里面的名字呢,其实可以把字符串表当成一个很大的char型数组sh_name就是所需要的字符串的首字符,通过字符串表首地址加上相对的偏移量就是对应的字符串的名字了.

下面我们就来通过代码来加深印象..

示例代码:

[cpp]  view plain copy
  1. #include "readShdr.h"  
  2. SectionType secTyoe[] = {  
  3. {0,"NULL"},{1,"SHT_PROGBITS"},  
  4. {2,"SHT_SYMTAB"},{3,"SHT_STRTAB"},  
  5. {4,"SHT_RELA"},{5,"SHT_HASH"},  
  6. {6,"SHT_DYNAMIC"},{7,"SHT_NOTE"},  
  7. {8,"SHT_NOBITS"},{9,"SHT_REL"},  
  8. {10,"SHT_SHLIB"},{11,"SHT_DYNSYM"},  
  9. {14,"SHT_INIT_ARRAY"},{15,"SHT_FINI_ARRAY"},  
  10. {16,"SHT_PREINIT_ARRAY"},{17,"SHT_GROUP"},  
  11. {18,"SHT_SYMTAB_SHNDX"},{19,"SHT_NUM"},  
  12. {0x60000000,"SHT_LOOS"},{0x6ffffff6,"SHT_GNU_HASH"},  
  13. {0x6ffffff7,"SHT_GNU_LIBLIST"},{0x6ffffff8,"SHT_CHECKSUM"},  
  14. {0x6ffffffa,"SHT_LOSUNW"},{0x6ffffffb,"SHT_SUNW_move"},  
  15. {0x6ffffffc,"SHT_SUNW_COMDAT"},{0x6ffffffd,"SHT_SUNW_syminfo"},  
  16. {0x6ffffffe,"SHT_GNU_verdef"},{0x6fffffff,"SHT_GNU_verneed"},  
  17. {0x70000000,"SHT_LOPROC"},{0x7fffffff,"SHT_HIPROC"},  
  18. {0x80000000,"SHT_LOUSER"},{0x8fffffff,"SHT_HIUSER"},  
  19. };  
  20. char* findSecTypeName(unsigned int type)  
  21. {  
  22. int i = 0;  
  23. for(i = 0;i < sizeof(secTyoe) / sizeof(SectionType);i++){  
  24. if(secTyoe[i].type == type){  
  25. return secTyoe[i].typeName;  
  26. break;  
  27. }  
  28. }  
  29. return secTyoe[0].typeName;  
  30. }  
  31. void displayShdr(Elf32_Ehdr *ehdr,Elf32_Shdr *shdr)  
  32. {  
  33. int py = ehdr->e_shstrndx * sizeof(Elf32_Shdr);  
  34. Elf32_Shdr *symtab = (Elf32_Shdr *)((char*)shdr + py);  
  35. printf("symtab 0x%x\n",symtab);  
  36. char *szShdrName = (char*)(symtab->sh_offset + (char*)ehdr);  
  37. printf("e_shstrndx=%dsizeof(Elf32_Shdr)=%dshdr=x%x\n",ehdr->e_shstrndx,sizeof(Elf32_Shdr),shdr);  
  38. printf("Section Headers: 0x%x\n",szShdrName);  
  39. int i = 0;  
  40. printf("[Nr] %-20s%-20s%-5s%-8s%-6s%-4s%-6s%-4s%-4s%-2s\n",  
  41. "Name","Type","Addr","Off","Size","ES",  
  42. "Flg","Lk","Inf","Al"  
  43. );  
  44. for(i = 0; i < ehdr->e_shnum; i++){  
  45. printf("[%-2d] %-20s",i,szShdrName + shdr->sh_name);  
  46. printf("%-20s",findSecTypeName(shdr->sh_type));  
  47. printf("%-5x",shdr->sh_flags);  
  48. printf("%-08x",shdr->sh_addr);  
  49. printf("%-06x",shdr->sh_offset);  
  50. printf("%-06x",shdr->sh_size);  
  51. printf("%-4x",shdr->sh_link);  
  52. printf("%-4x",shdr->sh_info);  
  53. printf("%-4x",shdr->sh_addralign);  
  54. printf("%-02x\n",shdr->sh_entsize);  
  55. shdr++;  
  56. }  
  57. }  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值