objdump -T 在 MIPS .so 上给出无效操作

逆向工程 文件格式 小精灵
2021-07-08 16:15:55

我有一个 MIPS .so 文件,我正在尝试反转它。Binary Ninja(对于 IDA 来说太便宜了)没有找到任何符号,也没有找到objdump -T,而是给出“无效操作”:

% mips-linux-gnu-objdump -x libinet.so

libinet.so:     file format elf32-tradbigmips
libinet.so
architecture: mips:isa32r2, flags 0x00000140:
DYNAMIC, D_PAGED
start address 0x000040f0

Program Header:
0x70000000 off    0x000000f4 vaddr 0x000000f4 paddr 0x000000f4 align 2**2
         filesz 0x00000018 memsz 0x00000018 flags r--
    LOAD off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**16
         filesz 0x00013454 memsz 0x00013454 flags r-x
    LOAD off    0x00014000 vaddr 0x00024000 paddr 0x00024000 align 2**16
         filesz 0x000006c0 memsz 0x00000d6c flags rw-
 DYNAMIC off    0x0000010c vaddr 0x0000010c paddr 0x0000010c align 2**2
         filesz 0x00000108 memsz 0x00000108 flags rwx
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
         filesz 0x00000000 memsz 0x00000000 flags rw-
    NULL off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
         filesz 0x00000000 memsz 0x00000000 flags ---
private flags = 74001007: [abi=O32] [mips32r2] [mips16] [not 32bitmode] [noreorder] [PIC] [CPIC]

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
SYMBOL TABLE:
no symbols


% mips-linux-gnu-objdump -T libinet.so
mips-linux-gnu-objdump: libinet.so: Invalid operation
libinet.so:     file format elf32-tradbigmips

有谁知道为什么会发生这种情况?是否有更好的工具来探索 ELF 元数据以查看此共享对象是否有异常之处?

编辑更多结果:

% file libinet.so 
libinet.so: ELF 32-bit MSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, corrupted section header size
% readelf -SW ./libinet.so 

There are no sections in this file.
1个回答

唉,基于 BFD 的工具就像gdbobjdump 不能处理没有节表的 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程序头转储中的VirtAddrreadelf)。
  • --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