스택프레임 이해하기
nano sum.c 로 sum.c 를 만들어주고
#include <stdio.h>
int sum(int a, int b) {
return a + b;
}
int main(void) {
int c = sum(1, 2);
return c;
}
리눅스는 기본적으로 스택의 취약점을 잘 알고있기 때문에 방어체계를 마련해 놓는데 이것들을 우선 꺼보겠다
gcc -S -fno-stack-protector -mpreferred-stack-boundary=4 -z execstack -o sum.a sum.c (어셈블리어로 변환)
vi sum.a 로 어셈블리어 작성된 파일을 볼 수 있다
vi 에디터를 끌 때에는 esc 키를 누르고 :q 를 입력해주면 된다
nano sum.c를 보자
main 함수를 불렀을 때 가장 아래 RET 이라고 return address가 들어가게 되는데 가장 아래에 쌓이게 된다
return address는 특정한 함수가 끝난 후에 돌아갈 장소를 의미하는 것
모든 함수는 return address를 가지게 된다
RET 위에 RBP가 있는데 스택이 시작하는 베이스 포인터이다
즉 여기서부터 스택이 차례대로 위쪽으로 쌓일 것을 알려주는 첫번째 공간
그 위에 변수 c가 있고 (main함수 처음시작했을 때)
그 위에 버퍼가 있다
이게 기본적으로 main함수를 실행했을때의 결과이다
이제 sum을 호출했을 때를 보겠다
가장 아래 RET가 존재하고 그위에 RBP 그위에 변수 c 그위에 버퍼 (여기까지가 main)
이제 이 위로 새롭게 함수가 들어가는 것
변수 x 위에 변수y 위에 RET 위에 RBP 위에 버퍼 (이 때 변수 x, y는 매개변수 값이다)
이 때 변수값이 RET 아래에 위치하게되는데 RET는 sum을 실행하고 난 뒤에 돌아가는 위치이고 x, y는 함수를 실행하기 위해 사용되는 도구
이제 sum함수를 다하고 리턴하게 되면 하나하나가 다 삭제되고
변수 c에는 위에서 실행한 결과 값인 3이 들어가게 되고 메인함수만 남게 되고 3을 리턴해 준다
이제 gcc -o sum sum.c 입력해서 컴파일을 하고 ./sum 으로 실행해보면 아무 결과도 안나온다
return 3이 수행되기 때문에 아무것도 안뜨는 것이고 이것을 눈으로 보고싶다면 printf명령어를 사용하면 된다
printf("%d\n", c); 다시 컴파일하고 실행하면 3이 출력된다
RET, 특정함수가 끝나고 돌아가는 위치를 해커가 조작함으로써 서버에 악영향을 끼칠 수 있는데 대표적인 기법으로는 BOF 등이 있다
vi sum.a 로 어셈블리어를 보자
main 함수부분을 보면 먼저 RET가 자리를 잡고 push로 RBP가 생기고 RBP는 RSP가 되는건데 둘이 동일한 위치를 가리키게 됨
RSP에서 16을 빼면 16만큼 점프를 하게 됨 이것은 16만큼 공간을 확보하여 그 안에서 어떠한 코드를 작성하겠다는 뜻
ESI에 2를 넣고 EDI에 1을 넣었는데 이것은 RSI와 RDI와 같다고 생각하면 된다
이렇게 한 이유는 최적화를 위해 다운그레이드한 것임 작동원리는 거의 흡사
이제 sum을 보자
아까 RSP가 16만큼 공간을 확보한다고 하였었는데 sum을 불러왔으니 똑같이 RET부터 시작
RET 위에 RBP(push) 그리고 RBP -4의 위치에다가 EDI 값(=1)을 집어넣어줌
RBP -8의 위치에다가 ESI 값(=2)을 넣어준다
그리고 -4의 RBP의 위치 즉 1의 값을 EDX에 넣어주고 -8의 RBP의 위치 즉 2의 값을 EAX에 넣어줌
그다음 addl %edx, %eax 므로 EDX의 값을 EAX에 더해준다
결과적으로 EAX=3 이 나오게 된다
마지막으로 RBP를 빼줌으로써 RET로 돌아갈 수 있음
EAX는 RAX와 같다고 봐도 무방한데
RAX같은 경우는 특정 함수가 끝날 때 반환 값을 가지고 있는 레지스터
결과적으로 sum은 3이라는 값을 반환하고 있는 것
이제 다시 돌아와서 EAX=3값을 -4의 RBP에 위치
-4의 RBP 값을 EAX에 넣고 leave를 하고 RET를 함으로 3을 반환