Self-Improvement

함수 호출 규약 본문

리버싱 기초

함수 호출 규약

JoGeun 2018. 11. 3. 01:29

함수 호출 규약 종류

32bit

cdecl (함수 호출 종료 후 스택 정리)

stdcall (호출된 함수에서 스택 정리)

fastcall (ECX, EDX 레지스터와 스택 사용)

64bit

fastcall

- 리눅스에서는 EDI, ESI, EDX, ECX, R8, R0 레지스터, 실수는 XMM0 ~ XMM7 레지스터

- 윈도우세너느 ECX, EDX, R8, R9, 실수는 XMM0 ~ XMM4 레지스터

 

Caller(호출자), Callee(피호출자)

ex) main()함수에서 printf()함수를 호출했다면 Caller는 main()이고, Callee는 printf()가 된다.

 

Cdecl

cdecl 방식은 주로 C언어에서 사용되는 방식이며, Caller에서 스택을 정리 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stdio.h"
 
int add(int a, int b)
 
{
 
return (a+b);
 
}
 
 
int main(int argc, char* argv[])
 
{
 
return add(1,2);
 
}
cs

 

------------------디버깅--------------------------

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
00401010 PUSH EBP
 
00401011 MOV EBP, ESP
 
00401013 PUSH 2
 
00401015 PUSH 1
 
00401017 CALL 00401000
 
0040101C ADD ESP, 8
 
0040101F POP EBP
 
00401020 RETN
cs

add() 함수의 파라미터 1,2를 역순으로 스택에 입력하고 add() 함수(401000)을 호출한 후 ADD ESP, 8 명령으로 스택을 정리한다.

즉 Caller인 main() 함수가 자신이 스택에 입력한 함수 파라미터를 직접 정리하는 방식이 cdecl이다.

 

장점 : C언어의 printf() 함수와 같이 가변 길이 파라미터를 전달할 수 있음.

 

Stdcall

stdcall 방식은 Win32 API에서 사용되며 Callee에서 스택을 정리하는 것이 특징 이다.

아래의 예제는 C언어 이지만 _stdcall 키워드를 입력하여 stdcall 방식으로 컴파일을 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stdio.h"
 
int _stdcall add(int a, int b)
 
{
 
return (a+b);
 
}
 
 
int main(int argc, char* argv[])
 
{
 
return add(1,2);
 
}
cs
--------------디버깅------------------

 

1
2
3
4
5
6
7
8
9
10
11
12
13
00401010 PUSH EBP
 
00401011 MOV EBP, ESP
 
00401013 PUSH 2
 
00401015 PUSH 1
 
00401017 CALL 00401000
 
0040101F POP EBP
 
00401020 RETN
cs

main()함수에서 add()함수 호출 후에 스택 정리 코드(ADD ESP, 8)이 생략되는 걸 확인할 수 있다.

스택 정리 코드는 Callee인 add() 함수 내부에 존재하며 이러한 방식이 stdcall 방식이다.

 

장점 : cdecl 방식에 비해 코드 크기가 작아진다. 호환성이 좋다

 

Fastcall

fastcall 방식은 기본적으로 stdcall 방식과 같지만 함수에 전달하는 파라미터 일부(2개까지)를 스태 메모리가 아닌 레지스터를 이용하여 전달하는 것이 특징이다.

예를 들면 어떤 함수의 파라미터가 4개라면, 앞의 두개의 파라미터는 각각 ECX, EDX 파라미터를 이용하여 전달하게 된다.

 

장점 : fastcall 이름 그대로 빠른 함수 호출이 가능하다.

'리버싱 기초' 카테고리의 다른 글

PE 구조 (DOS Stub)  (0) 2018.11.11
PE 구조 (DOS 헤더)  (0) 2018.11.11
MOV vs LEA  (0) 2018.10.28
리버싱 기초 4 (어셈블러 명령어)  (0) 2018.10.23
리버싱 기초 3 (어셈블러 명령어)  (0) 2018.10.23