코드엔진 Basic RCE L10 문제를 풀어보았다.
문제는 다음과 같다. OEP를 구한 후 '등록성공'으로 가는 분기점의 OPCODE를 구하라는 문제이다.
파일을 실행시켜보면 문자 입력이 안되는 창이 뜬다.
DIE에 올려보았다. ASPack로 압축되어있다고 뜬다.
ASPack를 언패킹할 수 있는 unipacker로 압축을 풀어주려고 했지만, 해당 모듈에서는 패커를 감지하지 못해 실패했다.
따라서 패킹을 수동으로 푸는 방법밖에 없는 것 같다. 찾아보니 Aspack를 언패킹하는 방법에는 두 개가 있다고 한다.
첫 번째는 RET C를 찾아 OEP를 찾는 방법이고, 두 번째는 하드웨어 BP를 이용해서 언패킹하는 방법이다. 하나씩 알아보자.
DIE에 패킹된 파일을 올려보았을 때, EP는 0x456001
이라고 뜬다.
x64dbg에서도 처음에 F9
로 패킹된 파일의 EP로 이동할 수 있고, 여기서 PUSHAD
명령어를 확인할 수 있다. 이부분에서 현재 레지스터(EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI)를 스택에 저장한다.
DIE의 PE를 눌러 들어가서 IMAGE_NT_HEADERS 안의 IMAGE_OPTIONAL_HEADER에 들어가면 AddressOfEntryPoint(메모리로부터의 상대주소 RVA)가 0x56001
, ImageBase가 0x400000
인 것을 볼 수 있다. 프로그램이 메모리에 로딩 시 ImageBase + AddressOfEntryPoint로 저장되므로, 진입점은 0x00056001
+ 0x00400000
= 0x00456001
(VA, 가상메모리의 절대주소)이다.
스크롤을 내리다보면 POPAD
와 그 밑의 RET C
를 확인할 수 있다.
메모리 및 레지스터를 POPAD로 복구 후 OEP로 분기하기 위해 RET C 명령어를 수행한다.
pop rip
와 같아 push한 값을 ret으로 빼낸다. 후에 push 0이 push OEP로 바뀌기 때문에 push한 OEP값을 ret으로 빼내서 OEP값으로 이동하는 뜻이다.RET C 이후 push 0과 ret 명령어를 확인할 수 있는데, 두 opcode에 BP를 걸고 프로그램을 실행한다.
이때 push 0이 push 10.445834로 변경된 것을 확인할 수 있는데, 이는 OEP인 0x445834
를 push하고, ret에서 해당 주소로 이동한다는 뜻이다. 따라서 이곳이 OEP이다.
-> 해당 파일의 OEP는 0x445834
이다.
여기까지 하면 모든 압축이 풀린 것을 확인할 수 있는데, 다음을찾기-모든모듈-문자열참조
에서 “Registered... well done!” 문자열을 찾을 수 있는 것이 그 증거이다. (패킹된 상태에서는 찾을 수 없음)
→ 445834 + 7555 = 4458347555가 답이다!
먼저 패킹의 원리는 다음과 같다.
- PUSHAD 명령어를 통해 레지스터를 스택에 쌓는다
- 정상 코드를 메모리에 복구한다
- POPAD 명령어를 통해 레지스터 값들을 복구한다
- OEP로 분기한다.
따라서 1번을 실행한 후 스택에 저장된 레지스터에 하드웨어 브레이크포인터를 걸고 F9를 눌러 실행시킨다면, 해당 스택 값을 복원하려고 하는 3번 지점에서 BP가 걸릴 것이다.
PUSHAD
를 실행했을 때, 스택에 레지스터들이 쌓인 것을 볼 수 있다.
그 중 한 개에 브레이크포인트를 걸고, F9
를 눌러 실행한다.
POPAD
아래에서 BP가 걸려 멈추는 것을 알 수 있다. 그 아래에 있는 0x445834
가 OEP이고, 이곳을 지나 ret하면 언패킹이 완료된다!
언패킹 루틴을 지났고 함수의 프롤로그가 보이는 것으로 보아 언패킹이 완료된 것을 알 수 있다. 이 상태에서 덤프를 뜨는 방법을 알아보자.
메모리 덤프를 위해 x64dbg 메뉴의 Scaylla
를 클릭한다.
Scaylla
를 클릭해서
1. IAT Autosearch를 클릭한다
2. Get Imports를 클릭한다
3. Dump를 클릭하고 원하는 경로에 새로운 파일로 저장한다
4. Fix Dump를 클릭하고 저장한 파일을 Fix한다
Fix Dump
를 하는 이유는?최종적으로 덤프한 언패킹된 파일을 x64dbg에서 열어보았다. 성공적으로 덤프된 것을 확인할 수 있다.
RET C를 찾고 OEP를 찾는 방법에서 '등록성공'으로 가는 분기점을 찾은 방법과 완전히 같다.
ASPack를 처음 접해봐서 RET C를 찾으면 언패킹할 수 있다는 건 어디서 알 수 있는 건지 궁금했는데, 검색해보니 관련 자료를 찾을 수 있었다. 아래에서 여러 패커들을 수동으로 패킹하는 방법들을 소개하고 있다.