본문 바로가기
해킹 맛보기

리버싱 스터디2

by paysmile 2016. 10. 11.

3.6 함수 리버싱

3.6.1 콜링 컨벤션

콜링 컨벤션이란?

함수가 어떻게 인자를 전달받고 자신을 호출한 함수에게 리턴값을 어떻게 다시 돌려주는지 에 대한 약속된 함수 호출 규약이다.

< 호출 규약 >

- __cdecl

인자 전달 방법: 스택,

스택 해제 방법: 호출한 함수

sum() 함수의 호출 규약을 __cdecl로 정의

 

<!--[if !vml]--><!--[endif]-->

push 명령어를 이용해 높은 주소에서 낮은 주소로 데이터를 스택에 쌓아갑니다.

__cdecl 호출 규약은 호출한 함수에서 스택을 해제 하기 때문에 호출된 함수에서는 스택 해제에 대해 신경을 쓰지 않습니다.

<!--[if !supportEmptyParas]--> <!--[endif]-->



- __stdcall

인자전달방법: 스택

스택 해제 방법: 호출된 함수

sum()함수의 호출 규약을 __stdcall 호출규약으로 정의한 것


__stdcall의 인자입력도 __cdecl 호출 규약과 같이 스택으로 입력하는 것을 확인할 수 있다.

<!--[if !supportEmptyParas]--> <!--[endif]-->

<!--[if !supportEmptyParas]--> <!--[endif]-->

- __fastcall

인자전달방법: 레지스터, 스택

스택해제방법: 호출된 함수

sum() 함수의 호출 규약을 __fastcall 호출 규약으로 정의 한 것


__fastcall 호출 규약은 인자입력에 메모리보다 속도가 빠른 레지스터가 사용됩니다. 그런데 레지스터 사용에는 한계가 있어 모든 인자를 레지스터로 입력하지 않고 메모리(스택)도 같이 사용합니다.

__fastcall 인자에 사용된 스택 해제는 __stdcall 호출 규약과 같이 호출된 함수에서 합니다.

<!--[if !supportEmptyParas]--> <!--[endif]-->

<!--[if !supportEmptyParas]--> <!--[endif]-->

<!--[if !supportEmptyParas]--> <!--[endif]-->

<!--[if !supportEmptyParas]--> <!--[endif]-->

<!--[if !supportEmptyParas]--> <!--[endif]-->

<!--[if !supportEmptyParas]--> <!--[endif]-->

3.6.2 함수 호출 리턴값 확인

 

<!--[if !vml]--><!--[endif]-->

위에서 보듯 모든 함수의 리턴값을 EAX레지스터를 사용해 전달합니다.

<!--[if !supportEmptyParas]--> <!--[endif]-->

<!--[if !supportEmptyParas]--> <!--[endif]-->




3.6.4 함수 프롤로그, 에필로그

프롤로그 = 스택과 레지스터를 재구성 합니다. (노랑색)

에필로그 = 함수 종료 시 스택과 레지스터를 정리합니다. (파랑색)


 

<프롤로그>


main() 함수의 프롤로그 PUSH EBP를 실행했을 때 스택 구조


함수의 프롤로그 MOV EBP, ESP를 실행 했을 때 스택구조


0x010513D3 SUB ESP, 0C0 명령어는 지역변수를 사용하기 위해 ESP를 아래로 이동시킨다. 명령어 실행 후 스택구조는 위와 같다.

0x010513F0에서 printf() 함수를 호출하기 위해 1개의 인자를 입력합니다.

PUSH 1055858 명령어를 실행한 후의 스택 구조이다.


0x010513F5 CALL DWORD PTR DS : [10592BC] 명령어는 printf() 함수를 호출하는 명 령어입니다. 명령어를 실행 후 스택구조는 위와 같습니다. 함수를 계속 호출하게 되면 스택 구조는 이전 함수의 지역변수, 리턴주소, 인자, 이전 EBP값을 그림 3-36과 같은 형태로 계 속 저장해서 관리 합니다.


0x010513F5 CALL DWORD PTR DS : [10592BC] 명령어는 printf() 함수를 호출하는 명 령어입니다. 명령어를 실행 후 스택구조는 위와 같습니다. 함수를 계속 호출하게 되면 스택 구조는 이전 함수의 지역변수, 리턴주소, 인자, 이전 EBP값을 그림 3-36과 같은 형태로 계 속 저장해서 관리 합니다.


printf() 함수를 실행하고 리턴하기 위해 에필로그 MOV ESP, EBP 명령어를 실행하면 위와 같은 스택 구조가 됩니다.


<에필로그>

에필로그 MOV ESP, EBP 명령어를 실행 한 후, 다음 에필로그 명령어인 POP EBP 명령어를 실행한 스택구조는 위와 같습니다. EBP는 다시 main() 함수의 EBP 주소를 가지고 ESP는 리턴 주소를 저장한 스택 주소를 가리킵니다.


에필로그의 마지막인 리턴 주소로 되돌아 가는 명령어 RETNESP가 가리키는 스택에 저장된 주소를 EIP 레지스터에 저장해 리턴 주소의 명령어를 실행합니다. RETN 명령어를 실행한 후의 스택 구조는 위와 같습니다.

'해킹 맛보기' 카테고리의 다른 글

메모리 오염 공격  (0) 2016.12.26
명령어 삽입공격&레이스 컨디션  (0) 2016.11.22
웹 해킹  (0) 2016.11.01
리버싱 스터디3  (0) 2016.10.11
엔지니어링 스터디1  (0) 2016.10.11