我尝试为ARM构建一个小型反汇编程序,我想知道objdump如何设法从拇指模式指令(16位指令宽)中整理出普通模式指令(32位指令宽)。在CPSR的t标志处。

但是首先,让我们构建一个小示例并对其进行一些实验。

我写了这小块ARM程序集(gas语法)作为基础示例:

.arm
    mov fp, #0
    moveq   r1, r0
.thumb
    mov r0, #0
    mov fp, r0


然后,我像这样交叉编译了它:

$> arm-none-eabi-gcc -Wall -Wextra -mlittle-endian -c -o arm_sample arm_sample.s


这是ARM对象文件上objdump的输出:

$> objdump -d ./arm32_mov

./arm32_mov:     file format elf32-littlearm

Disassembly of section .text:
00000000 <.text>:
   0:   e3a0b000    mov fp, #0
   4:   01a01000    moveq   r1, r0
   8:   2000        movs    r0, #0
   a:   4683        mov fp, r0


但是,当我运行我的工具时,我得到:

 warning: decoder says at (0x8,0):'strmi r2, [r3], r0' : Unknown mnemonic
   0:   00 b0 a0 e3                 mov fp, #0
   4:   00 10 a0 01                 moveq   r1, r0
   8:   ...


我的工具基于libopcodes(与objdump一样),因此第三条指令仍被解释为仍在32位模式和两条拇指模式指令仅被解释为一个给出strmi r2, [r3], r0的32位指令。到拇指模式。在发现这一点之前,我认为尽管CPSR状态寄存器中的objdump标志的值,该信息仅在执行时可用。看不到任何依赖于体系结构的情况来对待ARM拇指模式的情况。所以,这对我来说仍然是个谜...

任何建议都值得欢迎!

编辑

事实上,我在研究一个物体文件(与t选项一起编译),因此没有太多符号。但是,这是通过objdump获得的更详细的输出:

$> objdump -x ./arm32_mov

./arm32_mov:     file format elf32-littlearm
./arm32_mov
architecture: armv4t, flags 0x00000010:
HAS_SYMS
start address 0x00000000
private flags = 5000000: [Version5 EABI]

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000000c  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000040  2**0
                  ALLOC
  3 .ARM.attributes 00000016  00000000  00000000  00000040  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l    d  .ARM.attributes    00000000 .ARM.attributes


,这是-c的输出:

$> readelf -a ./arm32_mov
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          148 (bytes into file)
  Flags:                             0x5000000, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         8
  Section header string table index: 5

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 00000c 00  AX  0   0  4
  [ 2] .data             PROGBITS        00000000 000040 000000 00  WA  0   0  1
  [ 3] .bss              NOBITS          00000000 000040 000000 00  WA  0   0  1
  [ 4] .ARM.attributes   ARM_ATTRIBUTES  00000000 000040 000016 00      0   0  1
  [ 5] .shstrtab         STRTAB          00000000 000056 00003c 00      0   0  1
  [ 6] .symtab           SYMTAB          00000000 0001d4 000070 10      7   7  4
  [ 7] .strtab           STRTAB          00000000 000244 000007 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.
There are no program headers in this file.
There are no relocations in this file.
There are no unwind sections in this file.

Symbol table '.symtab' contains 7 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 SECTION LOCAL  DEFAULT    1 
     2: 00000000     0 SECTION LOCAL  DEFAULT    2 
     3: 00000000     0 SECTION LOCAL  DEFAULT    3 
     4: 00000000     0 NOTYPE  LOCAL  DEFAULT    1 $a
     5: 00000008     0 NOTYPE  LOCAL  DEFAULT    1 $t
     6: 00000000     0 SECTION LOCAL  DEFAULT    4 

No version information found in this file.
Attribute Section: aeabi
File Attributes
  Tag_CPU_arch: v4T
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-1


解决方案(Ian Cook)

$ objdump --syms --special-syms ./arm32_mov

./arm32_mov:     file format elf32-littlearm

SYMBOL TABLE:
00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l       .text  00000000 $a   <-- ARM code
00000008 l       .text  00000000 $t   <-- Thumb code
00000000 l    d  .ARM.attributes    00000000 .ARM.attributes


