您的位置:首页 > 其它

180104 逆向-DebugMe(3)&ARM调用约定

2018-01-05 11:41 253 查看
1625-5 王子昂 总结《2018年1月4日》 【连续第461天总结】

A. ARM调用约定

B.

ARM汇编中规定:R0-R3这4个寄存器用来传递函数调用的第1到第4个参数,超出的参数通过堆栈来传递。R0寄存器同时用来存放函数调用的返回值。被调用的函数在返回前无需恢复这些寄存器的内容。

知道这一点就可以回头去搞DebugMe那里IDA解析错误的函数了

先回忆一下该函数:



可以看到v10是不明来由的,事实上是因为在汇编状态下,返回值理应由r0传递

但是在(又调用了一个子函数,只是包装的)sub_EAC中,调用完子函数后将R0赋值给了r1,使得在外部将r1赋给v3(即r7)时IDA不知道r1是哪来的

这是一个不符合调用约定的行为

那么分析ARM汇编

.text:00000D44                 MULS    R0, R3          ; 7*(r7+1)
.text:00000D46                 MOVS    R1, #0xB        ; 11
.text:00000D48                 BL      sub_EAC
.text:00000D4C                 ADDS    R4, #1
.text:00000D4E                 MOVS    R7, R1


可以看到,R0和R1分别传参,R4是计数器可以不用管它

R7就是外部的v3,我们的关键变量

那么继续向内查看追踪R1

text:00000EAC                 CMP     R1, #0
.text:00000EAE                 BEQ     sub_E98
.text:00000EB0                 PUSH    {R0,R1,LR}      ; r0 = 7*(r3+1)
.text:00000EB0                                         ; r1 = 11
.text:00000EB2                 BL      sub_E14
.text:00000EB6                 POP     {R1-R3}         ; r1 = 7*(r3+1)
.text:00000EB6                                         ; r2 = 11
.text:00000EB8                 MULS    R2, R0          ; r1=r1-(r2*r0)
.text:00000EBA                 SUBS    R1, R1, R2      ; r3 = 7*(r3+1)-11*sub(7*e3+1, 11)
.text:00000EBC                 BX      R3


可以看到,在R1=11的情况下会跳过sub_E98,将R0、R1和LR(返回地址)PUSH入栈中,再调用sub_E14

运算完成后将堆栈POP出来

根据调用约定,被调用方是不会清理参数存放的,也就是说在函数内部的堆栈都包含在栈帧中解决的情况下,这里的堆栈仍然是刚才传入的参数

于是此时R1=原R0=7*(r3+1),R2=原R1=11,R3=原LR

下面进行返回值计算:

R2 = R2*R0; 11*sub_E14()

R1 = R1-R2; 7*(R3+1) - 11*sub_E14()

从而得到
v3 = 7*(v3+1) - 11*sub_E14(7*(v3+1), 11)
的递推式

另外,sub_E14这个函数其实就是整除

核心部分如下



可以看到,先将除数a2左移到比a1大的情况

然后再不断试探,如果能除就作差并在结果v4上记下一位

直到a1能整除a2(a1=0)或a1不能整除a2(标志位v3=0),此时余数为a1

这里有一个疑问,余数a1(即r0)是否会被保存下来呢?

答案是否定的,虽然在函数内直接调用寄存器进行计算,但是r0作为结果寄存器,将只会保留商,即结果v4

result = v4;


另一方面,参数是放在堆栈中的,没有参与运算,POP出来可以保证原值

这样可以追溯出该调用的本来样貌:

v3 = 7*(v3+1) - 7*(v3+1)//11*11


C. 明日计划

比赛、看书
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: