함수호출규약이란?
함수 호출 및 반환을 일관되고 효율적으로 처리하기 위해 정의한 규칙으로 인수를 전달하고 반환 값을 받는 방식, 레지스터 사용 규칙, 스택의 구성 등을 명시한다.
함수호출규약이 없다면?
프로세스가 종료되면 ESP는 함수 호출 전으로 돌아가고 스택 안에 남은 매개변수들은 지워지지 않고 이후 사용할 때 덮어씌워진다. 그러면 이후 계속 함수를 호출하면 결국 ESP가 스택의 끝에 위치하게 되고 그러면 더 이상 스택을 사용할 수 없으므로 ESP를 정리해야 한다.
환경 | 이름 | 매개변수 레지스터 | 스택정리 |
---|---|---|---|
32bit | cdecl | 스택사용 | Caller |
stdcall | 스택사용 | Callee | |
fastcall | ecx, edx | Callee | |
64bit | System V AMD64 ABI | RDI, RSI, RDX, RCX, R8, R9 (실수일 경우 XMM0 ~ 7) | Caller |
32bit 환경 C언어에서는 일반적으로 cdecl 함수 호출 규약을 사용한다.
매개변수 정리 방법
파라미터가 스택에 저장되면 ESP도 마지막 매개변수를 가르키고 있는데 여기서 ESP에 8을 더한다. 그러면 ESP는 파라미터보다 더 위에 주소를 가키기 때문에 ESP의 아래쪽에 있는 파라미터들은 유효하지 않은 데이터가 된다.
exam
#include <stdio.h>
int func(int a, int b, int c) {
return a+b+c;
}
int main(){
int a = func(3, 4, 5);
}
32bit cdecl을 예제로 살펴보자.
위와 같은 예제 코드가 있다. 어셈블리로 보자.
gcc -m32 -fno-stack-protector -o exam2 exam2.c
func함수전에 5, 4, 3 을 push한다.
ebp+xx 로 값을 가져온다.
그리고 caller 에서 add esp, 0x10으로 매개변수 정리를 해준다.
64bit fastcall로 컴파일 해보자.
edi, esi, edx 순서로 레지스터를 이용해서 인자전달을 하는것을 볼 수 있다.
return 값을 eax에 저장한다.
'포너블 > Stack' 카테고리의 다른 글
BoF, Shellcode, Nx bit (1) | 2023.10.23 |
---|---|
핸드레이 (0) | 2023.10.17 |
스택 프레임 (0) | 2023.10.17 |
메모리 구조 (0) | 2023.10.14 |
K0n9의 heap부터 시작하는 줄 알았으나 stack을 시작해버린 이야기 (0) | 2023.10.14 |