본문 바로가기

INTERTLUDE/리버싱 스터디

Codeengn Basic RCE 9

Codeengn Basic RCE 9

Q. StolenByte를 구하시오 Ex) 75156A0068352040


해당 문제를 읽었는데, 처음 보는 개념인  Stolenbyte가 등장하였다. Stolenbyte가 무엇인지 모르겠어서 이에 대해 알고 문제 풀기를 시작하고자 한다.

  • Stolenbyte란 무엇일까? 말 그대로 “훔쳐진 바이트”라는 뜻으로,
    원래 실행 파일의 초기 코드(OEP 근처)에 있어야 할 바이트가 패킹 과정에서 디스크에서는 사라졌다가,
    프로그램이 실제 실행될 때 메모리에서 다시 복구되는 코드 조각을 의미한다.

Q. 왜 이러한 훔쳐진 바이트가 생길까?

UPX와 같은 패커는 프로그램을 압축하기 위해 내부 섹션 구조를 재배치한다.
이 과정에서 아래와 같은 동작이 일어난다.

  1. 원래 OEP 앞뒤의 코드 일부가 디스크에서 제거됨
  2. 실행 시 먼저 언패킹 루틴(PUSHAD → 언패킹 → POPAD) 이 수행됨
  3. 패킹되기 전 OEP의 코드 일부(예: PUSH, MOV 등)가
    스택이나 특정 메모리 위치에 몰래 저장됨
  4. 언패킹이 거의 끝나는 시점에서
    이 “원래 코드”를 POPAD 아래 ~ JMP OEP 사이에서 다시 복원함

디스크에는 없고, 실행 중 메모리에서만 다시 나타나는 “원래 코드” → StolenByte 

 

** UPX의 전형적 언패킹 루틴 구조는 다음과 같다: 

더보기
PUSHAD
[ 압축해제 루프 / 복원 코드 ]
POPAD
[ StolenByte 복구 구간 ]
JMP OEP

여기서 중요한 점은:

  • 패킹되기 전 원래 OEP에 있던 코드 일부를
  • 패커가 스택(PUSH 명령어들) 또는 특정 메모리 영역에 먼저 몰래 저장해 두었다가
  • 언패킹 루틴이 모두 끝나기 직전에 다시 복원해서 실행하도록 만들어 놓는다는 것이다.                                                                                                                    
  • 여기서 POPAD 바로 뒤가 언패킹이 끝나는 지점이고,
    POPAD ~ JMP OEP 사이가 바로 StolenByte가 복구되는 구간이라고 기억하면 된다.


해당 문제를 풀기 위해, 09.exe  문제 파일을 다운로드하여 주었다.

 7-Zip File Manager로 압축을 풀고 DIE로 파일 정보를 확인해보려고 한다.

 

압축을 푼 다음에, DIE로 확인해 보니 파일이 패킹이 되어 있음을 알 수 있다. 

그래서 upx-4.2.4-win64 폴더 내에서, CMD를 열고 언패킹 명령어를 입력하였다.

** 언패킹 명령어 :  upx -d -o (저장할 파일명) (원본 파일명) 

 

  • 패킹 파일 / 언패킹 파일 실행 결과 비교

 

 

  • 원본 09.exe 실행 시
    → 제목: abex' 3rd crackme
    → 내용: Click OK to check for the keyfile.
    라는 정상 메시지 박스가 뜬다.
  • unpacked_09.exe 실행 시
    → 메시지 박스는 뜨지만
    → 내용 부분이?↑P 䧪^? t卞 4Lᄑ 같이 깨져서 나온다.

즉, 언패킹 된 EXE에서 메시지박스에 전달돼야 할 문자열 관련 코드가 제대로 복구되지 못했다는 뜻이다.
문제에서 말하는 StolenByte가 바로 이 부분과 관련되어 있을 것이라고 추측할 수 있다.

 

 

  • 디버거로 UPX 언패킹 루틴 관찰하기                                                                                                                                Immunity Debugger로 09.exe를 열어 UPX 언패킹 루틴을 확인하였다. 

 

코드를 따라가다 보면, UPX의 전형적인 구조인 형태를 볼 수 있다.

 

