본문 바로가기

정보보안/리버싱

reverse _assembly 스택프레임 **다시 공부하고 쓰기

12_어셈블리(스택 프레임)

 

 - 분석 환경 : WindowsXP(32bit)

 - 분석 도구 : OllyDbg, VS2008

 

1. 스택 프레임

 

 - 스택 프레임은 EBP 레지스터를 사용하여 스택 내의 지역 변수, 함수 인자값, 리턴 주소에 접근하는 기법이다.

 - 스택에는 지역 변수, 함수 인자값, 리턴 주소들이 저장된다.

 - 스택 프레임은 함수가 호출될 때 생성되고, 함수 처리 완료되면 자동으로 소멸된다.

 

2. 스택 프레임 이해

 

 1) VS 2008을 이용하여 'stack.exe' 파일을 제작한다.

 

 - 파일 -> 새로 만들기 -> 프로젝트 -> 빈 프로젝트 -> 위치(04_테스트) & 이름(StackFrame) -> 확인

 - '소스 파일' 우클릭 -> 추가 -> 새 항목 -> 'C++ 파일(.cpp)' 선택 -> 이름(StackFrame) -> 추가

 

 

#include <stdio.h>

 

int add(int a, int b)

{

           int x = a , y = b;

           return (x + y);

}

 

 

int main(int argc, char* argv[])

{

           int a = 6 , b = 2;

           printf("%d\n", add(a, b));

           return 0;

}

 - 파일 -> 모두 저장 -> 닫기

 

 

 2) 'cl' 명령어를 이용한 최적화 컴파일 실시

 

 

 

 

C:\리버싱\04_테스트\stack\stack>dir

 

3. 올리디버거를 이용한 'stack.exe' 분석

 

 - 메모리 주소, 레지스터 저장 값, 스택 내용, 메모리 덤프 내용 확인

 

< main함수 >

 

1)    main 함수 찾기(F8) à 00401020

2)    main함수 진입(F7) 후 BreakPoint (F2) 지정 ( main함수 프롤로그, 함수 본체, 함수 에필로그 확인 )

3)    add 함수 찾기(F8) -> 00401000

main함수에 진입한 모습, add함수(00401000)를 call하고 있다.

 

< add 함수 >

1)    add 함수 진입(F7) 후 BreakPoint (F2) 지정 ( add 함수 프롤로그, 함수 본체, 함수 에필로그 확인 )

________________________________________________________________________________________

 

Main함수 호출 전의 모습은 다음과 같다.

 

PUSH명령을 통해 파라미터 두개를 스택에 넣고 CALL로 함수를 부르고있다.

 

Main함수 호출 이후 다음 명령어의 주소는 00401241이고, 이 주소는 Main함수가 호출된 이후 다음 주소를 나타낸다.

Main함수를 호출함과 동시에 아래와 같이 스택에 리턴주소가 저장된 것을 확인할 수 있다.

 

<Main함수 분석>

00401020      /$  55            PUSH EBP      ebp레지스터의 값을 스택에 저장한다.

00401021      |.  8BEC          MOV EBP,ESP  EBP의 값을 ESP의 값과 동일하게 만들어주었다.

00401023      |.  83EC 08       SUB ESP,8       // 지역변수용 스택 공간 할당( 4byte * 2 )

00401026      |.  C745 FC 06000>MOV DWORD PTR SS:[EBP-4],6

0040102D      |.  C745 F8 02000>MOV DWORD PTR SS:[EBP-8],2

지역변수 6과 2를 초기화하는 과정을 나타낸다.

 

00401034      |.  8B45 F8       MOV EAX,DWORD PTR SS:[EBP-8]

00401037      |.  50            PUSH EAX                                 ; /Arg2

add함수에 넘겨줄 인자들을 EAX로 넘겨준 뒤 이를 PUSH하는 과정이다. 이때, 인자는 코드의 오른쪽부터 전달되므로, 2 ->6 순서로 PUSH하게된다.

 

00401038      |.  8B4D FC       MOV ECX,DWORD PTR SS:[EBP-4]             ; |

