워게임을 풀고 공부를 진행했다.
리버싱 문제를 풀다 보니, 리버싱에 필요한 기초 지식이 필요할 것 같아, 이를 간단히 공부하고자 함수 호출 규약을 공부했다.
이는 x64 아키텍처에 관한 호출 규칙에 한정된다.
참고자료: Microsoft x64 호출 규칙
호출 규칙 기본값
기본값: 네 개의 레지스터 빠른 호출 규칙 사용, 공백은 호출 수신자가 해당 레지스터를 저장하는 섀도 저장소로 할당됨.
함수 호출의 인수와 레지스터 사이의 규칙: 8바이트에 맞지 않거나 1, 2, 4, 8바이트가 아닌 인수는 참조로 전달되어야 함.
- 부동 소수점 연산: 16개의 XMM 레지스터 사용
- 부동 소수점 인수: XMM0L, XMM1L, XMM2L, XMM3L
- 정수 인수: RCX, RDX, R8, R9 레지스터 사용
- 16바이트 인수: 참조로 전달
-> 위의 레지스터들과 RAX, R10, R11, XMM4, XMM5는 휘발성.
- 프로토타입화된 함수: 모든 인수가 예상된 호출 수신자 형식으로 변환된 후 전달
- 프로토타입화되지 않은 함수: 모든 부동 소수점 값은 범용 레지스터에서 중복되어야 함(2번째 매개변수로 전달된 1.0의 경우, 예시로 XMM1, RDX에 중복으로 들어감). 처음 4개를 초과하는 매개 변수는 섀도 저장소 뒤의 스택에 저장되어야 함.
호출자가 호출 수신자에 매개 변수 공간을 할당하며, 수신자가 많은 매개 변수를 사용하지 않는 경우에도 4개의 레지스터 매개 변수를 저장할 수 있는 공간을 할당해야 함. -> 프로토타입화되지 않은 C/C++, vararg 함수에 대한 지원을 간소화함.
매개 변수 전달
처음 네 개의 인수를 레지스터 함수에 전달, 나머지 인수는 오른쪽에서 왼쪽 순서로 스택에 전달됨.
호출자가 필요한 스택 공간을 예약, 각 인수에 대해 8바이트 맞춤을 유지하며 인수를 스택 메모리에 씀.
가장 왼쪽 네 개 위치의 정수 값 인수는 왼쪽에서 오른쪽으로 각각 RCX, RDX, R8, R9에 전달됨. 5번째 이상의 인수가 스택에서 전달됨. 레지스터의 모든 정수 인수는 오른쪽으로 정렬되어 필요한 레지스터 부분만 액세스할 수 있음.
- 4개 매개 변수의 부동 소수점/배정밀도 인수: 위치에 따라 XMM0~XMM3에서 전달됨. varags 인수가 있는 경우, RCX, RDX, R8, R9에만 배치됨.
- 배열/문자열/__m128 형식: 포인터가 전달됨. 16바이트 맞춤이어야 함.
- 내장 함수: 다른 휘발성 레지스터를 사용하여 인수를 전달하는 경우도 있음.
| 매개 변수 형식 | 다섯 번째 이상 | 네 번째 | 세 번째 | 두 번째 | 첫 번째 |
| 부동 소수점 | stack | XMM3 | XMM2 | XMM1 | XMM0 |
| 정수 | stack | R9 | R8 | RDX | RCX |
| 집계(8/16/32/64비트), __m64 | stack | R9 | R8 | RDX | RCX |
| 기타 집계, 포인터 | stack | R9 | R8 | RDX | RCX |
| __m128, 포인터 | stack | R9 | R8 | RDX | RCX |
예제
func3(int a, double b, int c, float d, int e, float f);
// a in RCX, b in XMM1, c in R8, d in XMM3, f then e passed on stack
반환 값
- 64비트에 맞출 수 있는 반환 값: RAX를 통해 반환
- 부동 소수점, doubles, 벡터 형식(__m128 등)을 포함한 비칼라 형식: XMM0를 통해 반환
- 사용자 정의 형식: 전역 함수, 정적 멤버 함수 값으로 반환될 수 있음.
-RAX으로 반환하려면 길이가 1/2/4/8/16/32/64비트여야 함. 사용자 정의 생성자, 소멸자, 복사 대입 연산자가 없어야 함. 기본 클래스 또는 가상 함수를 포함할 수 없음.
정렬
대부분의 구조체는 자연 정렬에 맞춰 정렬.
예외: 스택 포인터, malloc, alloca 메모리 -> 항상 16바이트로 정렬 보장됨.
16바이트 이상의 맞춤은 수동으로 정렬을 수행해야 하며, XMM 작업의 일반적인 맞춤 크기가 16바이트이므로 대부분의 코드에서 이 값이 유효함. -> 메모리를 16바이트로 맞춰둬야 한다는 뜻.
되감기 가능성
- 리프 함수: 비휘발성 레지스터를 변경하지 않는 함수
- 비리프 함수: 예시로, 함수를 호출해 비휘발성 RSP를 변경할 수 있는 함수.
-> 예외 처리 시, 비휘발성 레지스터를 복구하기 위해 비리프 함수에 정적 데이터를 이용해 주석이 달림. 이 정적 데이터는 pdata 또는 프로시저 데이터로 저장되며 xdata(예외 처리 데이터)를 참조함.
호출자/호출 수신자 저장 레지스터
- 휘발성: RAX, RCX, RDX, R8, R9, R10, XMM0~XMM5. 또한 YMM0~YMM15, ZMM0~ZMM15 상위 부분도 휘발성.
- 비휘발성: RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15, XMM6~XMM15
'소학회 > 워게임 추가 공부' 카테고리의 다른 글
| [web]Dreamhack_phpreg 추가 공부 (0) | 2026.03.23 |
|---|---|
| [reversing]Dreamhack_simple-operation 추가 공부 (0) | 2026.01.13 |
| [misc]Dreamhack_Exercise: SSH 추가 공부 (0) | 2025.11.04 |
| [pwnable]Dreamhack_baby-bof : pwntools 추가 공부 (0) | 2025.09.30 |
| [web]Dreamhack_session : 자바스크립트 추가 공부 (0) | 2025.09.23 |