linux中ELF格式二进制程序( 四 )


0x2C~0x2D是e_phnum,2个字节,e_phnum = 0x00 02,表示程序头表中段的个数,此处为2个段;
0x2E~0x2F是e_shentsize,2个字节,e_shentsize = 0x00 28,表示节头表中节的大小,此处为0x28;
0x30~0x31是e_shnum,2个字节,e_shnum = 0x00 06,表示节头表中节的个数,此处为6个节;
0x32~0x33是e_shstrndx,2个字节,e_shstrndx = 0x00 03,表示string name table在节头表中的索引为3;
 
5.2 程序头表 
$ xxd -u -a -g 1 -s 0 -l 0x100 kernel.bin ......0000030: 00 06 00 03 00 00 00 01 00 00 00 00 C0 00 00 00................0000040: C0 00 00 00 00 00 15 10 00 00 15 10 00 00 00 05................0000050: 00 01 00 00 64 74 E5 51 00 00 00 00 00 00 00 00....dt.Q........0000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06................0000070: 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00................在ELF header中,程序头表偏移e_phoff = 0x00 00 00 34,所以程序头表的偏移位置为0x34,程序头表中段的大小e_phentsize = 0x00 20,段的个数e_phnum = 0x00 02,表示程序头表中有两个段,每个段大小0x20字节;ELF header大小e_ehsize = 0x00 34,程序头表紧跟ELF header之后;0x34~0x73之间共0x40个字节,是两个程序头的内容,从0x34地址开始,按照Elf32_Phdr结构分析;
 
第一个段头在0x34~0x53,共0x20个字节;
0x34~0x37是p_type,4个字节,p_type = 0x00 00 00 01,表示类型为PT_LOAD,为可加载程序段;
0x38~0x3B是p_offset,4个字节,p_offset = 0x00 00 00 00,表示本段在文件内的偏移量;
0x3C~0x3F是p_vaddr,4个字节,p_vaddr = 0xC0 00 00 00,表示本段被加载到内存后的起始虚拟地址;
0x40~0x43是p_paddr,4个字节,p_paddr = 0xC0 00 00 00,保留,和p_vaddr一致;
0x44~0x47是p_filesz,4个字节,p_filesz = 0x00 00 15 10,表示本段在文件中的大小;
0x48~0x4B是p_memsz,4个字节,p_memsz = 0x00 00 15 10,表示本段在内存中的大小;
0x4C~0x4F是p_flags,4个字节,p_flags = 0x00 00 00 05,表示本段的属性,5 = 4 + 1 = PF_R + PF_X,此处为可读和可执行权限;
0x50~0x53是p_align,4个字节,p_align = 0x00 01 00 00,表示本段的对齐方式,此处为64K对齐;
 
第二个段头在0x54~0x73,共0x20个字节;
0x54~0x57是p_type,4个字节,p_type = 0x64 74 E5 51,表示类型为PT_GNU_STACK,为GNU的栈段;
// include/uapi/linux/elf.h#define PT_LOOS0x60000000#define PT_GNU_STACK(PT_LOOS + 0x474e551) 
之后的分析省略;
 
5.3 节头表 
在ELF header中,节头表偏移e_shoff = 0x00 00 15 74,所以节头表的偏移位置为0x1574,节头表中段的大小e_shentsize = 0x00 28,段的个数e_shnum = 0x00 06,表示节头表中有六个节,每个节0x28字节;0x1574~0x1663共0xF0个字节,是六个节头的内容,从0x1574地址开始,按照Elf32_Shdr结构分析;
$ xxd -u -g 1 -s 0x1570 -l 0x100 kernel.bin0001570: 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00t...............0001580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................0001590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1B................00015a0: 00 00 00 01 00 00 00 06 C0 00 15 00 00 00 15 00................00015b0: 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 04................00015c0: 00 00 00 00 00 00 00 21 00 00 00 01 00 00 00 00.......!........00015d0: 00 00 00 00 00 00 15 10 00 00 00 38 00 00 00 00...........8....00015e0: 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 11................00015f0: 00 00 00 03 00 00 00 00 00 00 00 00 00 00 15 48...............H0001600: 00 00 00 2A 00 00 00 00 00 00 00 00 00 00 00 01...*............0001610: 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 00................0001620: 00 00 00 00 00 00 16 64 00 00 00 80 00 00 00 05.......d........0001630: 00 00 00 04 00 00 00 04 00 00 00 10 00 00 00 09................0001640: 00 00 00 03 00 00 00 00 00 00 00 00 00 00 16 E4................0001650: 00 00 00 25 00 00 00 00 00 00 00 00 00 00 00 01...%............0001660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00................ 
第一个节头在0x1574~0x159B,共0x28个字节;
0x1574~0x1577是sh_name,4个字节,sh_name = 0x00 00 00 00,表示节名称是在字符串表索引值为0x00的字符串,该字符串为空;
0x1578~0x157B是sh_type,4个字节,sh_type = 0x00 00 00 00,表示该节是一个无效的节头,没有对应的节;该节中其他成员也无意义;
 
第二个节头在0x159C~0x15C3,共0x28个字节;
0x159C~0x159F是sh_name,4个字节,sh_name = 0x00 00 00 1B,表示节名称是在字符串表索引值为0x1B的字符串;该字符串为".text";
0x15A0~0x15A3是sh_type,4个字节,sh_type = 0x00 00 00 01,表示
0x15A4~0x15A7是sh_flags,4个字节,sh_flags = 0x00 00 00 06,0x06 = 0x04 + 0x02 = SHF_EXECINSTR + SHF_ALLOC,表示该节内容是指令代码,并且包含内存在进程运行时需要占用内存单元;


推荐阅读