코드엔진 Basic RCE L11 문제를 풀어보았다.
문제는 다음과 같다.
파일을 DIE에 올려보니 UPX로 패킹되어있다고 뜬다.
UPX로 언패킹해준다.
언패킹된 파일을 다시 DIE에 올려보았다. 패커가 감지되지 않는 걸로 보아 제대로 언패킹된 것을 알 수 있다. 여기에는 OEP가 0x400600라고 나오는데, 이게 맞는 값인지 검증해보자.
PE
버튼을 눌러서 들어가보았다. 진입 지점은 ImageBase + AddressOfEntryPoint이라서 401000이 되어야 한다.
하지만, 진입 지점이 400600으로 나오는 것으로 보아 무언가 오류가 있어 잘못 나온 것으로 보인다. 그래서 OEP는 401000이라고 짐작할 수 있다.
(하이라이트를 잘못쳤는데, BaseOfCode가 아니라 AddressOfEntryPoint를 강조하려고 했다.)
이제 StolenByte를 찾아보자.
StolenByte란?
- 안티디버깅 기법 중 하나이다.
- OEP 주소의 코드를 따로 분리해서 OEP로 점프하기 직전에 push로 넘겨준다.
- OEP의 옵코드 일부가 JMP 직전에 있어서 OEP로 코드 조각이 오지 못했고, 이 경우 StolenByte라는 옵코드를 찾아 실행코드 부분에 복원해준 다음 언팩을 해주어야 정상 실행이 가능하게 된다.
StolenByte를 찾기 위해 x64dbg에서 OEP로 점프하는 부분을 찾아서 그 직전에 push하는 부분을 살펴보기로 하자.
PUSHAD 명령어를 한 줄 실행시켜 레지스터들을 스택에 저장시킨다.
그리고 PUSHAD 후에 ESP값에 접근하는 지점에 BP를 설정한다.
F9
로 실행시켜보면, 실행하다가 POPAD 아래에서 멈추는 것을 알 수 있다. 아래의 JMP 40100C가 OEP이고, 0x40736E부터 3줄이 StolenByte일 것이다.
💻 MessageBoxA 💻
파일이 언패킹 된 상태일 때, MessageBoxA에 인자가 하나만 들어간 걸 볼 수 있지만 원래 인자가 4개 들어가야 한다. 따라서 사라진 3개의 인자가 push되어야 하고, 결국 StolenByte는 3줄이다.
push된 문자열을 보면 실행파일의 깨진 문자 대신 들어올 정상적인 문자열인 것을 알 수 있다.
이제 StolenByte를 써서 정상적인 파일이 됐다고 가정했을 때의 OEP를 구해보자.
StolenByte는 MessageBoxA의 인자로 들어가므로 MessageBoxA가 call되는 0x40100C
윗부분의 nop
부분에 들어간다.
nop
부분을 드래그해서 Ctrl + E
를 눌러 코드 편집
창을 연 후, StolenByte의 Hex값을 모두 써준다.
그러면 OEP가 0x401000인 파일이 완성된다!