티스토리 뷰
[Reversing] 스택프레임(Stack Frame)
스택프레임
- 새로운 함수가 호출 될 때 호출 후 원래의 위치로 돌아갈 정보를 담고 있습니다.
- ESP, EBP 레지스터를 사용해서 변수나 원복주소에 접근하는 방식입니다.
- 즉, 함수가 호출 될때 그 함수가 가지는 공간 구조입니다.
함수를 호출할 때 그 함수가 가지고 있는 공간으로 스택 프레임 구조는 함수 프롤로그 - 함수 원형 - 함수 에필로그로 구분할 수 있다.
스택 프레임 예제
#include <stdio.h>
int main()
{
int x;
printf("정수입력 : ");
scanf_s("%d", &x);
printf("%d\n", x);
return 0;
}
[소스코드]
스택 프레임의 구조
[예제 스택프레임 구조]
[main() 함수의 스택 프레임]
x64 dbg
- 우선 main() 함수를 찾습니다.
- 4012A3 main( )함수 입니다.
- 이후 main() 함수가 끝이나고 돌아오는 주소를 보시면 4012A8 입니다.
main() 함수 시작 시 스택의 상태
- 현재의 EBP 18FF88, ESP 18FF44 입니다.
- 현재 ESP 18FF44에 4012A8 저장되어있습니다.(main함수 종료 후 리턴 주소)
401090 PUSH EBP
- main() 함수는 바로 스택 프레임을 생성한다고 합니다.
- 나중에 함수가 종료되기전에 이 값을 원복 시켜줍니다.
EBP 18FF88
401091 MOV EBP, ESP
- main() 함수가 끝날 때까지는 EBP는 변경되지 않습니다.(함수의 스택 프레임 생성)
EBP 18FF40
ESP 18FF40
- 18FF40 주소에는 18FF88(main() 함수의 EBP) 값 저장
~ 함수의 본체
4010D4 MOV ESP, EBP(main() 함수가 시작할 때의 초기값 원복)
4010D6 POP EBP(원래의 EBP 값 복원)
RETN
- 스택 프레임의 구조와 같이 마지막 위 명령로 스택 프레임은 해제 됩니다.
- main() 함수의 스택 프레임은 해제되면서 스택 프레임이 생성 되었을 때와 같은 모습(ESP, EBP)으로 돌아옵니다.
[MOV ESP, EBP / POP EBP / RETN 부분]
중간정리
PUSH EBP |
MOV EBP, ESP |
~ 함수의 본체 |
MOV ESP, EBP |
POP EBP |
RETN |
잠시 스택 프레임의 구조를 간략하게 설명하기 위해 작성한 부분입니다
이제 함수의 본체를 알아보기 위해 401091 MOV EBP, ESP 이후 명령부터 다시 시작하겠습니다.
현재 스택의 상태의 상태를 보면 18FF40 => 18FF88(main() 함수의 EBP), 18FF44 => 4012A8(main() 함수 리턴 주소) 입니다.
401093 SUB ESP, 8
- 변수(x) 값을 저장하기 위해 메모리 공간 확보하는 부분입니다.
- ESP에서 8을 빼서 공간을 확보한다라고 할수있습니다.
- 현재 ESP는 18FF38 입니다.
- 참고로 리버싱 핵심원리에서는 long 타입의 2개의 변수를 선언해서 4byte * 2(a, b) 총 8byte를 확보했습니다. 8byte 보다는 커야된다는거겠죠.
- int x; 선언한 변수는 이후 scanf() 함수에서 변수 x의 값을 입력 받아 저장이 될것 입니다.
401096 MOV EAX, DWORD PTR DS:[41E004]
40109B XOR EAX, EBP
40109D MOV DWORD PTR ss:[EBP-4], EAX
- 해당 명령을 한줄씩 보게 되면,
DS:[41E004] 값을 EAX에 저장 =>
EBP(18FF40)를 EAX값과 XOR =>
XOR 한 EAX 값을 [EBP-4](18FF3C)에 저장(스택가드 값)
4010A0 PUSH PROJECT1.41C788
- 다음주소(18FF34)에 41C788 주소 저장
- 41C788에는 printf("정수입력 : "); "정수입력 : " 문자열이 해당 부분이 있습니다.
4010A5 CALL project1.401020
- 해당 명령은 Pinrtf() 함수를 호출하는 부분입니다.
- printf() 함수에 대한 어셈블리는 구글링(비슷한 맥락)
[printf() 함수의 스택 프레임]
중간정리
소스코드로 보게되면 int x; , printf("정수입력 : "); 까지 진행했습니다.
401093 메모리 공간 확보, 변수 x에 관한 내용을 선언하였습니다.
401096 ~ 40109D 해당 부분은 스택 버퍼오버플로우를 탐지하기 위해 XOR을 통하여 스택가드가 적용되어있습니다.
4010A0, 4010A5 "정수입력 : " 문자열을 pritnf() 함수를 통하여 출력하였습니다.
4010AA LEA EAX, DWORD PTR SS:[EBP-8]
- LEA는 주소를 가져오는 뜻입니다. MOV는 해당 값을 가져오지만 LEX 주소입니다.
- [EBP-8]의 주소를 가져와 EAX에 저장하라는 뜻이 되겠습니다.(이유는 다음 PUSH EAX 에서)
4010AD PUSH EAX
- 생각해보면 EAX 18FF38은 이전 위에서 변수(x) 값을 저장하기 위해 공간을 8 확보한 주소이죠!
- EAX 18FF38을 다음주소에 넣어줍니다.
4010AE PUSH PROJECT1.41C794
- 41C794에는 scanf_s("%d", &x); 의 "%d" 해당 부분이 있습니다.
4010B3 CALL PROJECT1.401050
- 해당 명령은 Scanf() 함수를 호출하는 부분입니다.
- scanf() 함수에 대한 어셈블리는 구글링(비슷한 맥락)
[scanf() 함수의 스택 프레임]
- 해당 명령을 진행하면서 변수(x)의 값(저는 숫자 7)을 입력했습니다.
- 해당 변수(x) 값은 18FF38에 저장이 되었습니다.
중간정리
scanf() 함수까지 진행했습니다.
저는 7을 입력하여 18FF38에는 7이 저장되었습니다.
4010B8 PUSH DWORD PTR SS:[EBP-8]
- [EBP-8]은 변수(x) 값을 말하는 거죠!
- [EBP-8]에 있는 7을 다음주소에 넣어줍니다.
4010BB PUSH PROJECT1.41C798
- 41C798에는 printf("%d\n", x); 의 "%d\n" 해당 부분이 있습니다.
- 현재까지 printf() 함수 2번, scanf() 함수를 사용했습니다.
- 여기서 한번 생각을 해보면 main() 함수의 EBP 값을 기준으로 엑세스를 진행한다는것 입니다.
- [EBP-8]에 변수(x) 값이며, 스택에는 반대로 저장이 된다는것 입니다.(당연한거죠 스택은 올래 그런거니 LIFO)
4010C0 CALL PROJECT1.401020
- 이전과 같은 printf() 함수 호출 부분입니다.
RETURN & 마무리
나머지 부분은 위에서 정리를 했었습니다.
[파일]
'Reversing > ETC' 카테고리의 다른 글
[Reversing] 패킹(Compressor, Protector), Packer, Crypter (0) | 2019.07.20 |
---|---|
[Reversing] Printf()함수 스택프레임(Stack Frame) (0) | 2019.06.30 |
[Reversing] 가능한 가장 작은 PE 실행 파일 만들기(Tiny PE) ② (0) | 2019.06.07 |
[Reversing] 가능한 가장 작은 PE 실행 파일 만들기(Tiny PE) ① (0) | 2019.04.02 |
[Reversing] IMAGE_SECTION_HEADER (0) | 2019.02.12 |
- Total
- Today