스택 프레임: 함수가 사용하는 독립적인 메모리 영역 >> 함수가 실행 중일 때 존재하고 실행이 끝나면 사라짐
스택: 메모리와 달리 기준점(EBP 레지스터; 프레임 포인)을 중심으로 데이터를 참조
EBP(프레임 포인터) : 하나의 루틴에서 서브루틴으로 이동할 때 EBP 레지스터의 값을 따로 보관해둬야한다. 서브루틴에서 원래의 루틴으로 복귀할 때(return할 때) 따로 보관해뒀던 값을 EBP 레지스터에 복구시킨다.
ESP(스택 포인터) : 현재 사용하는 스택의 맨 위를 가리킨다. 또한, EBP 레지스터의 값을 유지하는데 사용한다.
PUSH EBP
MOV EBP, ESP
// 원래 루틴의 ebp값을 스택에 push = esp가 가리키는 주소에 ebp 값 저장
.....
// 서브루틴
// 서브루틴 중 ebp에는 이전 루틴의 ebp를 가리키는 스택의 주소 저장
.....
MOV ESP, EBP
POP EBP
// esp에 들어간 데이터(이전 루틴의 프레임 포인)를 ebp로 옮김
JMP EAX
①~② 서브루틴에 처음 진입했을 때 ESP 레지스터에는 0018ff8c가 저장되어 있고, EBP 레지스터에는 0018ff94가 저장되어 있다. ESP는 현재 실행되고 있는 스택의 최상단 주소라는 것을 확인할 수 있다.
③~④ 스텝오버[F8]를 통해 명령어를 하나 실행해보면 "PUSH EBP"가 실행된다. 이 명령을 통해 ESP 레지스터가 가리키는 위치(스택의 최상단)에 EBP의 값을 저장한다 : 현재의 서브루틴 이전 루틴에서의 ebp 값을 저장한다. --> 여기서 내가 헷갈렸던 부분이기도 한데, 사실 정말 당연한 얘기지만,, 스택이기 때문에
⑤~⑥ 스텝 오버로 명령어를 하나 더 실행해보면 "MOV EBP, ESP"가 실행된다. 이 명령을 통해 EBP에 ESP의 값을 복사한다 : 현재 서브루틴에 대한 새로운 스택 프레임을 생성한다.
ESP 레지스터가 가리키는 값을 읽어 원본 EBP에 값을 복구시킨다. 여기서 ESP 레지스터가 가리키는 값을 읽는 동작에 bp를 설정하면 언패킹 로직이 종료되는 시점을 파악할 수 있다. >> 패커가 언패킹 로직 종료 후 OEP 로 점프한다면 프로그램 실행이 멈춘 지점에서 OEP로 가는 부분에 대해 찾아 볼 수 있을 것이다.
변경되는 데이터의 첫 부분을 선택하고 Hardware breakpoint를 설정한다. 이 때, Read와 Write의 Access에 대한 하드웨어 브레이크포인트로 설정하고, 4byte씩 데이터를 읽고 있기 때문에 size는 0x4로 설정한다.
이렇게 설정한 breakpoint들을 확인할 수 있다.
**IDA 사용법(breakpoint 설정하기)**
빨간 응원봉처럼 생긴... 저 아이콘을 누르면 위에 나오는 브레이크 포인터 설정창이 뜬다. 이 아이콘의 바로 왼쪽 아이콘을 누르면 바로 이전 캡처본인 Breakpoints window를 띄울 수 있고, 오른쪽 아이콘을 누르면 이미 설정했던 브레이크 포인트를 해제할 수 있다.