004071F0   60               PUSHAD
0040736C   58               POP EAX
0040736D   61               POPAD

 

이때 우리가 특히 주목해야 할 구간은:

POPAD 바로 아래 ~ JMP 직전이 StolenByte 의심 구간

이 자리에서 원래 OEP에서 수행됐어야 하는 코드가 복구되기 때문이다. 


실제로 09.exe의 POPAD 인근 코드를 보면 다음과 같다.

0040736C   58               POP EAX
0040736D   61               POPAD
0040736E   6A 00            PUSH 0
00407370   68 00204000      PUSH 09.00402000       ; ASCII "abex' 3rd crackme"
00407375   68 12204000      PUSH 09.00402012       ; ASCII "Click OK to check for the keyfile."

 

이를 통해 알 수 있는 사실은, 

 

  • POPAD 바로 아래에 PUSH 0, PUSH 00402000, PUSH 00402012 가 연달아 나온다는 것과, 
  • 00402000, 00402012 주소를 따라가 보면 문자열이 있다는 것이다. 
    • 00402000 → "abex' 3rd crackme"
    • 00402012 → "Click OK to check for the keyfile."
  • 즉, 메시지박스(MessageBoxA) 호출을 위한 인자들이 PUSH되고 있는 것이라는 사실을 파악할 수 있었다. 

MessageBoxA의 함수는 다음 인자를 받는다.

int MessageBoxA(
    HWND   hWnd,     // 윈도우 핸들
    LPCSTR lpText,   // 메시지 내용
    LPCSTR lpCaption,// 메시지 제목
    UINT   uType     // 버튼/아이콘 타입
);

 

 

PUSH는 오른쪽 인자부터 역순으로 들어가므로:

PUSH uType
PUSH lpCaption
PUSH lpText
PUSH hWnd
CALL MessageBoxA

 

다음과 같다. 

 

우리가 본 코드를 여기에 대입해 보면,

0040736E   6A 00            PUSH 0              ; uType = 0 (MB_OK)
00407370   68 00204000      PUSH 09.00402000    ; lpCaption = "abex' 3rd crackme"
00407375   68 12204000      PUSH 09.00402012    ; lpText    = "Click OK to check for the keyfile."

각 주소(00402000, 00402012)를 따라가보면 실제 문자열이 존재한다.
즉, 이 3개의 PUSH가 원래 OEP에서 실행됐어야 하는 메시지박스 인자 세팅 코드임을 알 수 있다.

 

다음으로는 언패킹 된 exe 코드도 살펴보기 위해서, 

unpacked_09.exe를 디버거로 열면, 엔트리포인트(OEP) 00401000 부근의 코드가 다음처럼 보인다.

00401000   90     NOP
00401001   90     NOP
...
(총 12바이트 정도의 NOP)
...
0040100C   6A 00  PUSH 0
0040100E   E8 ... CALL MessageBoxA
...


OEP 위치에 NOP 12개가 깔려 있다는 것은
:: 최소 12바이트 분량의 “원래 코드”가 디스크에서 사라졌다는 뜻이고

 

 

  • NOP 12바이트 = 사라진 원래 코드 12바이트
  • POPAD 아래 PUSH 3줄의 크기도 12바이트
    (2 + 5 + 5 = 12)

따라서 NOP로 사라진 12바이트 = POPAD 아래의 PUSH 3줄 = StolenByte 라는 결론이 성립한다.

 

 

  • 최종 StolenByte 계산
  • 이제 POPAD 이후의 세 줄 PUSH 명령을 바이트 단위로 적어보면 된다.

바이트만 쭉 이어 쓰면: 6A 00 68 00 20 40 00 68 12 20 40 00

공백을 제거하면 6A0068002040006812204000

 

이 값이 바로 CodeEngn Basic RCE 9의 정답인 StolenByte이다.

 

문제 해결 성-공 

'INTERTLUDE > 리버싱 스터디' 카테고리의 다른 글

[Reversing.Kr] Music Player  (0) 2025.11.29
CodeEngn Advance RCE 3  (1) 2025.11.28
Codeengn Basic RCE 11  (0) 2025.11.26
Codeengn Basic RCE 17  (0) 2025.11.20
Codeengn Basic RCE 13  (0) 2025.11.18