IDA逆向笔记-C语言入参顺序约定和结构体
Posted 千夫长-向往生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IDA逆向笔记-C语言入参顺序约定和结构体相关的知识,希望对你有一定的参考价值。
目录
1.逆向为什么必须要了解入参顺序(调用约定)?
了解这部分,可以了解汇编功能代码前(序言部分)后(结束部分)的参数传递,堆栈的入(push)出(pop)栈顺序,这是逆向代码分析的根基,在浩如烟海的汇编代码中,有这些知识和信息,会增加确定度,利于总体代码的识别。
2.X86平台不同的调用约定
C语言转为汇编,因为有不同的调用约定,会有三种参数入栈顺序和栈平衡的方法,分别是:
在32位的体系结构中,有3种调用约定,分别是cdecl
,stdcall
,fastcall
,GCC的默认调用约定为cdecl
。参数从右向左压栈,调用者负责在调用后清理堆栈,返回值保存在eax寄存器中,非易失寄存器为ebp
,esp
,ebx
,esi
,edi
。
C++还有一种叫thiscall的传参模式,导出类的函数,也是类似用寄存器eax来传递参数:
1.IDA分析的时候,默认使用cdecl来解析:
2.初始化局部变量的初始值用的是0XCCCCC,因为CC是汇编中断指令,如果不小心跑到这里,会立即终止。不会乱操作。
3.eax寄存器是放返回值的。有一种爆破的方法是:进入call调用的过程后做如下修改:
"mov eax,1"指令的作用是将eax的al赋值为01,retn则是跳出call,程序接着执行call后面的test指令(相当于c++中的return),这样的操作是因为函数retn之后,执行了一个:
4.edi,esi,edx三个寄存器是出入栈时要保留的。
5.其他寄存器的用途
(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
(3)EIP寄存器,用来存储CPU要读取指令的地址的,通过修改这个寄存器的值,可以让程序跑到一个别的地方去,比如我们自己的代码。
3.X64平台系统调用约定
X64默认使用_fastcall模式,rcx,rdx,r8,r9四个寄存器用于存放参数的最后前面的四个参数,但在栈上还是会预留4个寄存器的对应空间(shadow space),调用者负责栈的平衡:调用者来管理变量的初始化和管理堆栈指针(来支持可变参数),这和之前的约定不一样,参数入栈,会对齐到8个字节,栈的大小是16的整数倍。
下面是一个选择了X64平台编译的函数。
int mix(int a,int b,int c,int d,int e,int f, int g)
return a | b | c | d | e | f |g;
int addAll(int a,int b,int c,int d,int e,int f, int g)
return a+b+c+d+e+f+g+mix(a,b,c,d,e,f,g);
int main(int argc,char **argv)
int total;
total = addAll(1,2,3,4,5,6,7);
printf("result is %d\\n",total);
return 0;
对应的汇编指令为:
(gdb) disassemble *main
Dump of assembler code for function main:
0x0000000000400534 <main+0>: push rbp
0x0000000000400535 <main+1>: mov rbp,rsp
0x0000000000400538 <main+4>: sub rsp,0x30
0x000000000040053c <main+8>: mov DWORD PTR [rbp-0x14],edi
0x000000000040053f <main+11>: mov QWORD PTR [rbp-0x20],rsi
0x0000000000400543 <main+15>: mov DWORD PTR [rsp],0x7
0x000000000040054a <main+22>: mov r9d,0x6
0x0000000000400550 <main+28>: mov r8d,0x5
0x0000000000400556 <main+34>: mov ecx,0x4
0x000000000040055b <main+39>: mov edx,0x3
0x0000000000400560 <main+44>: mov esi,0x2
0x0000000000400565 <main+49>: mov edi,0x1
0x000000000040056a <main+54>: call 0x4004c7 <addAll>
0x000000000040056f <main+59>: mov DWORD PTR [rbp-0x4],eax
0x0000000000400572 <main+62>: mov esi,DWORD PTR [rbp-0x4]
0x0000000000400575 <main+65>: mov edi,0x400688
0x000000000040057a <main+70>: mov eax,0x0
0x000000000040057f <main+75>: call 0x400398 <printf@plt>
0x0000000000400584 <main+80>: mov eax,0x0
0x0000000000400589 <main+85>: leave
0x000000000040058a <main+86>: ret
对应的addALL里面,极有可能会有这样的汇编语句:
move dword ptr p[rsp+20h],r9d ;将四个寄存器的值放回到堆栈中
move dword ptr p[rsp+18h],r8d
move dword ptr p[rsp+10h],edx
move dword ptr p[rsp+8h],ecx
以上是关于IDA逆向笔记-C语言入参顺序约定和结构体的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向IDA 工具使用 ( 十六进制视图 Hex View-1 | 结构体视图 Structures | 枚举视图 Enums | 导入视图 Import | 导出视图 )
Android 逆向IDA 工具使用 ( 十六进制视图 Hex View-1 | 结构体视图 Structures | 枚举视图 Enums | 导入视图 Import | 导出视图 )(