问题
我希望有人可以帮助我确定为什么这个二进制文件不会执行。
它是一个闭源的、剥离的 ARM 二进制文件。也就是说,它可以在互联网上免费下载,所以在这篇文章的底部有一个链接。
目标是从固件映像中提取的 ARM 二进制文件。我已经设置了一个 ARM VM,但也尝试在 Pi 上运行二进制文件,结果相同。
这是我所看到的:
root@debian-armel:/tmp/squashfs-root/usr/bin# ./my_arm_bin
Illegal instruction
“非法指令”错误并不是很有帮助……所以我深入挖掘了一点。
我的虚拟机
我不认为问题出在我的 VM 上。这是一个非常标准的 ARM VM 设置。来自:https : //people.debian.org/~aurel32/qemu/armel/
使用debian_squeeze_armel_standard.qcow2
,initrd.img-2.6.32-5-versatile
和vmlinuz-2.6.32-5-versatile
。它与 QEMU 一起启动,并转发了一些端口(ssh、http、31337 用于 gdb 内容)。我可以毫无问题地在系统上执行其他 ARM 二进制文件,包括从同一固件映像中提取的其他二进制文件。
此外,正如之前提到的,我尝试将二进制文件放到 Pi 上,但没有运气。我在 pi 上以 root 身份以及在 chroot 环境中使用提取的固件映像的 rootfs 进行了尝试,结果相同:Illegal Instruction
.
r2 信息
rabin2 -I my_arm_bin
:
Warning: Cannot initialize dynamic strings
arch arm
binsz 44831825
bintype elf
bits 32
canary false
class ELF32
crypto false
endian little
havecode true
lang c
linenum false
lsyms false
machine ARM
maxopsz 16
minopsz 1
nx false
os linux
pcalign 0
pic false
relocs false
rpath NONE
static true
stripped true
subsys linux
va true
额外调试(gdb w/ gef on Pi)
因此,是时候附加一个调试器并准确查看实际抛出该错误的指令了。这是在 Pi 上完成的。
在启动和进入中断后,使用ni
单步,我看到:
gef> x/20i $pc
=> 0x796a0: mov r11, #0
0x796a4: mov lr, #0
0x796a8: pop {r1} ; (ldr r1, [sp], #4)
0x796ac: mov r2, sp
0x796b0: push {r2} ; (str r2, [sp, #-4]!)
0x796b4: push {r0} ; (str r0, [sp, #-4]!)
0x796b8: ldr r12, [pc, #16] ; 0x796d0
0x796bc: push {r12} ; (str r12, [sp, #-4]!)
0x796c0: ldr r0, [pc, #12] ; 0x796d4
0x796c4: ldr r3, [pc, #12] ; 0x796d8
0x796c8: bl 0x4021a0
0x796cc: bl 0x401fa0
0x796d0: andeq r2, r12, #200, 2 ; 0x32
0x796d4: andeq r10, r1, r12, lsl #11
0x796d8: andeq r2, r12, #40, 2
0x796dc: ldr r3, [pc, #20] ; 0x796f8
0x796e0: ldr r2, [pc, #20] ; 0x796fc
0x796e4: add r3, pc, r3
0x796e8: ldr r2, [r3, r2]
0x796ec: cmp r2, #0
gef>
这一切看起来都是有效的 ARM 指令。
在情况下,它相关的-所有LDR指令(0x796b8,0x796c0,0x796c4)在gdb执行时是给这样的信息:Cannot access memory at address 0x0
。一些 mov 指令也会抛出这个。
在0x796c8: bl 0x4021a0
:
-> 0x796c8 bl 0x4021a0
\-> 0x4021a0 ldr pc, [pc, #-4] ; 0x4021a4
最终我们到达这里:
gef> x/20i $pc
=> 0x20c1b30: push {r4, r5, r6, r7, lr}
0x20c1b34: sub sp, sp, #300 ; 0x12c
0x20c1b38: movw r12, #0
0x20c1b3c: mov r5, r3 --> Here is our illegal instruction
0x20c1b40: movt r12, #0
0x20c1b44: str r1, [sp, #4]
0x20c1b48: movw r1, #65336 ; 0xff38
0x20c1b4c: cmp r12, #0
0x20c1b50: ldr r3, [sp, #4]
0x20c1b54: str r2, [sp, #8]
0x20c1b58: ldrne r12, [r12]
0x20c1b5c: add r2, r3, #1
0x20c1b60: str r0, [sp, #12]
0x20c1b64: movw r3, #56376 ; 0xdc38
0x20c1b68: ldr r7, [sp, #8]
0x20c1b6c: movw r0, #3092 ; 0xc14
0x20c1b70: ldr lr, [sp, #328] ; 0x148
0x20c1b74: clzne r12, r12
0x20c1b78: movt r0, #685 ; 0x2ad
0x20c1b7c: movt r1, #827 ; 0x33b
当然,可以在此处找到二进制文件的副本:https : //mega.nz/#!CKxBQKaI!T__d9pjpOn_rPtfvPNkkPsFWHTjg7u-vDt5AK6610ug
那么寄存器只是没有初始化为正确的值吗?这怎么可能?
套用 Archer 的话:我没有得到什么?...我认为核心概念。
我可能在这里遗漏了一个重要的想法。我希望有人可以帮助填补空白。
更新 1:
在@0xC0000022L 的建议下,我研究了确保我的 VM/Pi 的 ARM 版本与二进制版本匹配。据我所知,他们是这样做的。只是将来自 VM 的二进制文件与我的 ARM 二进制文件进行比较,我正在尝试运行它们的 ABI 匹配(32 位 ARMv5):
$ file my_arm_bin
my_arm_bin: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, stripped
$ file /usr/bin/id
/usr/bin/id: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32, stripped
更新 2:
在@perror 建议中,我尝试强制二进制文件以拇指模式执行。这里的上下文是在“手臂”(非拇指)模式下运行时的反汇编:
gef> x/10i $pc
=> 0x20c1b38: movw r12, #0
0x20c1b3c: mov r5, r3
0x20c1b40: movt r12, #0
0x20c1b44: str r1, [sp, #4]
0x20c1b48: movw r1, #65336 ; 0xff38
0x20c1b4c: cmp r12, #0
0x20c1b50: ldr r3, [sp, #4]
0x20c1b54: str r2, [sp, #8]
0x20c1b58: ldrne r12, [r12]
0x20c1b5c: add r2, r3, #1
强制拇指模式,我现在看到:
gef> set arm force-mode thumb
gef> x/10i $pc
=> 0x20c1b38: stmia r0!, {}
0x20c1b3a: b.n 0x20c213e
0x20c1b3c: str r3, [r0, r0]
0x20c1b3e: b.n 0x20c1e82
0x20c1b40: stmia r0!, {}
0x20c1b42: b.n 0x20c21c6
0x20c1b44: asrs r4, r0, #32
0x20c1b46: b.n 0x20c1664
0x20c1b48: subs r0, r7, #4
0x20c1b4a: b.n 0x20c216c
在执行之前强制使用拇指模式,程序立即退出并出现以下错误:
[!] Cannot disassemble from $PC
[!] Cannot access memory at address 0x6ac
启动可执行文件、中断和切换模式会以非法指令错误退出。