ARM中分支指令的偏移量计算

逆向工程 艾达 安卓 手臂 抵消
2021-07-01 10:04:20

正如标题所说,如何计算分支指令的偏移量?例如我有以下汇编代码,

0x60ECE    B loc_60EE6
;
;
;
0x60EE6    LDR.W R2, #0x123

位置的十六进制代码0x60ECE0A E0. 我想知道它是如何计算的。根据https://stackoverflow.com/questions/6744661/understanding-arm-assembler-branch-offset-calculation, offset 应该04代替0A

我正在研究 android 二进制文件。

2个回答

指令格式为 little-endian,因此字节0A E0被解析为机器码0xE00A1110000000001010b二进制。

根据THUMB 指令集的文档,前 5 位 ( 11100b) 解码为无条件分支操作码,后 11 位 ( 00000001010b) 解码为Offset11

无条件分支

根据上面的文档,目标地址计算为“PC 相对 +/- Offset11 << 1”加上 4 以用于预取操作。

如果我们进行数学计算,我们会看到一切正常:

   0x60ECE + (00000001010b << 1) + 0x4
== 0x60ECE +       10100b        + 0x4
== 0x60ECE +        0x14         + 0x4
== 0x60EE6

你忽略了你在 THUMB 模式下工作的事实,在这种模式下,每条指令有两个字节(至少对于大多数指令),并且该链接描述了 ARM 模式,其中每条指令有 4 个字节。

(我怎么知道你处于 THUMB 模式?除了你的最后一个问题,你0x60ECE B loc_60EE6的不是 4 字节对齐的,所以它必须是 THUMB)。

如果向 处的指令添加 4 个字节loc_60ECE,则会得到0x60ED2. 减去它60EE6得到14,或 20 位小数。除以 2(THUMB 模式下的 2 字节指令)得到10十进制或0A十六进制。

由于计算偏移量可能很困难并且容易出错,我让 gnu arm 汇编程序为我处理它。先写一个汇编文件,像这样(命名为qs,随便取个名字):

.thumb
.arch armv7a
.syntax unified
.org 0x60ECE
    B codecave
original:
.org 0x60EE6
codecave:
movw R2, #0x123
B original

然后组装它并检查结果:

arm-linux-gnueabi-as q.s
arm-linux-gnueabi-objdump -s a.out | grep -v "00000000 00000000 00000000 00000000"

Contents of section .text:
 60ec0 00000000 00000000 00000000 00000ae0  ................
 60ee0 00000000 000040f2 2312f1e7           ......@.#...    

你会看到你的0ae0at60ece40f22312f1e7at 60ee6您可以直接在 IDA 中修补它,或者使用idapatcher 插件来复制/粘贴十六进制。我发现这比手动制作修补字节要容易得多。