what is SFP & FPO
SFP 란?
saved frame pointer 라는 뜻으로 흔히 아는 함수가 호출될 때 저장해 둔 프레임 포인터 $rbp 레지스터 값을 말한다. 이 값은 이런식으로 해석된다.
$rbp , $rsp 는 callee-saved 레지스터이다. 이 둘은 즉, 무슨 일이 있어도 함수 시작전과 후과 같게 된다. 그 보장을 위한 과정이 함수 초반에 push $rbp 이런식으로 saved 하는 것이다. 그런데 반대로 말하면 이 값을 수정할 수 있다면, caller의 레지스터 값 ( $rbp )을 내가 수정하는 것과 같다. 즉, 함수의 흐름을 제어할 수 있다.
FPO 란?
frame pointer overwrite 라는 뜻으로 위해서 말한 SFP를 overwrite 해서 함수의 흐름을 내가 제어하는 것을 말한다.
제어의 흐름은 다음과 같다.
메인 함수 → A 함수 → ret → 메인함수 → ret → 종료
이런식의 흐름의 프로그램은 흔하다. 이때 A함수에서 특정 이유로 FPO 가 가능하게 된다면, A함수의 마지막 에필로그에는 다음과 같다.
A함수 에필로그
0x0804866e <+34>: leave
0x0804866f <+35>: ret이때 leave는
mov $rbp $rsp
pop $rbp와 같다. 이 뜻은 내가 변조한 SFP 의 값이 pop $rbp 여기서 실제 $rbp로 들어가게 된다.
이후에 ret 을 하고 나면 main 함수의 내부에서 내가 변조한 $rbp 레지스터를 가지고 계속 이어지게 된다. 이 뜻은 Main 함수에서 사용되는 -0x10($rbp) 와 같은 사용을 내가 변조할 수 있으며 ( 심지어 다른 함수를 이후에 main 함수에서 호출해도 계속 내가 변조한 $rbp가 유지 된다 → $rbp는 callee-saved 니깐 )가장 큰 부분은 바로 main 함수의 에필로그이다.
main함수 에필로그
0x0804866e <+34>: leave
0x0804866f <+35>: ret역시 leave가 실행되고
mov $rbp $rsp
pop $rbp이때 내가 변조한 $rbp가 이제는 $rsp 까지 변조 시킨다.
0x0804866f <+35>: ret.
그리고 ret 함수는 pop $rip 이다. 이 말은 변조된 $rsp 의 다음 부분에 있는 값으로 점프를 하게 된다.
정확히 말하면 내가 변조시킨 $rbp 값의 + 한 스택 의 위치의 값으로 점프를 하게 된다.
중간에 pop $rbp 이 있기 때문에 $rsp 가 한스택 작아지기 때문