我试图理解包含二进制代码的二进制文件如何转换为汇编指令。
例如,这里是基于ARM的应用程序的objdump的示例输出:
00008420 <main>:
8420: e92d4800 push {fp, lr}
8424: e28db004 add fp, sp, #4
8428: e24dd008 sub sp, sp, #8
842c: e59f2054 ldr r2, [pc, #84] ; 8488 <main+0x68>
8430: e24b300c sub r3, fp, #12
8434: e1a00002 mov r0, r2
8438: e1a01003 mov r1, r3
843c: ebffffc6 bl 835c <__isoc99_scanf@plt>
8440: e3a03000 mov r3, #0
8444: e50b3008 str r3, [fp, #-8]
8448: ea000006 b 8468 <main+0x48>
844c: e51b3008 ldr r3, [fp, #-8]
8450: e2833001 add r3, r3, #1
8454: e50b3008 str r3, [fp, #-8]
8458: e59f302c ldr r3, [pc, #44] ; 848c <main+0x6c>
845c: e1a00003 mov r0, r3
8460: e51b1008 ldr r1, [fp, #-8]
8464: ebffffb3 bl 8338 <printf@plt>
8468: e51b300c ldr r3, [fp, #-12]
846c: e51b2008 ldr r2, [fp, #-8]
8470: e1520003 cmp r2, r3
8474: bafffff4 blt 844c <main+0x2c>
8478: e3a03000 mov r3, #0
847c: e1a00003 mov r0, r3
8480: e24bd004 sub sp, fp, #4
8484: e8bd8800 pop {fp, pc}
8488: 00008500 .word 0x00008500
848c: 00008504 .word 0x00008504
正如您在偏移8464中看到的那样,二进制代码ebffffb3将转换为bl 8338.我想了解它。
这样做的明确原因是因为我想为以下python代码中存在的指令添加额外的正则表达式:
[b"[\x00\x08\x10\x18\x20\x28\x30\x38\x40\x48\x70]{1}\x47", 2, 2], # bx reg
[b"[\x80\x88\x90\x98\xa0\xa8\xb0\xb8\xc0\xc8\xf0]{1}\x47", 2, 2], # blx reg
[b"[\x00-\xff]{1}\xbd", 2, 2] # pop {,pc}
正如您所看到的,二进制文件中bx指令的正则表达式是“\ x00 \ x08 \ x10 \ x18 \ x20 \ x28 \ x30 \ x38 \ x40 \ x48 \ x70] {1} \ x47”和blx它是“\ x80 \ x88 \ x90 \ x98 \ xa0 \ xa8 \ xb0 \ xb8 \ xc0 \ xc8 \ xf0”。现在我想再添加两条指令B和BL(这些是ARM指令),但我不知道如何将指令转换为类似的二进制代码。 (源代码来自github中的ROPGadget。)
答案 0 :(得分:1)
我试图理解包含二进制代码的二进制文件如何转换为汇编指令。
除此之外:所有传统CPU硬件都使用二进制逻辑,使用一些标准晶体管配置来实现 NOT , NOR , NAND 等。很少有逻辑门,您可以使用逻辑元素的组合来实现更复杂的设备和逻辑。
因此,所有CPU都将提取位字段(几位位置,但不一定相邻)并确定它是哪种类型的指令。其他位字段将为特定操作码提供参数。
在&#39; C&#39;中,这会转换为一些掩码并比较操作,在这些操作中提取要检查的位,然后查看位模式是否相等。 GNU工具(binutils)的具体实现是arm-dis.c。
此sourceforge project是一个信息来源,但还有其他信息(包括 arm-dis.c 文件)。
|31..28|27..25| 24|23 .. 0|
+------+------+---+----------+
|cond | 101 | L | offset |
+------+------+---+----------+
唯一不变的部分是&#39; 101 &#39;。你的python reg-ex看起来像十六进制。前导半字节是一个条件,如果该指令将为真,则该条件;否则它就像 no op 。非常旧的ARM CPU文档中存在 never (前导十六进制&#39; F&#39;)条件;不推荐使用它来扩展指令集。因此可以忽略前导半字节(四位),然后查找“1010b”和“#10; 1010b”。或0xa(对于b
牧场)和&#39; 1011b&#39;或0xb(对于bl
或分支和链接)。
例如,arm-dis.c有,
{ARM_FEATURE_CORE_LOW (ARM_EXT_V1),
0x0a000000, 0x0e000000, "b%24'l%c\t%b"},
也就是说,b
和bl
指令对ROP没有用,因为它们没有 register 参数,所以你不能改变控制流。通常情况下,您只需安排将控制流直接放在ROP小工具中,而不是试图通过跳转到达它们。
b Rn
的ARM版本为mov pc, rN
;但是还有许多其他丰富的构造,例如添加移位和使用带有指针表的ldr
等等.Afaik,当我在ARM glibc上运行时,ROPGadget正在检测这些。
答案 1 :(得分:0)
引自https://www.ic.unicamp.br/~ranido/mc404/arm/arm-instructionset.pdf
分支指令包含带符号的2的补码24位偏移。 这会向左移两位,符号扩展为32位,并添加到 电脑。因此该指令可以指定+/-的分支 32M字节。分支偏移量必须考虑预取 操作,使PC在2字(8字节)之前 现行指示。超过+/- 32Mbytes的分支必须使用偏移量 或先前已加载到的绝对目的地 寄存器。在这种情况下,如果a,PC应手动保存在R14中 需要具有链接类型操作的分支。
那么让我们来看看你的分支示例
ntdll.dll
处理器逻辑采用24位偏移8464: ebffffb3 bl 8338 <printf@plt>
并将其乘以4(由于4字节对齐而有效编码)。然后它将此偏移量添加到当前指令的程序计数器+8。这给出了总和:
ffffb3