可以肯定的是,我再次插入了手臂代码,拇指代码和手臂代码。这是转储文件:

$> objdump --syms --special-syms ./arm32_mov

./arm32_mov:     file format elf32-littlearm

SYMBOL TABLE:
00000000 l    d  .text  00000000 .text
00000000 l    d  .data  00000000 .data
00000000 l    d  .bss   00000000 .bss
00000000 l       .text  00000000 $a
00000008 l       .text  00000000 $t
0000000c l       .text  00000000 $a
00000000 l    d  .ARM.attributes    00000000 .ARM.attributes


您会看到在objdumpreadelf上出现了两次ARM符号,这些ARM符号围绕在拇指符号周围。

评论

转储符号表

实际上,我没有太多符号,因为我只是直接用汇编语言编写的,并且没有链接最终的目标文件(我也这样做了,但结果完全相同。但是,我以最短的工作示例为例)。

#1 楼

ARM对象文件中应包含用于标识区域的符号,这些符号分别是Arm代码($a),Thumb代码($t)和文字数据($d)。在

中,您可以在符号#4和#5中看到它们。您的阅读精灵输出。
ie如果您使用0选项,则偏移量8为手臂,偏移量--special-syms为拇指

obj-dump也会输出这些符号。

阅读ARM ELF ABI将帮助您理解什么

如果您打算尝试在Apple(Mach-O)可执行文件或固件Blob中反汇编ARM代码,那么您将不得不使用另一种技术,因为这些符号不会在场。

评论


优秀的。确实,我在示例文件中找到了您正在谈论的符号。谢谢 !

–恐怖
14年8月16日在9:09

刚知道其他可执行文件格式时,您说过Mach-O没有这样的符号,但是Microsoft Windows PE格式呢?它也将这些信息存储在符号中吗?

–恐怖
14年8月16日在10:26

@perror:IMAGE_FILE_MACHINE_ARMNT假定为Thumb-2。我认为较旧的(用于WinCE)使用位0。

–伊戈尔·斯科钦斯基♦
2014年8月16日14:05

#2 楼

在代码映射符号($a$t$d)可用的情况下解决了此问题。但是,即使没有可用的符号,仍然有可能(几乎)完美地拆卸Thumb-2。

一种有前途的技术是推测性拆卸,本文已对此进行了讨论。 Spedi这个工具在这里开源。它至少在使用的有限基准测试方面优于IDA Pro。还可以指示Spedi使用ARM代码映射符号(如果有的话)来获得基本事实。

可以利用本文讨论的思想来增强此工具,甚至解决您的混合模式反汇编的情况。当符号不可用时。

#3 楼

编译C / C ++代码时,还可以通过查看符号表来检测功能的ARM /缩略图状态。对于Thumb指令,地址的最低位设置为1;对于ARM指令,地址的最低位设置为0。要查看此内容,可以使用readelf --symWhen using objdump -t and readelf`。

$ readelf --syms foo.elf |grep strlen$
  4460: 08000195    16 FUNC    GLOBAL DEFAULT    2 strlen
$ objdump -t foo.elf |grep strlen$
  08000194 g     F .text  00000010 strlen


请注意,实际地址为8000194(32位对齐),但是符号表条目(如readelf所示)显示9000195(其中LSB设置为指示拇指)。

这种方法只会告诉您函数开始时的ARM /缩略图状态,以查看任何内容。在函数内部进行转换时,您仍然需要查看其他答案中记录的$t$a符号。

此LSB的含义在ARM ELF ABI中定义:


5.5.3符号值

除符号值的常规规则外,以下规则也适用于STT_FUNC类型的符号:


如果该符号寻址一条Arm指令,则其值就是该指令的地址(在可重定位的对象中,该指令与包含该指令的节的开头之间的偏移量)。
如果该符号寻址到Thumb指令, n,其值是设置了位0的指令的地址(在可重定位对象中,设置了位0的节偏移)。
为了重定位,使用的值应是指令的地址(st_value) &〜1)。

注意:这使链接程序无需参考映射即可区分Arm和Thumb代码符号。 Arm符号将始终具有偶数值,而Thumb符号将始终具有奇数值。但是,链接器应在将其用于重定位之前从该值中去除该区分位。