리버싱 엔지니어링/리버싱 핵심 원리
10 함수 호출 규약 (Calling Convention)
흰싸라기
2022. 3. 17. 00:13
함수를 호출할 때 파라미터를 어떤 식으로 전달하는가에 대한 일종의 약속
- 스택에 저장된 값은 임시로 사용하는 값, 값을 지우거나 하면 불필요하게 CPU 자원을 소모하는 것
- 다른 값을 입력할 때 자동으로 덮어씀
- 스택 메모리는 이미 고정되어있기 때문에 메모리를 해제할 수 없음
- 스택 메모리는 고정되어 있고 ESP로 스택의 현재 위치를 가리킴
- 함수 호출 후 ESP는 함수 호출 전으로 복원되어야 함
- 함수 호출 후에 ESP를 어떻게 정리하는지 : 함수 호출 규약
- 주요 함수 호출 규약
- cdecl
- stdcall
- fastcall
- caller(호출자) : 함수를 호출한 쪽
- callee(피호출자) : 호출을 당한 함수
10.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);
}

- 401013~40101C 주소 영역
- add() 함수 파라미터 1, 2를 역순으로 스택에 입력
- add() 함수 후 ADD ESP, 8 명령으로 스택을 정리
- cdecl : Caller인 main() 함수가 자신이 스택에 입력한 함수 파라미터를 직접 정리하는 방식
10.2 stdcall
- Win32 API에서 사용되며, Callee(피호출자)에서 스택을 정리함
#include "stdio.h"
int _stdcall add(int a, int b)
{
return (a + b);
}
int main(int argc, char* argv[])
{
return add(1, 2);
}
- stdcall 방식으로 컴파일 : ‘_stdcall’ 키워드 추가

- main() 함수에서 함수 호출 후 스택 정리코드(ADD ESP,8) 생략
- 스택 정리 : add()함수의 마지막(40100A) RETN 8
- RETN 8 : RETN + POP 8바이트
- Callee 내부에 스택 정리 코드가 존재하므로 cdecl 방식에 비해 코드 크기가 작아짐
- stdcall : Callee인 함수 내부에서 스택을 정리하는 방식
- Win32 API는 API를 직접 호출할 때 호환성을 좋게 하기 위한 것
10.3 fastcall
- 기본적으로 stdcall 방식과 같지만, 함수에 전달하는 파라미터 일부를 스택 메모리가 아닌 레지스터를 이용하여 전달
- 장점 : 빠른 함수 호출 가능
- CPU 입장에서 멀리 있는 메모리보다 CPU에 같이 붙어있는 레지스터에 접근하는 것이 빠르기때문