-
[리버싱 핵심원리 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++에서 최적화 옵션을 끄고 빌드한 후, 디버깅해보자.
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); }
똑같이 빌드해보고 디버깅해보자.
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은 좀 더 빠른 함수의 호출이 가능하다. 그러나 레지스터에 중요한 값이 저장되어있는 경우, 백업해야 하는 오버헤드가 발생할 수도 있다.
반응형'Reverse Engineering' 카테고리의 다른 글
[리버싱 핵심원리 study] 13장 PE File Format (1) (0) 2020.12.25 [리버싱 핵심원리 study] 11장 Lena's Reversing for Newbies (0) 2020.12.23 [리버싱 핵심원리 study] 8장 abex' crackme#2 분석(2) (0) 2020.12.03 [리버싱 핵심원리 study] 8장 abex' crackme#2 분석(1) (1) 2020.12.02 [리버싱 핵심원리 study] 7장 Stack Frame (0) 2020.12.01