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

来源:互联网 发布:mmd麻烦鬼动作数据 编辑:程序博客网 时间:2024/06/05 04:01

从上一篇的ELF Head之后,想必很多读者已经对ELF文件开始感觉不是遥不可及了,今天这一节,主要是讲程序头(Program Headers),程序头主要是从加载执行的角度来看的,很多人想那里面到底是什么东西呢,其实程序头就是一个结构数组,每一个头保存着对应的不同的数据,有的数据是告诉系统把我放入内存,有的数据时告诉系统我是变量.等等...在系统加载程序的时候就要通过该程序头来加载不同的段.

下面就来看一下程序头的结构体:

[cpp] view plaincopy
  1. typedef struct  
  2.   
  3. {  
  4.   
  5.    Elf32_Word p_type; /* Segment type */  
  6.   
  7.    Elf32_Off p_offset; /* Segment file offset */  
  8.   
  9.    Elf32_Addr p_vaddr; /* Segment virtual address */  
  10.   
  11.    Elf32_Addr p_paddr; /* Segment physical address */  
  12.   
  13.    Elf32_Word p_filesz; /* Segment size in file */  
  14.   
  15.    Elf32_Word p_memsz; /* Segment size in memory */  
  16.   
  17.    Elf32_Word p_flags; /* Segment flags */  
  18.   
  19.    Elf32_Word p_align; /* Segment alignment */  
  20.   
  21. } Elf32_Phdr;  

p_type:            段的类型

在elf.h头文件中,有很详细的说明段的类型,比如PT_LOAD 表示加载的程序段

p_offset:        文件偏移

该段在文件中的偏移。这个偏移是相对于整个文件的。

p_vaddr:         加载后的虚拟地址

该段加载后在进程空间中占用的内存起始地址。

p_paddr:        该段的物理地址

这个字段被忽略,因为在多数现代操作系统下物理地址是进程无法触及的。

p_filesz:         该段在文件中占用的字节大小

有些段可能在文件中不存在但却占用一定的内存空间,此时这个字段为0

p_memsz:     该段在内存中占用的字节大小

有些段可能仅存在于文件中而不被加载到内存,此时这个字段为0

p_flags:         段的属性

表示该段的读写执行等属性.elf.h文件中的定义是

[html] view plaincopy
  1. #define PF_X (1 << 0) /* Segment is executable */  
  2.   
  3. #define PF_W (1 << 1) /* Segment is writable */  
  4.   
  5. #define PF_R (1 << 2) /* Segment is readable */  
  6.   
  7. #define PF_MASKOS 0x0ff00000 /* OS-specific */  
  8.   
  9. #define PF_MASKPROC 0xf0000000 /* Processor-specific */  

p_align:          对齐

现代操作系统都使用虚拟内存为进程序提供更大的空间,分页技术功不可没,页就成了最小的内存分配单位,不足一页的按一页算。所以加载程序数据一般也从一页的起始地址开始,这就属于对齐。

示例代码:

[cpp] view plaincopy
  1. typedef struct _SegmentType_  
  2.   
  3. {  
  4.   
  5. unsigned int type;  
  6.   
  7. char *typeName;  
  8.   
  9. }SegmentType;  
  10.   
  11. SegmentType segTyoe[] = {  
  12.   
  13. {0,"NULL"},{1,"LOAD"},  
  14.   
  15. {2,"DYNAMIC"},{3,"INTERP"},  
  16.   
  17. {4,"NOTE"},{5,"SHLIB"},  
  18.   
  19. {6,"PHDR"},{7,"TLS"},  
  20.   
  21. {8,"NUM"},{0x60000000,"LOOS"}, {0x6474e550,"GNU_EH_FRAME"},{0x6474e551,"PT_GNU_STACK"}, {0x6474e552,"PT_GNU_RELRO"},{0x6ffffffa,"PT_SUNWBSS"}, {0x6ffffffb,"PT_SUNWSTACK"},{0x6fffffff,"PT_HISUNW"},  
  22.   
  23. {0x70000000,"PT_HIOS"},{0x7fffffff,"PT_HIPROC"},  
  24.   
  25. };  
  26.   
  27. char* findSegTypeName(unsigned int type)  
  28.   
  29. {  
  30.   
  31. int i = 0;  
  32.   
  33. for(i = 0;i < sizeof(segTyoe) / sizeof(SegmentType);i++){  
  34.   
  35. if(segTyoe[i].type == type){  
  36.   
  37. return segTyoe[i].typeName;  
  38.   
  39. break;  
  40.   
  41. }  
  42.   
  43. }  
  44.   
  45. return segTyoe[0].typeName;  
  46.   
  47. }  
  48.   
  49. void displayPhdr(Elf32_Ehdr *ehdr,Elf32_Phdr *phdr)  
  50.   
  51. {  
  52.   
  53. printf("Program Headers:\n");  
  54.   
  55. printf("%-20s%-10s%-10s%-10s%-10s%-10s%-10s%-10s\n",  
  56.   
  57. "Type","Offset","VirtAddr","PhysAddr","FileSiz",  
  58.   
  59. "MemSiz","Flg","Align");  
  60.   
  61. int i = 0;  
  62.   
  63. for(i = 0; i < ehdr->e_phnum;i++){  
  64.   
  65. printf("%-20s%-10x%-10x%-10x%-10x%-10x%-10x%-10x\n",  
  66.   
  67. findSegTypeName(phdr->p_type),  
  68.   
  69. phdr->p_offset,  
  70.   
  71. phdr->p_vaddr,  
  72.   
  73. phdr->p_paddr,  
  74.   
  75. phdr->p_filesz,  
  76.   
  77. phdr->p_memsz,  
  78.   
  79. phdr->p_flags,  
  80.   
  81. phdr->p_align  
  82.   
  83. );  
  84.   
  85. if(phdr->p_type == PT_INTERP){  
  86.   
  87. printf("\t[Requesting program interpreter: %s]\n",  
  88.   
  89. (char*)((char*)ehdr + phdr->p_offset));  
  90.   
  91. }  
  92.   
  93. phdr++;  
  94.   
  95. }  
  96.   
  97. }  


 

原创粉丝点击