函数补充
- 函数的参数和返回值
ARM64下,函数的参数
是存放在X0到X7(W0到W7)这8个寄存器里面的.如果超过8个参数,就会入栈.函数的返回值
是放在X0 寄存器里面的.- 函数的局部变量
函数的局部变量放在栈里面!
还原高级代码
在这之前一直都在看汇编代码,那么接下来我们通过汇编代码,一步一步还原高级代码。
我们先随便写个demo,选择真机,command + b
拿到demo.app文件。接下里右键显示包内容
拿到可执行文件
接下来讲可执行文件通过ida
打开,得到如下结果
(注:没安装ida的童鞋自己百度,也可以看我第一篇笔记《逆向学习笔记1 —— 工具安装》
接下里我们练习里面需要还原的部分是
func
函数里面的内容。根据汇编部分,我们分析结果如下(汇编中,w寄存器是x寄存器的低32位,所以Wx=Xx)
__text:00000001000068E4 _main
__text:00000001000068E4
__text:00000001000068E4 var_14 = -0x14
__text:00000001000068E4 var_10 = -0x10
__text:00000001000068E4 var_4 = -4
__text:00000001000068E4 var_s0 = 0
__text:00000001000068E4 SUB SP, SP, #0x30
__text:00000001000068E8 STP X29, X30, [SP,#0x20+var_s0]
__text:00000001000068EC ADD X29, SP, #0x20
//寄存器w8=2,是用w寄存器存储的,说明是int/short
__text:00000001000068F0 MOV W8, #2
//寄存器w9=3,是用w寄存器存储的,说明是int/short
__text:00000001000068F4 MOV W9, #3
__text:00000001000068F8 STUR W0, [X29,#var_4]
__text:00000001000068FC STR X1, [SP,#0x20+var_10]
//寄存器x0=x8=2
__text:0000000100006900 MOV X0, X8
//寄存器x1=x9=3
__text:0000000100006904 MOV X1, X9
//调用func函数的部分,根据函数传值的特征这里可大概估计出func函数有两个参数x0,x1
__text:0000000100006908 BL _func
__text:000000010000690C MOV W8, #0
__text:0000000100006910 STR W0, [SP,#0x20+var_14]
__text:0000000100006914 MOV X0, X8
__text:0000000100006918 LDP X29, X30, [SP,#0x20+var_s0]
__text:000000010000691C ADD
int pi = 0;
int func(int a, int b){
//_text:000000010000688C EXPORT _func
//__text:000000010000688C _func ; CODE XREF: _main+24↓p
//__text:000000010000688C
//__text:000000010000688C var_20 = -0x20
//__text:000000010000688C var_C = -0xC
//__text:000000010000688C var_8 = -8
//__text:000000010000688C var_4 = -4
//__text:000000010000688C var_s0 = 0
//以上部分是ida将栈偏移的部分保存在变量中
//__text:000000010000688C
//__text:000000010000688C SUB SP, SP, #0x30
//__text:0000000100006890 STP X29, X30, [SP,#0x20+var_s0]
//__text:0000000100006894 ADD X29, SP, #0x20
//上面三句是栈操作不用去管
//下面两句是取得一个全局变量pi,具体地址目前还不清楚,根据下面打印 %d可以判断出pi为int
//__text:0000000100006898 ADRP X8, #_pi@PAGE
//__text:000000010000689C ADD X8, X8, #_pi@PAGEOFF
int * x8 = π
//下面两句直接是stur操作,可以判断出,下面两句是用来存函数的形参, 这里也就确定了func函数有两个参数,参数是暂且用int类型代替了
//__text:00000001000068A0 STUR W0, [X29,#var_4]
int var_4 = a;
//__text:00000001000068A4 STUR W1, [X29,#var_8]
int var_8 = b;
//这里w0加载x8中的值
//__text:00000001000068A8 LDR W0, [X8]
int w0 = *x8;
//__text:00000001000068AC MOV X8, X0
//int x8 = pi;
x8 = pi;
//
//__text:00000001000068B0 MOV X9, SP
//__text:00000001000068B4 STR X8, [X9,#0x20+var_20]
// x8=x9;
//__text:00000001000068B8 ADRP X0, #aD@PAGE ; "%d"
//__text:00000001000068BC ADD X0, X0, #aD@PAGEOFF ; "%d"
//__text:00000001000068C0 BL _printf
printf("%d",w0);
//__text:00000001000068C4 LDUR W1, [X29,#var_4]
int w1 = var_4;
//__text:00000001000068C8 LDUR W10, [X29,#var_8]
int w10 = var_8;
//__text:00000001000068CC ADD W10, W1, W10
w10 = w1 + w10;
//存储w0所对应的值
//__text:00000001000068D0 STUR W0, [X29,#var_C]
//__text:00000001000068D4 MOV X0, X10
w0 = w10;
//根据函数的特征,返回值放在w0/x0中,所以此处一定有返回值,根据x10的结果,可以得知是个int 类型
return w0;
//以下是栈平衡
//__text:00000001000068D8 LDP X29, X30, [SP,#0x20+var_s0]
//__text:00000001000068DC ADD SP, SP, #0x30
// 返回
//__text:00000001000068E0 RET
}
删掉多余的部分得到的结果如下:
int pi = 0;
int func(int a, int b){
int * x8 = π
int var_4 = a;
int var_8 = b;
int w0 = *x8;
x8 = pi;
printf("%d",w0);
int w1 = var_4;
int w10 = var_8;
w10 = w1 + w10;
w0 = w10;
return w0;
}
从下向上替换,最终得到的结果如下:
//这个全局变量的值,没办法确定,需要动态调试,本节重点在于做个汇编还原高级代码的联系,动态调试的内容放在后面的部分再讲
int pi = 0;
int func(int a, int b){
printf("%d",pi);
return a + b;
}
这样一个简单的汇编还原练习就这样完成了,怎么样?赶快为自己点个赞吧