唉,基于 BFD 的工具就像gdb或objdump 不能处理没有节表的 ELF 文件。但是,Linux 和其他使用 ELF 的操作系统实际上并不要求文件具有段表才能执行,只需段表(程序头)就足够了。但是,readelf不使用 BFD,因此即使没有节表也可以显示 ELF 详细信息。例如:
>readelf -SW sample.elf
There are no sections in this file.
但:
>readelf -ed sample.elf
ELF Header:
Magic: 7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, big endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: MIPS R3000
Version: 0x1
Entry point address: 0x405110
Start of program headers: 52 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x50001007, noreorder, pic, cpic, o32, mips32
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
There are no sections in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x00400034 0x00400034 0x000e0 0x000e0 R E 0x4
INTERP 0x000114 0x00400114 0x00400114 0x00014 0x00014 R 0x1
[Requesting program interpreter: /lib/ld-uClibc.so.0]
REGINFO 0x000128 0x00400128 0x00400128 0x00018 0x00018 R 0x4
LOAD 0x000000 0x00400000 0x00400000 0x5d86c 0x5d86c R E 0x1000
LOAD 0x05e000 0x10000000 0x10000000 0x01f64 0x055c4 RW 0x1000
DYNAMIC 0x000140 0x00400140 0x00400140 0x04f36 0x04f36 RWE 0x4
GNU_EH_FRAME 0x05d850 0x0045d850 0x0045d850 0x0001c 0x0001c R 0x4
Dynamic section at offset 0x140 contains 26 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libcrypt.so.0]
0x00000001 (NEEDED) Shared library: [libm.so.0]
0x00000001 (NEEDED) Shared library: [libnbu.so]
0x00000001 (NEEDED) Shared library: [libnbd.so]
0x00000001 (NEEDED) Shared library: [libc.so.0]
0x0000000c (INIT) 0x405088
0x0000000d (FINI) 0x4557b0
0x00000004 (HASH) 0x400238
0x00000005 (STRTAB) 0x403868
0x00000006 (SYMTAB) 0x401398
0x0000000a (STRSZ) 6158 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x70000016 (MIPS_RLD_MAP) 0x10001630
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x10001640
0x00000011 (REL) 0x405078
0x00000012 (RELSZ) 16 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x70000001 (MIPS_RLD_VERSION) 1
0x70000005 (MIPS_FLAGS) NOTPOT
0x70000006 (MIPS_BASE_ADDRESS) 0x400000
0x7000000a (MIPS_LOCAL_GOTNO) 13
0x70000011 (MIPS_SYMTABNO) 589
0x70000012 (MIPS_UNREFEXTNO) 35
0x70000013 (MIPS_GOTSYM) 0x11
0x00000000 (NULL) 0x0
如您所见,它确实有一个适当的动态表,其中包含DT_SYMTAB解析符号所需的条目。但是,readelf缺少反汇编器,所以我们终将不得不使用objdump,只是不依赖节表。首先,让我们将第一个LOAD段(它有“(R)ead (E)execute”标志很可能包含代码)提取到一个单独的文件中:
dd if=sample.elf bs=1 skip=0 count=383084 of=text.bin
(不幸的是dd只接受十进制值)。
PS其实由于segment是从0开始的,你可以跳过这一步直接反汇编输入文件。然而,这并非总是如此。所以可能对其他文件有用。
现在我们可以用objdump原始二进制文件反汇编它:
mips-linux-gnu-objdump -b binary -D -m mips:isa32r2 --adjust-vma=0x00400000 --start-address=0x405110 -EB text.bin
选项分解:
b binary: 将输入视为原始二进制
-D:将所有内容反汇编为代码(对于原始二进制文件是必需的,因为它们没有节或其他元数据)
-m mips:isa32r2 : 将代码视为 MIPS32r2 指令
--adjust-vma=0x00400000:假设二进制文件加载在0x00400000(程序头转储中的VirtAddr列readelf)。
--start-address=0x405110:在 0x405110(头转储中的“入口点地址”)处开始反汇编
-EB: 指令是大端的(如 所暗示的readelf)。
结果如下:
Disassembly of section .data:
00405110 <.data+0x5110>:
405110: 04100001 bltzal zero,0x405118
405114: 00000000 nop
405118: 3c1c0fc0 lui gp,0xfc0
40511c: 279c4518 addiu gp,gp,17688
405120: 039fe021 addu gp,gp,ra
405124: 0000f821 move ra,zero
405128: 8fa40000 lw a0,0(sp)
40512c: 27a50004 addiu a1,sp,4
405130: 24860001 addiu a2,a0,1
405134: 00063080 sll a2,a2,0x2
405138: 00c53020 add a2,a2,a1
40513c: 8f87861c lw a3,-31204(gp)
405140: 27bdffe8 addiu sp,sp,-24
405144: 8f82829c lw v0,-32100(gp)
405148: 00000000 nop
40514c: afa20010 sw v0,16(sp)
405150: 8f998114 lw t9,-32492(gp)
405154: 00000000 nop
405158: 0320f809 jalr t9
40515c: 00000000 nop
405160: 27bd0018 addiu sp,sp,24
405164: 1000ffff b 0x405164
405168: 00000000 nop
不用注意.data,这只是默认名称,objdump 没有其他信息。
理解反汇编留给读者作为练习:)
编辑
我忘了readelf选项。事实上,联机帮助页提到:
-D
--use-dynamic
显示符号时,此选项使 readelf 使用文件动态部分中的符号表,而不是符号部分中的符号表。
确实,readelf -Ds sample.elf显示了不错的输出:
Symbol table for image:
Num Buc: Value Size Type Bind Vis Ndx Name
58 0: 00455690 0 FUNC GLOBAL DEFAULT UND execvp
384 1: 00454c90 0 FUNC GLOBAL DEFAULT UND getpgrp
68 3: 00455640 0 FUNC GLOBAL DEFAULT UND open
123 3: 004554a0 0 FUNC GLOBAL DEFAULT UND socketpair
513 3: 0044a298 0 FUNC GLOBAL DEFAULT bad xdr_dirpath
120 4: 004554b0 0 FUNC GLOBAL DEFAULT UND strftime
373 4: 00454ce0 0 FUNC GLOBAL DEFAULT UND strrchr
572 4: 00454730 0 FUNC GLOBAL DEFAULT UND waitpid