https://github.com/elfmaster/libelfmaster
这里是个不错的解析elf的c代码。
寻找导出函数对应偏移
我感觉文字没有代码明白,看下别人怎么写的,立马明白了。
mem指向elf文件加载的地址连续空间。
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
typedef struct
{
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
typedef struct {
Elf32_Word st_name; //符号表项名称。如果该值非0,则表示符号名的字
//符串表索引(offset),否则符号表项没有名称。
Elf32_Addr st_value; //符号的取值。依赖于具体的上下文,可能是一个绝对值、一个地址等等。
Elf32_Word st_size; //符号的尺寸大小。例如一个数据对象的大小是对象中包含的字节数。
unsigned char st_info; //符号的类型和绑定属性。
unsigned char st_other; //未定义。
Elf32_Half st_shndx; //每个符号表项都以和其他节区的关系的方式给出定义。
//此成员给出相关的节区头部表索引。
} Elf32_sym;
obj->ehdr64 = (Elf64_Ehdr *)mem;
obj->shdr64 = (Elf64_Shdr *)&mem[obj->ehdr64->e_shoff];
obj->section_count = section_count = obj->ehdr64->e_shnum;
obj->shstrtab =
(char *)&mem[obj->shdr64[obj->ehdr64->e_shstrndx].sh_offset];
for (i = 0; i < section_count; i++) {
const char *sname = (obj->e_class == elfclass32) ?
&obj->shstrtab[obj->shdr32[i].sh_name] :
&obj->shstrtab[obj->shdr64[i].sh_name];
if (strcmp(sname, ".strtab") == 0) {
obj->strtab = (char *)&mem[sh_offset];
}
else if (strcmp(sname, ".symtab") == 0) {
uint64_t sh_offset = (obj->e_class == elfclass32) ?
obj->shdr32[i].sh_offset : obj->shdr64[i].sh_offset;
obj->symtab_count = obj->shdr64[i].sh_size /sizeof(Elf64_Sym);
obj->symtab64 =(Elf64_Sym *)&mem[sh_offset];
}
}
for (i = 0; i < obj->symtab_count; i++)
symbol->name = &obj->strtab[symtab64[i].st_name];
symtab64 = obj->symtab64; //函数符号
symbol->value = symtab64[i].st_value; //函数偏移
symbol->size = symtab64[i].st_size; //函数大小
}
rel.plt和rel.dyn
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 5] .dynsym DYNSYM 00000000004002b8 000002b8
0000000000000078 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 0000000000400330 00000330
0000000000000044 0000000000000000 A 0 0 1
[ 9] .rela.dyn RELA 00000000004003a0 000003a0
0000000000000018 0000000000000018 A 5 0 8
[10] .rela.plt RELA 00000000004003b8 000003b8
0000000000000060 0000000000000018 AI 5 23 8
LOAD:00000000004003A0 ; ELF RELA Relocation Table
LOAD:00000000004003A0 Elf64_Rela <600FF8h, 400000006h, 0> ; R_X86_64_GLOB_DAT __gmon_start__
LOAD:00000000004003B8 ; ELF JMPREL Relocation Table
LOAD:00000000004003B8 Elf64_Rela <601018h, 100000007h, 0> ; R_X86_64_JUMP_SLOT puts
LOAD:00000000004003D0 Elf64_Rela <601020h, 200000007h, 0> ; R_X86_64_JUMP_SLOT printf
LOAD:00000000004003E8 Elf64_Rela <601028h, 300000007h, 0> ; R_X86_64_JUMP_SLOT __libc_start_main
LOAD:0000000000400400 Elf64_Rela <601030h, 400000007h, 0> ; R_X86_64_JUMP_SLOT __gmon_start__
LOAD:0000000000400400 LOAD ends
00000000004003A0 F8 0F 60 00 00 00 00 00 06 00 00 00 04 00 00 00 ..`.............
00000000004003B0 00 00 00 00 00 00 00 00 18 10 60 00 00 00 00 00 ..........`.....
00000000004003C0 07 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
00000000004003D0 20 10 60 00 00 00 00 00 07 00 00 00 02 00 00 00 .`.............
00000000004003E0 00 00 00 00 00 00 00 00 28 10 60 00 00 00 00 00 ........(.`.....
00000000004003F0 07 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 ................
0000000000400400 30 10 60 00 00 00 00 00 07 00 00 00 04 00 00 00 0.`.............
[12] .plt PROGBITS 0000000000400440 00000440
0000000000000050 0000000000000010 AX 0 0 16
[21] .dynamic DYNAMIC 0000000000600e28 00000e28
00000000000001d0 0000000000000010 WA 6 0 8
[22] .got PROGBITS 0000000000600ff8 00000ff8
0000000000000008 0000000000000008 WA 0 0 8
[23] .got.plt PROGBITS 0000000000601000 00001000
0000000000000038 0000000000000008 WA 0 0 8
[27] .symtab SYMTAB 0000000000000000 00001098
0000000000000618 0000000000000018 28 46 8
[28] .strtab STRTAB 0000000000000000 000016b0
00000000000001e2 0000000000000000 0 0 1
[29] .shstrtab STRTAB 0000000000000000 00001892
0000000000000108 0000000000000000 0 0 1
这个重定位表用来标识got.plt重定位信息如上,指出了got.plt中的位置和定位类型。符号不是这里指定的。
plt表在代码中的体现。
.plt:00000000004004F0 sub_4004F0 proc near ; CODE XREF: .plt:000000000040050B↓j
.plt:00000000004004F0 ; .plt:000000000040051B↓j ...
.plt:00000000004004F0 ; __unwind {
.plt:00000000004004F0 push cs:qword_601008
.plt:00000000004004F6 jmp cs:qword_601010
.plt:00000000004004F6 sub_4004F0 endp
.plt:00000000004004F6
.plt:00000000004004F6 ; ---------------------------------------------------------------------------
.plt:00000000004004FC align 20h
.plt:0000000000400500 ; [00000006 BYTES: COLLAPSED FUNCTION _write. PRESS CTRL-NUMPAD+ TO EXPAND]
.plt:0000000000400506 ; ---------------------------------------------------------------------------
.plt:0000000000400506 push 0
.plt:000000000040050B jmp sub_4004F0
.plt:0000000000400510 ; [00000006 BYTES: COLLAPSED FUNCTION ___stack_chk_fail. PRESS CTRL-NUMPAD+ TO EXPAND]
.plt:0000000000400516 ; ---------------------------------------------------------------------------
.plt:0000000000400516 push 1
.plt:000000000040051B jmp sub_4004F0
.plt:0000000000400520 ; [00000006 BYTES: COLLAPSED FUNCTION _read. PRESS CTRL-NUMPAD+ TO EXPAND]
.plt:0000000000400526 ; ---------------------------------------------------------------------------
.plt:0000000000400526 push 2
.plt:000000000040052B jmp sub_4004F0
.plt:0000000000400530 ; [00000006 BYTES: COLLAPSED FUNCTION ___libc_start_main. PRESS CTRL-NUMPAD+ TO EXPAND]
.plt:0000000000400536 ; ---------------------------------------------------------------------------
.plt:0000000000400536 push 3
.plt:000000000040053B jmp sub_4004F0
.plt:0000000000400540 ; [00000006 BYTES: COLLAPSED FUNCTION _perror. PRESS CTRL-NUMPAD+ TO EXPAND]
.plt:0000000000400546 ; ---------------------------------------------------------------------------
.plt:0000000000400546 push 4
.plt:000000000040054B jmp sub_4004F0
.plt:0000000000400550 ; [00000006 BYTES: COLLAPSED FUNCTION _exit. PRESS CTRL-NUMPAD+ TO EXPAND]
.plt:0000000000400556 ; ---------------------------------------------------------------------------
.plt:0000000000400556 push 5
.plt:000000000040055B jmp sub_4004F0
.plt:000000000040055B ; } // starts at 4004F0
.plt:000000000040055B _plt ends
.plt:000000000040055B
每个plt中的函数在第一次调用的时候都会跳到00000000004004F0 ,这个地址将会跳转到got[0]进行dlresolve。函数地址查询,之后所有的函数地址将会填写到相应的got表中,二次调用将会直接jmp到相应的位置。
got表位置
.got.plt:0000000000601000 ; ===========================================================================
.got.plt:0000000000601000
.got.plt:0000000000601000 ; Segment type: Pure data
.got.plt:0000000000601000 ; Segment permissions: Read/Write
.got.plt:0000000000601000 _got_plt segment qword public 'DATA' use64
.got.plt:0000000000601000 assume cs:_got_plt
.got.plt:0000000000601000 ;org 601000h
.got.plt:0000000000601000 _GLOBAL_OFFSET_TABLE_ dq offset _DYNAMIC
.got.plt:0000000000601008 qword_601008 dq 0 ; DATA XREF: sub_4004F0↑r
.got.plt:0000000000601010 qword_601010 dq 0 ; DATA XREF: sub_4004F0+6↑r
.got.plt:0000000000601018 off_601018 dq offset write ; DATA XREF: _write↑r
.got.plt:0000000000601020 off_601020 dq offset __stack_chk_fail
.got.plt:0000000000601020 ; DATA XREF: ___stack_chk_fail↑r
.got.plt:0000000000601028 off_601028 dq offset read ; DATA XREF: _read↑r
.got.plt:0000000000601030 off_601030 dq offset __libc_start_main
.got.plt:0000000000601030 ; DATA XREF: ___libc_start_main↑r
.got.plt:0000000000601038 off_601038 dq offset perror ; DATA XREF: _perror↑r
.got.plt:0000000000601040 off_601040 dq offset exit ; DATA XREF: _exit↑r
.got.plt:0000000000601040 _got_plt ends
.got.plt:0000000000601040
函数重定位信息: Elf64_Rela <601028h, 300000007h, 0> ; 可以定位到got表的read函数。
LOAD:00000000004003F8 ; ELF GNU Symbol Version Requirements
LOAD:00000000004003F8 Elf64_Verneed <1, 2, offset aLibcSo6 - offset byte_400378, 10h, 0> ; "libc.so.6"
LOAD:0000000000400408 Elf64_Vernaux <0D696914h, 0, 3, offset aGlibc24 - offset byte_400378, \ ; "GLIBC_2.4"
LOAD:0000000000400408 10h>
LOAD:0000000000400418 Elf64_Vernaux <9691A75h, 0, 2, offset aGlibc225 - offset byte_400378, \ ; "GLIBC_2.2.5"
LOAD:0000000000400418 0>
LOAD:0000000000400428 ; ELF RELA Relocation Table
LOAD:0000000000400428 Elf64_Rela <600FF8h, 500000006h, 0> ; R_X86_64_GLOB_DAT __gmon_start__
LOAD:0000000000400440 ; ELF JMPREL Relocation Table
LOAD:0000000000400440 Elf64_Rela <601018h, 100000007h, 0> ; R_X86_64_JUMP_SLOT write
LOAD:0000000000400458 Elf64_Rela <601020h, 200000007h, 0> ; R_X86_64_JUMP_SLOT __stack_chk_fail
LOAD:0000000000400470 Elf64_Rela <601028h, 300000007h, 0> ; R_X86_64_JUMP_SLOT read
LOAD:0000000000400488 Elf64_Rela <601030h, 400000007h, 0> ; R_X86_64_JUMP_SLOT __libc_start_main
LOAD:00000000004004A0 Elf64_Rela <601038h, 600000007h, 0> ; R_X86_64_JUMP_SLOT perror
LOAD:00000000004004B8 Elf64_Rela <601040h, 700000007h, 0> ; R_X86_64_JUMP_SLOT exit
LOAD:00000000004004B8 LOAD ends