01 함수의 기본 구조
1 2 3 4 5 | int sum(int a, int b) { int c = a + b; return c; } | cs |
↓ ↓ ↓ ↓
(retn이 이상한건 기분 탓)
push ebp를 해주면 main 을 가르키던 main ebp를 retn 위로 쌓아주고.
mov ebp를 해주면 그 위에 새로운 ebp가 생기면서 새로운 스택 프레임이 생깁니다.
(esp는 계속해서 따라 올라갑니다.)
[ebp+arg_0], [ebp+arg_4]는 하나의 심볼이다.
얘들의 의미는
[ebp+arg_0] = ebp로 부터 4바이트 떨어진 곳 (ebp + 8) (= a)
[ebp+arg_4] = ebp로 부터 8바이트 떨어진 곳 (ebp + 12) (= b)
a가 3, b가 4라고 하면
mov eax에서 eax가 3이 되고,
add eax에서 eax가 4와 더해져서 7이 된다.
mov [ebp+var_4], eax는 eax에 있던 7을 var_4에 옮겨준뒤,
var_4에 있는걸 다시 mov eax에서 eax로 7이라는 숫자를 저장해줍니다.
2번 연산을 하는 이유는 중간에 지역변수에 저장했기 때문입니다.
mov esp, ebp
pop ebp
retn
이 부분은 main 함수로 돌아오면 이때까지 쌓은 스택들은 필요가 없기 때문에
삭제를 해줘야 합니다. mov esp, ebp로 ebp와 esp를 돌려주고,
pop을 해주면 스택 데이터를 ebp에 넣어줍니다.
이 부분을 함수 호출 규약이라고 합니다.
02 함수 호출 규약 - 1) cdecl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // C 코드 int __cdecl sum(int a, int b) { int c = a + b; return c; } int main(int argc, char* argv[]) { sum(1,2); return 0; } // 어셈블리 코드 sum: push ebp mov ebp, esp push ecx mov eax, [ebp+arg_0] add eax, [ebp+arg_4] mov [ebp+var_4], eax mov eax, [ebp+var_4] mov esp, ebp pop ebp retn main: push 2 push 1 call calling.00401000 add esp, 8 | cs |
28번째 코드 ~ 31번째 코드를 보시면
call 함수에서 두개의 파라미터( 28, 29번째 코드)을 가져다가 사용하며,
cdecl 규약을 사용해서 마지막에 스택을 정리한다. 라고 해석하면 된다.
- 02 함수의 호출 규약 - 2) stdcall [1/2]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // C 코드 int __stdcall sum(int a, int b) { int c = a + b; return c; } // 어셈블리 코드 sum: push ebp mov ebp, esp push ecx mov eax, [ebp+arg_0] add eax, [ebp+arg_4] mov [ebp+var_4], eax mov eax, [ebp+var_4] mov esp, ebp pop ebp retn 8 main: push 2 push 1 call calling.00401000 | cs |
19번째 코드의 retn 8은
"내가 파라미터를 총 8바이트 만큼 사용했어"라는 뜻입니다.
retn 8을 하는 순간에 밑에있는 스택 8바이트가 삭제됩니다.
그래서 call 밑에는 스택을 정리하는 코드가 없습니다.
- 02 함수 호출 규약 - 3) fastcall [2/2]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // C 코드 int __fastcall sum(int a, int b) { int c = a + b; return c; } // 어셈블리 코드 sum: push ebp mov ebp, esp sub esp, 0Ch mov [ebp+var_C], edx mov [ebp+var_8], ecx mov eax, [ebp+var_8] add eax, [ebp+var_C] mov [ebp+var_4], eax mov eax, [ebp+var_4] mov esp, ebp pop ebp retn main: push ebp mov ebp, esp mov edx, 2 mov ecx, 1 call calling.00401000 xor eax, eax pop dbp retn | cs |
- 2. 함수의 호출 규약 - 4) thiscall [2/2]
파라미터 |
주소 |
a |
ecx+x |
b |
ecx+y |
c |
ecx+z |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // C++ 코드 Class CTemp { public: int MemberFunc(int a, int b); }; // 어셈블리 코드 mov eax, dword ptr [ebp-14h] push eax mov edx, dword ptr [ebp-10h] push edx lea ecx, [ebp-4] call 402000 | cs |
5번째 코드가 ecx에 어떤 값을 전달하는 부분입니다.
하나의 변수만으로 다양한 데이터를 넘길 수 있습니다.
'악성코드 분석' 카테고리의 다른 글
[리버싱] crackme0x00a WRITE UP (0) | 2018.10.27 |
---|---|
리버싱 기초 - Lena 듀토리얼 01번 풀이 (0) | 2018.09.01 |
1.5 리버싱 기초 - C 문법과 어셈블리어 (2) | 2018.08.25 |
1. 리버싱 기초 (2) | 2018.08.19 |