최신목록

2015년 9월 3일 목요일

[리버싱]콜링 컨벤션

함수 호출시 caller(호출자:main)와 callee(피호출자:sum)간의 파라미터 전달 방법및 스택 정리 담당자에 대한 규약을 콜링 컨벤션(함수 호출 규약)이라고 한다. 주로 사용되는 규약에는 세가지 정도가 있다. __cdecl, __stdcall, __fastcall에 대해 정리한다.
예제는 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

댓글 없음:

댓글 쓰기