0040103B      |.  51            PUSH ECX                                 ; |Arg1

 

0040103C      |.  E8 BFFFFFFF   CALL stackFra.00401000                   ; \stackFra.00401000

그 후, Main함수는 add함수를 호출한다. add함수를 Call하니 스택에 리턴주소가 입력된 것을 확인할 수 있다.

Add함수에 F7을 눌러 진입하였다.

 

<add함수>

코드를 한줄씩 분석해보자.

 

<함수 프롤로그> 

00401000      /$  55            PUSH EBP

00401001      |.  8BEC          MOV EBP,ESP 

위의 Main함수와 마찬가지로, EBP를 PUSH하고, EBP의 값을 ESP와 같게 맞추어 주는 함수 프롤로그의 과정을 확인할 수 있다.

 

<함수 본체>

00401003      |.  83EC 08       SUB ESP,8

지역변수 x,y 에 해당하는 공간을 만들기 위해 ESP의 값을 8byte만큼 늘려준 것을 확인할 수 있다.

00401006      |.  8B45 08       MOV EAX,DWORD PTR SS:[EBP+8]

00401009      |.  8945 F8       MOV DWORD PTR SS:[EBP-8],EAX

0040100C      |.  8B4D 0C       MOV ECX,DWORD PTR SS:[EBP+C]

0040100F      |.  894D FC       MOV DWORD PTR SS:[EBP-4],ECX

 

초기화 전
초기화 후 _ 6과 2가 스택에 들어간것을 확인할 수 있다.

아까 Main함수로부터 전달받은 인자 6을 EAX,에 넣어준 후, EAX를 add함수의 지역변수인 x의 자리인 EBP-8에 넣어주고, Main함수로부터 전달받은 인자 2를 ECX에 넣어준 후, ECX를 add함수의 지역변수인 y의 자리인 EBP-4에 대입한다.

이 과정은 코드의 int x = a , y = b; 즉, 넘겨받은 인자를 add함수의 지역변수에 초기화하는 과정을 나타낸다.

 

00401012      |.  8B45 F8       MOV EAX,DWORD PTR SS:[EBP-8]

6을 EAX에 넘겨주고

00401015      |.  0345 FC       ADD EAX,DWORD PTR SS:[EBP-4]

2와 더하여 6+2 인 8의 값을 EAX에 다시 저장한다.

 

< 함수 에필로그 >

 

00401018      |.  8BE5          MOV ESP,EBP

ESP의 값을 EBP와 같게 만들어 준 후,

0040101A      |.  5D            POP EBP

0040101B      \.  C3            RETN ------> main함수의 add함수 다음 코드의 주소(401041)으로 리턴 

 

pop하여 add함수의 스택프레임을 없앤 후, RETN을 통해 main함수의 add함수 다음 코드의 주소로 리턴하게 된다.

 

다시 Main함수로 돌아오면, add함수 호출 이후 다음 명령어의 주소로 돌아온 것을 확인할 수 있다.

00401041      |.  83C4 08       ADD ESP,8

add함수를 실행한 후에, ESP값을 4byte*2만큼 아래로 내려 파라미터 할당에 사용한 스택 두개를 정리하는 명령어이다.

 

 

00401044      |.  50            PUSH EAX

00401045      |.  68 6CA14000   PUSH stackFra.0040A16C                   ;  ASCII "%d

0040104A      |.  E8 09000000   CALL stackFra.00401058

 

위의 세 코드는 두 값의 합을 push하고, %d를 printf함수로 넘겨주는 과정이다. 

 

0040104F      |.  83C4 08       ADD ESP,8

main함수 지역변수 할당에 사용한 스택 두개를 정리하는 명령어이다.

 

00401052      |.  33C0          XOR EAX,EAX

XOR 을 통해 EAX값을 0으로 초기화시킨다.

00401054      |.  8BE5          MOV ESP,EBP

00401056      |.  5D            POP EBP

00401057      \.  C3            RETN

 

그 후, 함수에필로그과정이 수행되고, main함수는 종료된 후, Main함수 다음 명령어의 주소로 리턴하게 된다.