리버싱 공부
스택 프레임 기법
스택을 다루는데 있어서
ESP 레지스터, 현재 스택을 가리켜 주는 ESP레지스터를 사용하는데
함수를 만들고 사용할 때 함수를 들어가서 ESP 레지스터를 막 사용하다 보면
원래 돌아가야 할 위치를 알고 있더라도 함수의 시작 위치를 알 수 없게 되고
사용이 굉장히 복잡해진다.
그걸 방지?하기 위해 스택 프레임 기법이라는 방식이 도입되었다고 하는데.
함수를 들어갔을 때의 스택의 위치를 EBP레지스터, 베이직 포인터 레지스터가 가지고 있고, 함수에서 스택을 다룰 때 ESP를 사용 후 나중에 EBP에서 함수의 첫 주소를 가지고 있게 하며 안전하게 리턴할 수 있게 한다.
리버싱 핵심원리에 있는 예제와 비슷하게 코딩해봤다.
함수를 하나 만들어서 메인에서 호출하는 간단한 예제이다.
이걸 올리 디버거에서 보면,
메인이 시작되는 부분이다.
사실 메인도 함수기 때문에 스택 프레임 기법으로 작성되어 함수 프롤로그 부분이 있다.
메인부터 보자면,
메인 함수가 호출되고 나서. EBP에 원래 있던 주소는 스택에 담아서 백업해 두어야 하고,
PUSH EBP 명령어를 통해 실행하게 된다.
EBP가 가지고 있던 스택 주소를 스택에 백업해 두고, MOV EBP, ESP 명령어를 통해
현재 ESP의 주소를 EBP에 넣게 된다.
지역 변수의 크기 할당을 위해서 가지고 있는 지역 변수의 총 크기를 ESP에서 빼서
ESP를 다시 설정하고 ESP를 이용해 스택을 사용하게 된다.
(int 변수 3개 : 4byte * 3 = 0x0c)
그럼 EBP는 함수의 시작 주소를 가지고 있고, ESP는 스택을 마음대로 사용하게 된다.
그리고 추가적으로, EBP는 함수의 시작 주소를 가지고 있고, 함수가 가지고 있는 지역 변수와 함수를 호출할 때의 매개 변수 주소를 EBP의 주소에서 감가산을 해 가면서 계산하게 된다.
후에 함수의 내용이 끝나면 리턴하기 전에 ESP에 EBP의 값을 다시 집어넣어 함수의 처음 스택 주소를 가지고, 함수 호출 이전에 사용하던 EBP의 값을 다시 스택에서 POP해서 원래대로 놓고 리턴을 하게 된다.
예제 함수인 add함수를 호출할 때도 똑같이 작용한다.
함수를 호출하는 부분에서 레지스터의 값은
EBP : 006FF8C4
ESP : 006FF8B0
이다.
함수를 호출하면
add함수에도
PUSH EBP
MOV EBP, ESP
SUB ESP, X
...
...
MOV ESP, EBP
POP EBP
RETN
의 형태를 띄고 있는걸 볼 수 있다.
ESP 레지스터, 현재 스택을 가리켜 주는 ESP레지스터를 사용하는데
함수를 만들고 사용할 때 함수를 들어가서 ESP 레지스터를 막 사용하다 보면
원래 돌아가야 할 위치를 알고 있더라도 함수의 시작 위치를 알 수 없게 되고
사용이 굉장히 복잡해진다.
그걸 방지?하기 위해 스택 프레임 기법이라는 방식이 도입되었다고 하는데.
함수를 들어갔을 때의 스택의 위치를 EBP레지스터, 베이직 포인터 레지스터가 가지고 있고, 함수에서 스택을 다룰 때 ESP를 사용 후 나중에 EBP에서 함수의 첫 주소를 가지고 있게 하며 안전하게 리턴할 수 있게 한다.
리버싱 핵심원리에 있는 예제와 비슷하게 코딩해봤다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#include <stdio.h>
#include <stdio.h>
int add(int num1, int num2);
int main()
{
int a, b;
a = 10;
b = 20;
int c;
c = add(a, b);
printf("%d\n", c);
}
int add(int num1, int num2)
{
int number1;
int number2;
number1 = num1;
number2 = num2;
return (number1 + number2);
}
| cs |
이걸 올리 디버거에서 보면,
메인이 시작되는 부분이다.
사실 메인도 함수기 때문에 스택 프레임 기법으로 작성되어 함수 프롤로그 부분이 있다.
메인부터 보자면,
메인 함수가 호출되고 나서. EBP에 원래 있던 주소는 스택에 담아서 백업해 두어야 하고,
PUSH EBP 명령어를 통해 실행하게 된다.
EBP가 가지고 있던 스택 주소를 스택에 백업해 두고, MOV EBP, ESP 명령어를 통해
현재 ESP의 주소를 EBP에 넣게 된다.
지역 변수의 크기 할당을 위해서 가지고 있는 지역 변수의 총 크기를 ESP에서 빼서
ESP를 다시 설정하고 ESP를 이용해 스택을 사용하게 된다.
(int 변수 3개 : 4byte * 3 = 0x0c)
그럼 EBP는 함수의 시작 주소를 가지고 있고, ESP는 스택을 마음대로 사용하게 된다.
그리고 추가적으로, EBP는 함수의 시작 주소를 가지고 있고, 함수가 가지고 있는 지역 변수와 함수를 호출할 때의 매개 변수 주소를 EBP의 주소에서 감가산을 해 가면서 계산하게 된다.
후에 함수의 내용이 끝나면 리턴하기 전에 ESP에 EBP의 값을 다시 집어넣어 함수의 처음 스택 주소를 가지고, 함수 호출 이전에 사용하던 EBP의 값을 다시 스택에서 POP해서 원래대로 놓고 리턴을 하게 된다.
예제 함수인 add함수를 호출할 때도 똑같이 작용한다.
함수를 호출하는 부분에서 레지스터의 값은
EBP : 006FF8C4
ESP : 006FF8B0
이다.
함수를 호출하면
add함수에도
PUSH EBP
MOV EBP, ESP
SUB ESP, X
...
...
MOV ESP, EBP
POP EBP
RETN
의 형태를 띄고 있는걸 볼 수 있다.
댓글
댓글 쓰기