1.함수의 호출
함수를 호출할때 어떻게 스택에 어떻게 PUSH하고 어떻게 POP할까?
함수 호출은 크게 다음과 같이 나뉘어 진다.
이때 2번 과정을 프롤로그(prolog) 라고 부르며, 4번 과정을 에필로그(epilog) 라고 부른다. 보면 알겠지만 스택프레임의 설정과 복원과 관계가 있다.
그렇다면 함수 프롤로그와 에필로그가 어떤식으로 될까?
(by 어셈블리어)
2.함수 프롤로그 & 에필로그
함수의 프롤로그와 에필로그는 함수호출 규약에 따라 조금씩 다르다.
대표적으로 cdecl 을 보면 다음과 같다.
-cdecl
특징
- 스택에 파라메터 삽입 순서 : right → left
- 스택의 정리를 호출한 함수(caller)에서 수행한다. 따라서 가변인자를 사용할 수 있다.
- Name Mangling : 함수 이름 앞에 _ 추가
ex) _Foo - C / C++ 언어의 기본 함수 호출규약
int main() { foo(); /* foo 함수 호출 call foo (128102Dh) add esp, 8 ; (6) <<스택을 정리하는 부분>> */ return 0; }
int __cdecl foo( int a, int b ) { /* caller 의 ebp 를 저장하고 callee (foo) 의 ebp 를 확보 push ebp mov ebp, esp push ecx ; local 변수 c 의 자리 확보 */
int c;
- caller 의 ebp 를 저장하고 callee 의 ebp 를 새로 확보한다. 이 새로운 ebp 를 이용하여 foo 함수 내에서 파라메터 및 local 변수로의 접근을 시도할 것이다. 그리고 local 변수에 사용할 스택을 할당하는데 여기서는 4바이트 변수 하나이므로 단순히 ecx 를 push 함으로써 이를 수행한다. 하지만 local 변수들이 8바이트 (혹은 그 이상) 일 경우 “sub esp, 8” 과 같이 스택을 할당하게 된다.
} /* foo 함수 종료 후 caller 의 ebp, esp 복구 mov esp, ebp pop ebp ret */
- caller 의 ebp 를 저장하고 callee 의 ebp 를 새로 확보한다. 이 새로운 ebp 를 이용하여 foo 함수 내에서 파라메터 및 local 변수로의 접근을 시도할 것이다. 그리고 local 변수에 사용할 스택을 할당하는데 여기서는 4바이트 변수 하나이므로 단순히 ecx 를 push 함으로써 이를 수행한다. 하지만 local 변수들이 8바이트 (혹은 그 이상) 일 경우 “sub esp, 8” 과 같이 스택을 할당하게 된다.
함수 프롤로그
/* caller 의 ebp 를 저장하고 callee (foo) 의 ebp 를 확보 push ebp mov ebp, esp push ecx ; local 변수 c 의 자리 확보 */
베이스포인터(ebp)를 스택에 저장하고 현재 스택포인터(esp)를 베이스포인터(ebp)에다가 저장함.
함수 에필로그
} /* foo 함수 종료 후 caller 의 ebp, esp 복구 mov esp, ebp pop ebp ret */
현재 스택 포인터(esp)를 베이스포인터(ebp)로 복구한 후 베이스 포인터(ebp)를 복구해주고 ret를 통해 다음에 가야에 adress로 점프한다.
참고 : hhttp://z3moon.com/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%ED%98%B8%EC%B6%9C%EA%B7%9C%EC%95%BD
'리버싱(Reversing) > 보고서' 카테고리의 다른 글
리눅스 :: Linux 환경의 메모리 보호 기법 (0) | 2015.08.27 |
---|---|
리버싱 :: 64bit 에서 인자를 어떻게 전달할까? (0) | 2015.06.17 |
리버싱 :: 메모리 구조 , 스택프레임 , 함수 호출규약 (0) | 2015.06.08 |
리버싱 :: 어셈블리어 기초 , 범용 레지스터 (0) | 2015.06.08 |
리버싱 :: 디버거를 실행해보자! (0) | 2015.06.06 |
WRITTEN BY