其实看雪的书中已经提到这个问题了,只不过少了thiscall和fastcall,而thiscall是VC++类成员默认的函数调用方式、fastcall是C++Builder默认的调用方式,所以我在这里做一个补充,方便大家查阅。
例子:
假设我们的函数为:
int sumExample (int a, int b)
{
return a + b;
}
调用代码为: int c = sum (2, 3);
现在分别来看几种不同的调用方式,调用者汇编代码和函数体汇编代码:
(1)_cdecl (C语言的调用方式) ---------------
调用者代码>>>:
; // push arguments to the stack, from right to left
push 3
push 2
; // call the function
call _sumExample
; // cleanup the stack by adding the size of the arguments to ESP register
add esp,8
; // copy the return value from EAX to a local variable (int c)
mov dword ptr [c],eax
函数体代码>>>:
; // function prolog
push ebp
mov ebp,esp
sub esp,0C0h
push ebx
push esi
push edi
lea edi,[ebp-0C0h]
mov ecx,30h
mov eax,0CCCCCCCCh
rep stos dword ptr [edi]
; //return a + b;
mov eax,dword ptr [a]
add eax,dword ptr [b]
; // function epilog
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
(2)__stdcall (Windows API 的调用方式)
-----------------------
调用者代码>>>:
; // push arguments to the stack, from right to left
push 3
push 2
; // call the function
call _sumExample@8
; // copy the return value
from EAX to a local variable (int c)
mov dword ptr [c],eax
函数体代码>>>:
; // function prolog goes here (the same code as in the __cdecl example)
; //return a + b;
mov eax,dword ptr [a]
add eax,dword ptr [b]
; // function epilog goes here (the same code as in the __cdecl example)
; // cleanup the stack and
return
ret 8
(3)__fastcall(寄存器调用方式) -----------------------
调用者代码>>>:
; // put the arguments in the registers EDX and ECX
mov edx,3
mov ecx,2
; // call the function
call @fastcallSum@8
; // copy the return value from EAX to a local variable (int c)
mov dword ptr [c],eax
函数体代码>>>:
; // function prolog
push
ebp
mov ebp,esp
sub esp,0D8h
push ebx
push esi
push edi
push ecx
lea edi,[ebp-0D8h]
mov ecx,36h
mov eax,0CCCCCCCCh
rep stos dword ptr [edi]
pop ecx
mov dword ptr [ebp-14h],edx
mov dword ptr [ebp-8],ecx
; // return a + b;
mov eax,dword ptr [a]
add eax,dword ptr [b]
;// function epilog
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
(4)thiscall(C++类成员函数调用方式) -----------------------
这个比较特殊,函数是某个类的成员,所以我们这样定义:
class CSum //类定义
{
int sum ( int a, int b) {return a+b;}
};
调用者代码>>>:
push 3
push 2
lea ecx,[sumObj]
call ?sum@CSum@@QAEHHH@Z; CSum::sum
mov dword ptr [s4],eax
函数体代码>>>:
push ebp
mov ebp,esp
sub esp,0CCh
push ebx
push esi
push edi
push ecx
lea edi,[ebp-0CCh]
mov ecx,33h
mov eax,0CCCCCCCCh
rep stos dword ptr [edi]
pop ecx
mov dword ptr [ebp-8],ecx
mov eax,dword ptr [a]
add eax,dword ptr [b]
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret 8
总结: 这4种call基本上是C++程序(Visual C++ ,C++Builder)最常见的调用方式,熟练掌握这几种call的调用者与函数体的汇编代码格式有助于更快分析算法,写注册机。所以我简单列举在这里,不足的地方还请大家补充,错误的地方还请批评指正!
WinHack QQ: 85436 于2003-07-24
属于:CCG,OCN,FCG,YCG,转载请保持完整