例如我有以下汇编代码,
0x60ECE B loc_60EE6
;
;
;
0x60EE6 LDR.W R2, #0x123
位置
0x60ECE
的十六进制代码为0A E0
。我想知道它是如何计算的。根据https://stackoverflow.com/questions/6744661/understanding-arm-assembler-branch-offset-calculation,offset应该是04
而不是0A
。我正在处理android二进制文件。
#1 楼
指令格式为little-endian,因此字节0A E0
被解析为机器代码0xE00A
或二进制形式的1110000000001010b
。根据THUMB指令集的文档,前5位(
11100b
)解码到无条件分支操作码,最后11位(00000001010b
)解码为Offset11:根据上面的文档,目标地址计算为“相对于PC +/- Offset11 << 1“加上4用于预取操作。
如果我们做数学运算,我们会发现一切都变了:
0x60ECE + (00000001010b << 1) + 0x4
== 0x60ECE + 10100b + 0x4
== 0x60ECE + 0x14 + 0x4
== 0x60EE6
#2 楼
您错过了以下事实:您正在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 ......@.#...
您在
0ae0
看到60ece
,在40f22312f1e7
看到60ee6
。您可以直接在IDA中对此进行修补,也可以使用idapatcher插件复制/粘贴十六进制。我发现这比手动制作修补的字节要容易得多。
评论
谢谢您的先生指出这个窍门。这对我来说使一切变得容易得多。终于我能够创建代码凹坑了。
–user2578525
2015年6月9日下午4:31