汇编逆向(二)
本帖最后由 gmh5225 于 2014-12-25 14:47 编辑写这个纯属就是自己记录下自己的学习经历,没有其他的意思。
C函数的传递方式有三种: (1) __cdecl(2) __stacall(3) __fastcall 当然还有其他的 pascal register 什么的,不过这都不是C调用的,不管
先随便写下三种方式的函数
int __cdecl add1(int a,int b)
{
return a+b;
}
int __stdcall add2(int a,int b)
{
return a+b;
}
int __fastcall add3(int a,int b)
{
return a+b;
}
int main()
{
int a=3,b=4,c=0;
c=add1(a,b);
c=add2(a,b);
c=add3(a,b);
printf("%d",c);
system("pause");
return 0;
}
载入OD003C1040 >55 push ebp ;保存原来ebp指针
003C1041 8BEC mov ebp, esp ;ebp指向esp,即堆栈
003C1043 83EC 0C sub esp, 0xC ; 开辟12个字节空间供3个变量
003C1046 C745 FC 0300000>mov dword ptr , 0x3 ; int a
003C104D C745 F8 0400000>mov dword ptr , 0x4 ; int b
003C1054 C745 F4 0000000>mov dword ptr , 0x0 ; int c
003C105B 8B45 F8 mov eax, dword ptr
003C105E 50 push eax ; 压 b
003C105F 8B4D FC mov ecx, dword ptr
003C1062 51 push ecx ; 压 b
003C1063 E8 98FFFFFF call testtest.add1 ; _cdecl调用
003C1068 83C4 08 add esp, 0x8 ; 在函数外部平衡堆栈
003C106B 8945 F4 mov dword ptr , eax
003C106E 8B55 F8 mov edx, dword ptr
003C1071 52 push edx ; 压 b
003C1072 8B45 FC mov eax, dword ptr
003C1075 50 push eax ; 压 a
003C1076 E8 95FFFFFF call testtest.add2 ; _stdcall 在函数内部平衡堆栈
003C107B 8945 F4 mov dword ptr , eax
003C107E 8B55 F8 mov edx, dword ptr ; _fastcall特色不压参数
003C1081 8B4D FC mov ecx, dword ptr ; 分别传递b,a
003C1084 E8 97FFFFFF call testtest.add3
003C1089 8945 F4 mov dword ptr , eax
003C108C 8B4D F4 mov ecx, dword ptr
003C108F 51 push ecx
003C1090 68 F4203C00 push testtest.003C20F4 ; ASCII "%d"
003C1095 FF15 9C203C00 call dword ptr [<&MSVCR100.printf>] ; msvcr100.printf
003C109B 83C4 08 add esp, 0x8
003C109E 68 F8203C00 push testtest.003C20F8 ; ASCII "pause"
003C10A3 FF15 A4203C00 call dword ptr [<&MSVCR100.system>] ; msvcr100.system
003C10A9 83C4 04 add esp, 0x4
003C10AC 33C0 xor eax, eax ;清空eax
003C10AE 8BE5 mov esp, ebp ;esp指向当前ebp,同步跟进
003C10B0 5D pop ebp ;还原原来ebp指针
003C10B1 C3 retn
__cdecl函数内部
003C1000 >55 push ebp
003C1001 8BEC mov ebp, esp
003C1003 8B45 08 mov eax, dword ptr //这里是第一个参数,也就是a
003C1006 0345 0C add eax, dword ptr // b
003C1009 5D pop ebp
003C100A C3 retn
__stdcall函数内部
003C1010 >55 push ebp
003C1011 8BEC mov ebp, esp
003C1013 8B45 08 mov eax, dword ptr //一样,第一个参数 ,a
003C1016 0345 0C add eax, dword ptr // b
003C1019 5D pop ebp
003C101A C2 0800 retn 0x8 //这里就是上述所说的在函数内部的堆栈平衡
__fastcall函数内部
003C1020 >55 push ebp
003C1021 8BEC mov ebp, esp
003C1023 83EC 08 sub esp, 0x8 //开辟8个字节,也就是2个int的空间
003C1026 8955 F8 mov dword ptr , edx //此edx就是函数外部的ebx ,也就是b
003C1029 894D FC mov dword ptr , ecx //这是a
003C102C 8B45 FC mov eax, dword ptr //a赋值给eax
003C102F 0345 F8 add eax, dword ptr //eax=eax+b
003C1032 8BE5 mov esp, ebp
003C1034 5D pop ebp
003C1035 C3 retn <font color="#0000ff">//因为之前没有压栈,这里不需要平衡
总结一下:_cdecl 和_stdcall 传递参数需要压栈,_cdecl和_fastcall在函数内部返回时不需要平衡堆栈,并且_cdecl在函数外部平衡堆栈,_fastcall因为根本就没有压栈,所以不需要平衡堆栈,最后是_stdcall是在函数内部返时平衡的堆栈 , 前2种满足堆栈的压栈方式,先进后出,也就是第一个压入的变量其实是最后一个。
这里要纠正一个错误:__fastcall 前2个int 都是由ecx和edx传递的,多余的函数还是需要和上面2个调用函数一样,需要压栈
补例:0020107E 8B4D F4 mov ecx, dword ptr ; 这里函数原型是int add(int a,int b,int c) 超过了2个int,所以需要压栈
00201081 51 push ecx ; //压入c
00201082 8B55 F8 mov edx, dword ptr //传递b
00201085 8B4D FC mov ecx, dword ptr //传递 a
00201088 E8 93FFFFFF call testtest.add3
汇编命令自行百度谷歌。。。别来问我了
感谢分享学习笔记~ 赞一个~
膜拜Android逆向帝,C编程帝,C逆向帝,汇编帝,反汇编帝
五帝合一,天下无敌,膜拜大神!占位支持
经典教学,谢谢。
向大神看齐!谢谢分享!
{:5_191:}膜拜楼主大牛···不明觉厉!···占位支持...
{:5_117:}谢谢分享,进来学习了呀。哈哈。
不错,学习了,谢谢!
大神求加好友 ..