정현진Jeong Hyeonjin

정현진 — 보안 포트폴리오

Research / 리버싱 / 패킹과 언패킹: UPX, OEP 찾기, 하드웨어 브레이크포인트로 수동 언패킹하기

패킹과 언패킹: UPX, OEP 찾기, 하드웨어 브레이크포인트로 수동 언패킹하기

유형
연구 기록
분류
리버싱
발행
2025. 12. 29.
분량
2분
종류
연구 기록

패킹된 파일이 실행될 때 어떻게 원래 코드로 돌아오는지 보고, ESP와 하드웨어 브레이크포인트로 OEP를 찾아 덤프와 IAT 복구까지 했습니다.

리버싱 입문서 5장을 공부하면서 정리했습니다. 패킹된 파일은 디스크에 있는 코드와 실제로 실행되는 코드가 다릅니다. 그래서 언패킹된 원래 코드가 시작되는 지점(OEP) 을 찾는 것이 핵심입니다.

패킹이란

패킹은 실행 코드를 압축하거나 암호화해서 PE 파일의 한 섹션에 넣어 두고, 실행할 때 풀어서 돌리는 방식입니다.

종류 Compressor Protector
목적 파일 크기 줄이기 분석 방해(난독화)
장점 작은 실행 파일 내부 로직 보호
단점 실행 속도 저하 크기 증가, 속도 저하
예 UPX, Petite, ASPack Themida, ASProtect, Yoda
  • UPX: 가장 많이 쓰이고, OllyDbg에 언패킹 기능이 들어 있습니다.
  • Themida: 옵션마다 언패킹 방식이 달라 풀기 어렵고, 악성코드와 국내 보안 프로그램·게임에서도 씁니다.

패킹된 파일은 세 부분으로 나뉩니다. 언패킹 코드, 패킹된 데이터, 그리고 풀린 원본이 들어갈 빈 공간입니다.

실행될 때 일어나는 일 (UPX 기준)

  1. 로더가 파일을 메모리에 올립니다.
  2. 엔트리 포인트부터 실행되는데, 이 엔트리 포인트는 언패킹 코드에 있습니다.
  3. 언패킹 코드가 압축을 풀어 빈 공간에 원본을 씁니다.
  4. 다 풀리면 OEP(Original Entry Point), 즉 패킹 전 원래 엔트리 포인트로 점프합니다.

UPX로 직접 패킹해 보기

upx -o [패킹 후 파일] [패킹 전 파일]

Detect It Easy(DIE)로 전후를 비교했습니다.

패킹 전 패킹 후
크기 8.00K 6.50K
감지 델파이, 패킹 안 됨 델파이, UPX
섹션 데이터 분포 섹션마다 고르게 분포 UPX0 섹션에 데이터 없음

UPX0이 비어 있는 이유는 그곳이 실행 중 원본이 풀릴 자리이기 때문입니다.

UPX 엔트리 포인트의 모양

UPX로 패킹된 파일의 엔트리 포인트는 PUSHAD로 시작합니다.

  1. PUSHAD로 모든 레지스터를 스택에 백업
  2. 언패킹 코드가 압축을 풀어 메모리에 씀
  3. POPAD로 레지스터 복구
  4. OEP로 점프

그래서 POPAD 뒤의 큰 점프를 찾으면 OEP에 닿습니다. 수동으로 보려면 OllyDbg 옵션의 [SFX] → "Unpack SFX modules automatically"를 끕니다.

덤프와 IAT 복구

  1. OEP까지 실행한 상태에서 OllyDumpEx 플러그인으로 메모리를 PE 파일로 저장합니다. 이때 엔트리 포인트 칸에는 OEP에서 ImageBase를 뺀 값을 넣습니다.
  2. 덤프한 파일은 실행되지 않습니다. 덤프 과정에서 IAT(어떤 DLL의 어떤 함수를 쓰는지에 대한 표) 가 쉽게 망가지기 때문입니다. DIE로 보면 원본과 달리 DLL 정보가 깨져 있습니다.
  3. LoadPE의 [Rebuild PE]로 덤프 파일을 다시 구성하면 실행되고, 이후로는 언패킹 과정 없이 바로 디버깅할 수 있습니다.

수동 언패킹: ESP로 OEP 찾기 (Lena 20강, EZIP)

언패킹 루틴도 결국 하나의 함수처럼 동작합니다. 시작할 때 이전 EBP를 스택에 저장하고(PUSH EBP), 끝날 때 그 값을 다시 꺼냅니다(POP EBP). 그러면 그 스택 위치를 읽는 순간이 언패킹이 끝나는 순간입니다.

  1. 엔트리 포인트(004650BE)부터 스텝 오버로 진행해 PUSH EBP가 실행되게 합니다.
  2. 이때 ESP가 가리키는 스택 위치에 이전 EBP 값이 있습니다.
  3. 그 위치에 하드웨어 브레이크포인트(Access) 를 겁니다.
  4. 실행하면 그 값을 다시 읽는 지점(004271B5, 기존 EBP 복구)에서 멈추고, 바로 뒤가 OEP로 가는 길입니다.

소프트웨어 vs 하드웨어 브레이크포인트

소프트웨어 (F2) 하드웨어
방식 명령 첫 바이트를 0xCC로 바꿈 CPU의 디버그 레지스터(DR0~DR3)에 주소 기록
개수 제한 없음 4개
조건 실행만 실행, 쓰기, 접근(읽기/쓰기)
대상 코드 코드와 데이터(메모리)
크기 지정 — Byte, Word, Dword

실행되지 않는 스택 데이터를 지켜봐야 하므로 하드웨어 브레이크포인트가 필요했습니다.

코드 인젝션 개념

코드 인젝션은 PE 파일의 빈 공간에 셸코드를 넣어 실행되게 하는 기법입니다. 4장의 코드 케이브와 같은 원리입니다.

  • 셸코드: 공격자가 원하는 동작을 하는 작은 기계어 코드
  • 셸코드는 보통 100바이트 정도라 명령 하나 자리에 못 넣습니다. 그래서 빈 공간에 넣고, 원래 명령 하나를 그쪽으로 가는 점프로 바꿉니다.
  • 지운 원래 명령은 셸코드 영역 맨 위로 옮기고, 셸코드 끝에서 원래 흐름으로 돌아옵니다.
  • 셸코드는 메모리 맵에서 실행 권한(E)이 있는 영역에 넣어야 합니다.

공격자 관점에서 보면

패커는 "디스크에 있는 파일만 검사하면 된다"는 가정을 깹니다. 정적 분석으로 보이는 코드는 언패킹 루틴뿐이고, 실제 동작은 메모리에서 풀린 뒤에만 보입니다. 그래서 분석은 결국 실행 중 메모리를 기준으로 해야 하고, 그 출발점이 OEP입니다.

정리

  • 패킹된 파일의 엔트리 포인트는 언패킹 코드이고, 원래 코드는 OEP에서 시작합니다.
  • UPX는 PUSHAD … POPAD → 점프 패턴으로 OEP를 찾을 수 있습니다.
  • 덤프 후에는 IAT를 복구해야 실행됩니다.
  • 패턴이 없으면 ESP + 하드웨어 브레이크포인트로 언패킹이 끝나는 순간을 잡습니다.

0 백링크0 링크3 태그