예제는 Visual Studio와 OllyDbg를 사용하여 분석하였다.
간단히 정리하면 아래와 같다.
__cdecl
|
__stdcall
|
__fastcall
|
|
파라미터 전달 방법
|
스택
|
스택
|
스택, 레지스터
|
스택 정리 담당
|
caller
|
callee
|
Callee(래지스터만사용시불필요)
|
1. __cdecl(C declaration)
C 및 C++ 프로그램의 기본 호출 규칙으로 Visual Studio 프로젝트 생성하면 디폴트로 __cdecl로 되어있다. main에서 sum 함수를 호출할때 push로 파라미터를 stack에 저장하고 call 한 후 다시 Add ESP, 8을 하여 사용했던 stack을 반환하는것을 볼 수 있다. operator new, delete등 C, C++ 함수는 함수 포인터 얻을때 typedef 시 호출규약을 __cdecl로 정의해주어야 한다.
2. __stdcall
Win32 API 함수를 호출하는데 사용된다. WINAPI로 재정의 되있다. 그러므로 callback 함수등 정의시 함수 앞에 WINAPI라고 호출규약을 명시해주어야 한다. sum함수 앞에 명시적으로 __stdcall을 써서 호출규약을 정해주었다. OllyDbg로 해당 바이너리를 열어서 보면 __cdecl과 다르게 main에서 스택을 이용해서 파라미터를 전달하고 있으나 sum함수 콜 한 후 esp를 정리하는 부분이 없다. 대신 sum 함수에 보면 마지막에 retn 8을 하는데 이는 pop 8하여 stack을 정리하고 return 하는 역할을 한다.
3. __fastcall
64bit 시스템에서는 기본으로 레지스터를 이용해서 파라미터를 전달하는데 32bit 시스템에서는 __fastcall이라는 호출규약을 통해서 레지스터를 이용하게 강제할 수 있다. 레지스터를 이용함으로써 좀 더 빠른 함수 호출이 가능하다. 스택을 사용하지 않았기때문에 스택을 정리할 필요도 없겠지요. 만약 파라미터가 많아서 레지스터가 모자라다고 하면 그때 스택을 이용하게 되고 그 후 정리는 __stdcall과 같이 callee쪽에서 하게 됩니다.
4. __thiscall
클래스의 멤버함수에서만 사용되는 호출규약으로 클래스 포인터를 스택이 아닌 ecx를 통해 넘기겠다는 규약이다. __stdcall과 유사하나 클래스 포인터가 스택이 아닌 ecx를 통해 전달된다.
호출규약이 서로 맞게 되있는지 확인하기 위해선 VS 옵션인 C/C++>코드생성>기본 런타임 검사 를 실시한다. 만약 호출규약이 서로 맞지 않으면 RTC_CheckEsp에서 에러를 리턴하여 확인할 수 있다.
이번에는 32bit 프로세스를 분석하였는데 64bit에서는 어떤지 궁금하네요
64비트에서는 여전히 __stdcall과 __cdecl을 사용한다고 하나 실제 파라미터 전달방식을 보면 __fastcall과 같은데...뭔가 다른게 있는지는 확인되면 업데이트 해야겠네요. 또한 호출규약이 서로 맞지 않아도 RTC_CheckEsp에서 잡지 못하더군요...64비트에서는 RTC_CheckRsp일라나...또한 확인후...^^;
다음에~ to be continume
댓글 없음:
댓글 쓰기