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함수 에필로그

C
   0x0804866e <+34>:    leave
   0x0804866f <+35>:    ret

이때 leave는

C
mov $rbp $rsp
pop $rbp

와 같다. 이 뜻은 내가 변조한 SFP 의 값이 pop $rbp 여기서 실제 $rbp로 들어가게 된다.

이후에 ret 을 하고 나면 main 함수의 내부에서 내가 변조한 $rbp 레지스터를 가지고 계속 이어지게 된다. 이 뜻은 Main 함수에서 사용되는 -0x10($rbp) 와 같은 사용을 내가 변조할 수 있으며 ( 심지어 다른 함수를 이후에 main 함수에서 호출해도 계속 내가 변조한 $rbp가 유지 된다 → $rbp는 callee-saved 니깐 )가장 큰 부분은 바로 main 함수의 에필로그이다.

main함수 에필로그

C
   0x0804866e <+34>:    leave
   0x0804866f <+35>:    ret

역시 leave가 실행되고

C
mov $rbp $rsp
pop $rbp

이때 내가 변조한 $rbp가 이제는 $rsp 까지 변조 시킨다.

0x0804866f <+35>: ret.

그리고 ret 함수는 pop $rip 이다. 이 말은 변조된 $rsp 의 다음 부분에 있는 값으로 점프를 하게 된다.

정확히 말하면 내가 변조시킨 $rbp 값의 + 한 스택 의 위치의 값으로 점프를 하게 된다.

중간에 pop $rbp 이 있기 때문에 $rsp 가 한스택 작아지기 때문