<리버싱 핵심 원리>로 공부하였다.
10 함수 호출 규약 = Calling Convention
'함수를 호출할 때 파라미터를 어떤 식으로 전달하는가?'에 대한 일종의 약속.
함수 호출 전에 파라미터를 스택(프로세스에서 정의된 메모리 공간)으로 전달. PE 헤더에 크기가 명시돼있음.
=> 프로세스가 실행될 때 스택 메모리의 크기가 결정! (≠ malloc/new 동적 메모리 할당)
함수 실행 완료 시 스택에 남아있는 파라미터는 그대로 놔둔다!
=>값을 지우는데 불필요하게 cpu 자원을 소모한다/저절로 덮어써짐
/스택 메모리는 이미 고정돼있기 때문에 메모리 해제를 할 수도 없고 할 필요도 없다.
함수 실행 완료 시 ESP(스택 포인터)는 어떻게 되나?
=> ESP 값은 함수 호출 전으로 복원돼야 한다. 그래야 참조 가능한 스택의 크기가 줄어들지 않는다.
스택 메모리는 고정된 채 ESP로 스택의 현재 위치를 가리키는데 ESP가 스택의 끝을 가리키면 더 이상 스택 이용 불가능
함수 호출 후에 ESP를 어떻게 정리하는지에 대한 약속 = 함수 호출 규약!
ex>cdecl, stdcall, fastcall
caller : 함수를 호출한 쪽
callee : 호출을 당한 함수
main()에서 printf() 호출하면 caller는 main(), callee는 printf()인 것!
10.1.1. cdecl : 주로 c언어에서 사용. caller에서 스택을 정리하는 특징
401013~40101C : add() 함수의 파라미터 1,2를 역순으로 스택에 입력.
add 함수 호출(401000) add esp,0으로 스택 정리
caller인 main() 함수가 자신이 스택에 입력한 함수 파라미터를 직접 정리하는 방식이 cdecl
10.1.2. stdcall : Win32 API에서 사용, callee에서 스택을 정리하는 특징
40100A : 스택의 정리, RETN 8 명령의 의미는 RETN + POP 8 바이트이다.
리턴 후 지정된 크기 ESP 증가시키는 것!
이렇게 add 함수 내부에서 스택을 정리하는 방식이 stdcall 방식이다.
10.1.3. fastcall
stdcall 방식과 유사하지만, 함수에 전달하는 파라미터 일부를 스택 메모리가 아닌 레지스터를 이용해 전달하는 게 특징
좀 더 빠른 함수 호출 가능(CPU 입장에서는 멀리 있는 메모리보다 CPU와 같이 붙어있는 레지스터에 접근하는게 더 빠름)