ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [리버싱 핵심원리 study] 10장 함수 호출 규약
    Reverse Engineering 2020. 12. 4. 19:47

    함수 호출 규약(Calling Convention)은 함수를 호출할 때 어떤 방식으로 argument를 전달할지, 함수가 끝난 후 어떤 방식으로 ESP(스택 포인터)를 정리하는지에 대한 약속이다. 대표적으로 cdecl, stdcall, fastcall 등이 있다. Ollydbg로 예제 프로그램의 어셈블리 코드를 살펴보면서 각 방식의 특징을 살펴보겠다.

     

    1. cdecl

    주로 C언어에서 사용되는 방식이며, 'Caller'에서 스택을 정리하는 특징을 보인다.

    #include "stdio.h"
    
    int add(int a, int b)
    {
    	return a+b;
    }
    
    int main(int argc, char* argv[])
    {
    	return add(1, 2);
    }

    위와 같은 코드를 VC++에서 최적화 옵션을 끄고 빌드한 후, 디버깅해보자.

     

    main함수와 add함수

    00401010은 main함수, 00401000은 add 함수를 나타낸다. 여기서 CALL 00401000이 수행된 직후에 ADD ESP, 8 연산을 통해 스택을 정리하는 것을 확인할 수 있다. 이와 같이 Caller에서 자신이 스택에 넘긴 argument를 직접 정리하는 방식이 cdecl이다.

     

     

    2. stdcall

    stdcall 방식은 Win32 API에서 사용되며, 'Callee'에서 스택을 정리하는 것이 특징이다. C언어는 기본적으로 cdecl 방식을 사용하며, stdcall 방식을 이용하기 위해서는 _stdcall 키워드를 함수 이름 앞에 붙여주면 된다.

     

    #include "stdio.h"
    
    int _stdcall add(int a, int b)
    {
    	return a+b;
    }
    
    int main(int argc, char* argv[])
    {
    	return add(1, 2);
    }

    똑같이 빌드해보고 디버깅해보자.

     

    main 함수와 add함수

    cdecl과 비교했을 때 다른점은 함수 호출 직후 따로 ADD ESP, 8이 없으며, add 함수 내부에서 RETN 대신 RETN 8로 보트가 바뀌었다. RETN 8이란 RETN + POP 8과 같은 의미로, 리턴 후 지정된 크기만큼 ESP를 증가시킨다. stdcall 방식의 장점은 함수를 호출할 때마다 ADD ESP, XXX와 같은 명령어가 필요 없어 코드 size가 줄어든다. 

     

     

    3. fastcall

    fastcall은 기본적으로 stdcall과 같지만 함수에 argument를 전달할 때 일부(2개까지)를 레지스터를 이용하여 전달한다. 예를 들어 argument가 4개인 경우, ecx, edx 레지스터를 이용하여 앞의 두 argument를 전달한다. 따라서 fastcall은 좀 더 빠른 함수의 호출이 가능하다. 그러나 레지스터에 중요한 값이 저장되어있는 경우, 백업해야 하는 오버헤드가 발생할 수도 있다.

    반응형

    댓글

Designed by Tistory.