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

< 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

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


아까 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함수 다음 명령어의 주소로 리턴하게 된다.
'정보보안 > 리버싱' 카테고리의 다른 글
| reverse_assembly 기본명령어 JE&JZ (0) | 2022.09.02 |
|---|---|
| reverse_assembly 기본명령어 IDIV (0) | 2022.09.02 |
| reverse_assembly 기본명령어 MOV (0) | 2022.09.02 |
| reverse_assembly 함수 (0) | 2022.09.02 |
| reverse_assembly 지역변수&전역변수 (2) | 2022.09.02 |