我有一个老式的嵌入式系统,带有ARM cpu内核,我转储了ROM,用binwalk解压缩,并加载到IDA pro上。 我发现在某个例行程序中,BX不带LR,而是带有通用寄存器(R2,R3等),在伪代码中,它就像这样的“ memory [0xCC1232](a3,v4)”一样。我以为这就像ARM编译器构建C指针函数一样。可以吗 无论如何,我的主要问题是,如何仅通过ROM转储找到该子例程(memoryx ..)?因为该地址是ram地址,所以在没有ram dump的情况下,我找不到该子例程的引用?将值写入该特定地址,但这几乎是不可能的 谢谢
答案 0 :(得分:1)
取决于编译器设置和不带lr的bx目标是非常普遍的,如果不需要,因为lr的较早的核心pop(通常为ldmia)不适用于在arm和thumb模式之间切换,因此编译器将生成pop到r3,然后是bx r3。
extern unsigned int more_fun ( void );
unsigned int fun ( void )
{
return(more_fun()+1);
}
00000000 <fun>:
0: b510 push {r4, lr}
2: f7ff fffe bl 0 <more_fun>
6: 3001 adds r0, #1
8: bc10 pop {r4}
a: bc02 pop {r1}
c: 4708 bx r1
e: 46c0 nop ; (mov r8, r8)
vs
00000000 <fun>:
0: b508 push {r3, lr}
2: f7ff fffe bl 0 <more_fun>
6: 3001 adds r0, #1
8: bd08 pop {r3, pc}
a: bf00 nop
r4 vs r3作为虚拟寄存器在这里并不重要,有趣的是编译器可以这样做,但是它们只是用来使堆栈对齐,而不是保留寄存器。
这当然是拇指模式,手臂模式
00000000 <fun>:
0: e92d4010 push {r4, lr}
4: ebfffffe bl 0 <more_fun>
8: e8bd4010 pop {r4, lr}
c: e2800001 add r0, r0, #1
10: e12fff1e bx lr
您可能希望看到lr与bx lr一起使用
或更新版本,但gcc至少默认为拇指模式,您必须强制它生成像这样的手臂代码
00000000 <fun>:
0: e92d4010 push {r4, lr}
4: ebfffffe bl 0 <more_fun>
8: e2800001 add r0, r0, #1
c: e8bd8010 pop {r4, pc}
就找到ram中的内容而言,您需要做更多的工作,这可能是不可能的。如果这是一个嵌入式系统,并且所有内容都在非易失性存储器(闪存/ ROM /等)中,则在某些情况下(如果代码在ram中),则在分支之前将其复制或解压缩或以其他方式放入ram中。另一方面,您可能已经分解了一些代码,可以在ram中调用代码,但是ram中的代码可能来自下载,基本上是一些最终不在板上/芯片上的外部源。就像具有代码的引导程序,该引导程序可以通过uart下载程序然后将其分支到该程序一样,这并不意味着该代码可以正常使用,并且当然意味着您无法预测或知道该代码将是什么,更不用说找到并反汇编它了。
如果我下载到0x20000000并可以手动使用非lb的bx来启动此类代码,并且以某种方式知道这不是拇指代码,那么我需要以某种方式将地址或1或br改为or,有时您需要注册,有时不需要。
您还将看到链接器使用bx修补远处的东西或更改模式:
unsigned int more_fun ( void )
{
return(3);
}
链接器为您添加蹦床:
00000000 <fun>:
0: e92d4010 push {r4, lr}
4: eb000003 bl 18 <__more_fun_from_arm>
8: e8bd4010 pop {r4, lr}
c: e2800001 add r0, r0, #1
10: e12fff1e bx lr
00000014 <more_fun>:
14: 2003 movs r0, #3
16: 4770 bx lr
00000018 <__more_fun_from_arm>:
18: e59fc000 ldr r12, [pc] ; 20 <__more_fun_from_arm+0x8>
1c: e12fff1c bx r12
20: 00000015 andeq r0, r0, r5, lsl r0
24: 00000000 andeq r0, r0, r0
,在这种情况下使用r12。
答案 1 :(得分:0)
通常情况下,不拆卸和分析代码就无法确定实际的跳转地址。但是,可能有几种技巧。
BX LR
结尾)。您可以通过扫描ROM来查找所有或大多数子例程入口点,因为怀疑下一个子例程的入口点位于上一个“ BX LR”的旁边。要确定是否间接调用了特定的子例程,请尝试搜索其子地址是否存在于ROM中,或者是否装有“ MOVW” +“ MOVT”对。这使您知道可以在哪里使用它。从GNAT的运行时获取的示例RAM初始化代码:
movw r0,#:lower16:__data_start ; __data_start points to RAM
movt r0,#:upper16:__data_start ; (often it is start of RAM)
movw r1,#:lower16:__data_words
movw r2,#:lower16:__data_load ; __data_load points to ROM
movt r2,#:upper16:__data_load ; right after code and readonly data
cbz r1,1f
0: ldr r4,[r2],#4
str r4,[r0],#4
subs r1,r1,#1
bne 0b
1: