这是C/C++逆向中的基础, 无论是任何阶段都应重视,写个Deamon跟一下,就可以得出总结
1. Deamon:
// FuncCallTest.cpp : 此文件包含 "main" 函数。
//
#include <stdio.h>
#include <stdarg.h>
#include <iostream>
//非静态成员函数的第1个参数(this指针)为隐含参数
class CCallMethod {
public:
//__stdcall
int __stdcall sum_stdcall(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
}
//__cdecl
int __cdecl sum_cdecl(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
}
//__fastcall
int __fastcall sum_fastcall(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
}
//__thiscall(参数固定)
int sum_thiscall(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
}
//__thiscall(参数可变)
int sum_thiscallvarargs(int a...)
{
int sum = a, v;
va_list arg_ptr;
va_start(arg_ptr, a);
while ((v = va_arg(arg_ptr, int)) != -1) {
sum += v;
}
va_end(arg_ptr);
return sum;
}
};
int main()
{
CCallMethod objCallMethod;
printf("__stdcall: %d\n", objCallMethod.sum_stdcall(1, 2, 3, 4, 5, 6, 7));
printf("__cdecl: %d\n", objCallMethod.sum_cdecl(1, 2, 3, 4, 5, 6, 7));
printf("__fastcall: %d\n", objCallMethod.sum_fastcall(1, 2, 3, 4, 5, 6, 7));
printf("__thiscall: %d\n", objCallMethod.sum_thiscall(1, 2, 3, 4, 5, 6, 7));
printf("__thiscall(variant args): %d\n", objCallMethod.sum_thiscallvarargs(1, 2, 3, 4, 5, 6, 7,-1));
return 0;
}
2. 调试过程:
(1)x86
1)__stdcall: 从右向左压栈, 被调者自己恢复堆栈平衡
;调用者
printf("__stdcall: %d\n", objCallMethod.sum_stdcall(1, 2, 3, 4, 5, 6, 7));
00C328B2 push 7
00C328B4 push 6
00C328B6 push 5
00C328B8 push 4
00C328BA push 3
00C328BC push 2
00C328BE push 1
00C328C0 lea eax,[objCallMethod]
00C328C3 push eax
00C328C4 call CCallMethod::sum_stdcall (0C2CBEFh)
00C328C9 push eax
00C328CA push offset string "__stdcall: %d\n" (0CCEE50h)
00C328CF call _printf (0C2C3F2h)
00C328D4 add esp,8
;被调者
int __stdcall sum_stdcall(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
00C32610 push ebp
00C32611 mov ebp,esp
00C32613 sub esp,0C0h
00C32619 push ebx
00C3261A push esi
00C3261B push edi
00C3261C lea edi,[ebp-0C0h]
00C32622 mov ecx,30h
00C32627 mov eax,0CCCCCCCCh
00C3262C rep stos dword ptr es:[edi]
00C3262E mov ecx,offset _41BE8922_funccalltest@cpp (0CF7027h)
00C32633 call @__CheckForDebuggerJustMyCode@4 (0C2DEFFh)
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
00C32638 mov eax,dword ptr [a1]
00C3263B add eax,dword ptr [a2]
00C3263E add eax,dword ptr [a3]
00C32641 add eax,dword ptr [a4]
00C32644 add eax,dword ptr [a5]
00C32647 add eax,dword ptr [a6]
00C3264A add eax,dword ptr [a7]
}
00C3264D pop edi
00C3264E pop esi
00C3264F pop ebx
00C32650 add esp,0C0h
00C32656 cmp ebp,esp
00C32658 call __RTC_CheckEsp (0C2DFAEh)
00C3265D mov esp,ebp
00C3265F pop ebp
00C32660 ret 20h
2)__cdecl: 从右向左压栈, 调用者负责恢复堆栈平衡
printf("__cdecl: %d\n", objCallMethod.sum_cdecl(1, 2, 3, 4, 5, 6, 7));
00C328D7 push 7
00C328D9 push 6
00C328DB push 5
00C328DD push 4
00C328DF push 3
00C328E1 push 2
00C328E3 push 1
00C328E5 lea eax,[objCallMethod]
00C328E8 push eax
00C328E9 call CCallMethod::sum_cdecl (0C2C546h)
00C328EE add esp,20h
00C328F1 push eax
00C328F2 push offset string "__cdecl: %d\n" (0CCEE64h)
00C328F7 call _printf (0C2C3F2h)
00C328FC add esp,8
3) __fastcall: 第1个参数送ecx,第2个参数送edx,其余从右向左压栈,被调者自己恢复堆栈平横
;调用者
printf("__fastcall: %d\n", objCallMethod.sum_fastcall(1, 2, 3, 4, 5, 6, 7));
00C328FF push 7
00C32901 push 6
00C32903 push 5
00C32905 push 4
00C32907 push 3
00C32909 push 2
00C3290B mov edx,1
00C32910 lea ecx,[objCallMethod]
00C32913 call CCallMethod::sum_fastcall (0C2EA71h)
00C32918 push eax
00C32919 push offset string "__fastcall: %d\n" (0CCEE74h)
00C3291E call _printf (0C2C3F2h)
00C32923 add esp,8
;被调者
int __fastcall sum_fastcall(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
00C32590 push ebp
00C32591 mov ebp,esp
00C32593 sub esp,0D8h
00C32599 push ebx
00C3259A push esi
00C3259B push edi
00C3259C push ecx
00C3259D lea edi,[ebp-0D8h]
00C325A3 mov ecx,36h
00C325A8 mov eax,0CCCCCCCCh
00C325AD rep stos dword ptr es:[edi]
00C325AF pop ecx
00C325B0 mov dword ptr [a1],edx
00C325B3 mov dword ptr [this],ecx
00C325B6 mov ecx,offset _41BE8922_funccalltest@cpp (0CF7027h)
00C325BB call @__CheckForDebuggerJustMyCode@4 (0C2DEFFh)
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
00C325C0 mov eax,dword ptr [a1]
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
00C325C3 add eax,dword ptr [a2]
00C325C6 add eax,dword ptr [a3]
00C325C9 add eax,dword ptr [a4]
00C325CC add eax,dword ptr [a5]
00C325CF add eax,dword ptr [a6]
00C325D2 add eax,dword ptr [a7]
}
00C325D5 pop edi
00C325D6 pop esi
00C325D7 pop ebx
00C325D8 add esp,0D8h
00C325DE cmp ebp,esp
00C325E0 call __RTC_CheckEsp (0C2DFAEh)
00C325E5 mov esp,ebp
00C325E7 pop ebp
00C325E8 ret 18h
4)参数个数固定的 __thiscall: 对象地址(第1个参数this指针值)送ecx,其余参数从右向左压栈, 被调者自己恢复堆栈平横
;调用者
printf("__thiscall: %d\n", objCallMethod.sum_thiscall(1, 2, 3, 4, 5, 6, 7));
00C32926 push 7
00C32928 push 6
00C3292A push 5
00C3292C push 4
00C3292E push 3
00C32930 push 2
00C32932 push 1
00C32934 lea ecx,[objCallMethod]
00C32937 call CCallMethod::sum_thiscall (0C2DC84h)
00C3293C push eax
00C3293D push offset string "__thiscall: %d\n" (0CCEE88h)
00C32942 call _printf (0C2C3F2h)
00C32947 add esp,8
;被调者
//__thiscall(参数固定)
int sum_thiscall(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
00C32680 push ebp
00C32681 mov ebp,esp
00C32683 sub esp,0CCh
00C32689 push ebx
00C3268A push esi
00C3268B push edi
00C3268C push ecx
00C3268D lea edi,[ebp-0CCh]
00C32693 mov ecx,33h
00C32698 mov eax,0CCCCCCCCh
00C3269D rep stos dword ptr es:[edi]
00C3269F pop ecx
00C326A0 mov dword ptr [this],ecx
00C326A3 mov ecx,offset _41BE8922_funccalltest@cpp (0CF7027h)
00C326A8 call @__CheckForDebuggerJustMyCode@4 (0C2DEFFh)
return a1 + a2 + a3 + a4 + a5 + a6 + a7;
00C326AD mov eax,dword ptr [a1]
00C326B0 add eax,dword ptr [a2]
00C326B3 add eax,dword ptr [a3]
00C326B6 add eax,dword ptr [a4]
00C326B9 add eax,dword ptr [a5]
00C326BC add eax,dword ptr [a6]
00C326BF add eax,dword ptr [a7]
}
00C326C2 pop edi
00C326C3 pop esi
00C326C4 pop ebx
00C326C5 add esp,0CCh
00C326CB cmp ebp,esp
00C326CD call __RTC_CheckEsp (0C2DFAEh)
00C326D2 mov esp,ebp
00C326D4 pop ebp
00C326D5 ret 1Ch
5)参数个数可变的 __thiscall: 从右向左压栈,调用者负责恢复堆栈平衡
printf("__thiscall(variant args): %d\n", objCallMethod.sum_thiscallvarargs(1, 2, 3, 4, 5, 6, 7,-1));
00C3294A push 0FFFFFFFFh
00C3294C push 7
00C3294E push 6
00C32950 push 5
00C32952 push 4
00C32954 push 3
00C32956 push 2
00C32958 push 1
00C3295A lea eax,[objCallMethod] ;细心的读者也许已经看出来了。不错,VS2017上debug版确实是eax,不是ecx,所以要实践
00C3295D push eax ;__thiscall调用居然还把this指针压个栈,这里可以说是个特殊情况
00C3295E call CCallMethod::sum_thiscallvarargs (0C2C1D6h)
00C32963 add esp,24h
00C32966 push eax
00C32967 push offset string "__thiscall(variant args): %d\n" (0CCEE9Ch)
00C3296C call _printf (0C2C3F2h)
00C32971 add esp,8
(2) x64:根据参数字节数,第1个参数送rcx/ecx/cx/cl, 第2个参数送rdx/edx/dx/dl,第3个参数送r8/r8d/r8w/r8b,第4个参数送r9/rd/r9w/r9b, 其余参数从右向左依次从栈的下端向栈的上端送,由于调用时参数是直接送往栈上的,没有了压栈操作,被调者执行ret指令后,不存在堆栈恢复的问题,各个调用约定并无差异
int main()
{
00007FF67FEA79D0 push rbp
00007FF67FEA79D2 push rdi
00007FF67FEA79D3 sub rsp,138h
00007FF67FEA79DA lea rbp,[rsp+50h]
00007FF67FEA79DF mov rdi,rsp
00007FF67FEA79E2 mov ecx,4Eh
00007FF67FEA79E7 mov eax,0CCCCCCCCh
00007FF67FEA79EC rep stos dword ptr [rdi]
00007FF67FEA79EE mov rax,qword ptr [__security_cookie (07FF67FF9D008h)]
00007FF67FEA79F5 xor rax,rbp
00007FF67FEA79F8 mov qword ptr [rbp+0D8h],rax
00007FF67FEA79FF lea rcx,[__41BE8922_funccalltest@cpp (07FF67FFAD027h)]
00007FF67FEA7A06 call __CheckForDebuggerJustMyCode (07FF67FEA1816h)
CCallMethod objCallMethod;
printf("__stdcall: %d\n", objCallMethod.sum_stdcall(1, 2, 3, 4, 5, 6, 7));
00007FF67FEA7A0B mov dword ptr [rsp+38h],7
00007FF67FEA7A13 mov dword ptr [rsp+30h],6
00007FF67FEA7A1B mov dword ptr [rsp+28h],5
00007FF67FEA7A23 mov dword ptr [rsp+20h],4
00007FF67FEA7A2B mov r9d,3
00007FF67FEA7A31 mov r8d,2
00007FF67FEA7A37 mov edx,1
00007FF67FEA7A3C lea rcx,[objCallMethod]
00007FF67FEA7A40 call CCallMethod::sum_stdcall (07FF67FEA38CDh)
00007FF67FEA7A45 mov edx,eax
00007FF67FEA7A47 lea rcx,[string "__stdcall: %d\n" (07FF67FF6E088h)]
00007FF67FEA7A4E call printf (07FF67FEA27DEh)
printf("__cdecl: %d\n", objCallMethod.sum_cdecl(1, 2, 3, 4, 5, 6, 7));
00007FF67FEA7A53 mov dword ptr [rsp+38h],7
00007FF67FEA7A5B mov dword ptr [rsp+30h],6
00007FF67FEA7A63 mov dword ptr [rsp+28h],5
00007FF67FEA7A6B mov dword ptr [rsp+20h],4
printf("__cdecl: %d\n", objCallMethod.sum_cdecl(1, 2, 3, 4, 5, 6, 7));
00007FF67FEA7A73 mov r9d,3
00007FF67FEA7A79 mov r8d,2
00007FF67FEA7A7F mov edx,1
00007FF67FEA7A84 lea rcx,[objCallMethod]
00007FF67FEA7A88 call CCallMethod::sum_cdecl (07FF67FEA2C2Fh)
00007FF67FEA7A8D mov edx,eax
00007FF67FEA7A8F lea rcx,[string "__cdecl: %d\n" (07FF67FF6E0A0h)]
00007FF67FEA7A96 call printf (07FF67FEA27DEh)
printf("__fastcall: %d\n", objCallMethod.sum_fastcall(1, 2, 3, 4, 5, 6, 7));
00007FF67FEA7A9B mov dword ptr [rsp+38h],7
00007FF67FEA7AA3 mov dword ptr [rsp+30h],6
00007FF67FEA7AAB mov dword ptr [rsp+28h],5
00007FF67FEA7AB3 mov dword ptr [rsp+20h],4
00007FF67FEA7ABB mov r9d,3
00007FF67FEA7AC1 mov r8d,2
00007FF67FEA7AC7 mov edx,1
00007FF67FEA7ACC lea rcx,[objCallMethod]
00007FF67FEA7AD0 call CCallMethod::sum_fastcall (07FF67FEA2AD1h)
00007FF67FEA7AD5 mov edx,eax
00007FF67FEA7AD7 lea rcx,[string "__fastcall: %d\n" (07FF67FF6E0B0h)]
00007FF67FEA7ADE call printf (07FF67FEA27DEh)
printf("__thiscall: %d\n", objCallMethod.sum_thiscall(1, 2, 3, 4, 5, 6, 7));
00007FF67FEA7AE3 mov dword ptr [rsp+38h],7
00007FF67FEA7AEB mov dword ptr [rsp+30h],6
00007FF67FEA7AF3 mov dword ptr [rsp+28h],5
00007FF67FEA7AFB mov dword ptr [rsp+20h],4
00007FF67FEA7B03 mov r9d,3
00007FF67FEA7B09 mov r8d,2
00007FF67FEA7B0F mov edx,1
00007FF67FEA7B14 lea rcx,[objCallMethod]
00007FF67FEA7B18 call CCallMethod::sum_thiscall (07FF67FEA12A8h)
00007FF67FEA7B1D mov edx,eax
00007FF67FEA7B1F lea rcx,[string "__thiscall: %d\n" (07FF67FF6E0C8h)]
00007FF67FEA7B26 call printf (07FF67FEA27DEh)
printf("__thiscall(variant args): %d\n", objCallMethod.sum_thiscallvarargs(1, 2, 3, 4, 5, 6, 7,-1));
00007FF67FEA7B2B mov dword ptr [rsp+40h],0FFFFFFFFh
00007FF67FEA7B33 mov dword ptr [rsp+38h],7
00007FF67FEA7B3B mov dword ptr [rsp+30h],6
00007FF67FEA7B43 mov dword ptr [rsp+28h],5
00007FF67FEA7B4B mov dword ptr [rsp+20h],4
00007FF67FEA7B53 mov r9d,3
00007FF67FEA7B59 mov r8d,2
00007FF67FEA7B5F mov edx,1
00007FF67FEA7B64 lea rcx,[objCallMethod]
00007FF67FEA7B68 call CCallMethod::sum_thiscallvarargs (07FF67FEA1B59h)
00007FF67FEA7B6D mov edx,eax
00007FF67FEA7B6F lea rcx,[string "__thiscall(variant args): %d\n" (07FF67FF6E0E0h)]
00007FF67FEA7B76 call printf (07FF67FEA27DEh)
return 0;
00007FF67FEA7B7B xor eax,eax
}
00007FF67FEA7B7D mov edi,eax
00007FF67FEA7B7F lea rcx,[rbp-50h]
00007FF67FEA7B83 lea rdx,[__xt_z+260h (07FF67FF6E060h)]
00007FF67FEA7B8A call _RTC_CheckStackVars (07FF67FEA3DC8h)
00007FF67FEA7B8F mov eax,edi
00007FF67FEA7B91 mov rcx,qword ptr [rbp+0D8h]
00007FF67FEA7B98 xor rcx,rbp
00007FF67FEA7B9B call __security_check_cookie (07FF67FEA1CB2h)
00007FF67FEA7BA0 lea rsp,[rbp+0E8h]
00007FF67FEA7BA7 pop rdi
00007FF67FEA7BA8 pop rbp
00007FF67FEA7BA9 ret
最后于 2020-11-20 09:53
被低调putchar编辑
,原因: 追求严谨!避免误解!