함수 호출 규약에는 여러 가지 방식이 있다.

대표적인 것이 아래의 네 가지.

1. __cdecl

2. __stdcall

3. __fastcall

4. __thiscall


__cdecl 방식

int __cdecl sum(int a, int b){

int c = a + b;

return c;

}

int main(int argc, char* argv[]){

sum(1,2);

return 0;

}


sum:

push    ebp

mov    ebp, esp

push    ecx

mov    eax, [ebp + arg_0]

add    eax, [ebp + arg_4]

mov    [ebp + var_4], eax

mov    eax, [ebp + var_4]

mov    esp, ebp

pop     ebp

retn


main:

push 2

push 1

call calling.00401000

add esp, 8

1. call calling.00401000 밑에 add esp, 8을 한다. 즉, 함수를 호출한 곳에서 스택을 보정해준다.

2. 스택을 보정해주는 부분을 보고 함수의 파라미터 개수를 알 수 있다.

(예시 같은 경우는 파라미터 2개)



__stdcall 방식

int __stdcall sum(int a, int b){

int c = a + b;

return c;

}


sum:

push    ebp

mov    ebp, esp

push    ecx

mov    eax, [ebp + arg_0]

add    eax, [ebp + arg_4]

mov    [ebp + var_4], eax

mov    eax, [ebp + var_4]

mov    esp, ebp

pop    ebp

retn    8


main:

push    2

push    1

call    calling.00401000

1. 그냥 retn이 아닌 retn 8을 이용해 스택보정이 함수 내부에서 이루어진다.

즉, 파라미터의 개수도 함수 내부를 봐야 알 수 있다.

* retn이 보이고 retn 10 과 같은 별도의 숫자가 보이지 않는 상태에서 call 후에 add esp, x도 보이지 않는다면 그 함수는 __stdcall 방식이자 파라미터가 없는 경우!



__fastcall 방식

int __fastcall sum(int a, int b){

int c = a + b;

return c;

}


sum:

push    ebp

mov    ebp, esp

sub    esp, 0Ch

mov    [ebp + var_C], edx

mov    [ebp + var_8], ecx

mov    eax, [ebp + var_8]

add    eax, [ebp + var_C]

mov    [ebp + var_4], eax

mov    eax, [ebp + var_4]

mov    esp, ebp

pop    ebp

retn


main:

push    ebp

mov    ebp, esp

mov    edx, 2

mov    ecx, 1

call    sub_401000

xor    eax, eax

pop    ebp

retn

1. sub esp, 0Ch로 스택 공간을 확보한다.

2. 함수의 파라미터가 2개 이하일 경우, 인자를 push 하지 않고 ecxedx 레지스터를 이용한다.



__thiscall 방식

Class CTemp{
public:

int MemberFunc(int a, int b);

};


mov     eax, dword ptr [ebp - 14h]

push    eax

mov    edx, dword ptr [ebp - 10h]

push    edx

lea    ecx, [ebp - 4]

call    402000

__thiscall 방식은 주로 C++의 클래스에서 이용되는 방법이다.

현재 객체의 포인터를 ecx에 전달한다.

해당 클래스에서 사용하고 있는 멤버 변수나 각종 값은 아래와 같이 ecx 포인터에 오프셋 몇 번지를 더하는 식으로 사용할 수 있다.

ecx + x

ecx + y

ecx + z

* 인자 전달 방법이나 스택 처리 방법은 __stdcall과 동일하다.



+ Recent posts