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汇编
可以看到,R0和R1分别传参,R4是计数器可以不用管它
R7就是外部的v3,我们的关键变量
那么继续向内查看追踪R1
可以看到,在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()
从而得到
另外,sub_E14这个函数其实就是整除
核心部分如下
可以看到,先将除数a2左移到比a1大的情况
然后再不断试探,如果能除就作差并在结果v4上记下一位
直到a1能整除a2(a1=0)或a1不能整除a2(标志位v3=0),此时余数为a1
这里有一个疑问,余数a1(即r0)是否会被保存下来呢?
答案是否定的,虽然在函数内直接调用寄存器进行计算,但是r0作为结果寄存器,将只会保留商,即结果v4
另一方面,参数是放在堆栈中的,没有参与运算,POP出来可以保证原值
这样可以追溯出该调用的本来样貌:
C. 明日计划
比赛、看书
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. 明日计划
比赛、看书
相关文章推荐
- x86 常见调用约定(cdecl,fastcall,stdcall) & x86和ARM调用约定的栈帧分析 & ARM ATPCS(ARM-THUMB procedure call standard)
- iOS高级调试&逆向技术-汇编寄存器调用约定教程
- C++常用的调用约定__cdecl &__stdcall
- 逆向知识十一讲,识别函数的调用约定,函数参数,函数返回值.
- C/C++中函数的调用约定(__cdecl, __stdcall)以及extern, extern “C"的详细解释
- _STDCALL&_CDECL 调用约定
- _STDCALL&_CDECL 调用约定
- 170826 逆向-段寄存器和调用约定的补充知识点
- _STDCALL&_CDECL 调用约定
- iOS高级调试&逆向技术-汇编寄存器调用
- GCC&&G++ C && C++ 内嵌汇编和调用汇编函数的方法(x86,ARM自己对照改)
- ARM 调用约定 calling convention
- ARM汇编 C语言 C++ 相互调用 <此方法在armv8 测试成功 !>
- C语言函数调用约定-stdcall&cdecl&thiscall
- 【黑客免杀攻防】读书笔记7 - 软件逆向工程基础1(函数调用约定、Main函数查找)
- 模块"........."已加载,但对DllRegisterServer的调用失败
- cdecl和stdcall调用约定的汇编代码对比
- 几种调用约定(Calling convention)的介绍
- 裸函数_与调用约定
- mybatis逆向工程的Example类用法==笔记==【单表操作只需调用,多表查询需要自定义sql+mapper接口方法(待补全)】