LAB-22Hard

Manual Unpacking Challenge

Go past packer identification: reason about what the compressed payload region implies, and what it takes to actually recover the unpacked code.

30 min6 prerequisites7 tools

Investigate

Hints

Hint 1

0x5200 - 0x200 is the region's length, not either endpoint's value.

Hint 2

Look at the Optional Header field that tells the loader how many bytes of virtual address space to reserve — packers keep this large even though the file itself is small.

Hint 3

You don't need to decompress the payload by hand — you just need to catch it after the packer decompresses it for you, at the moment it hands off to OEP.

Submit Findings

Prerequisites

  • ar1-packers-and-unpacking
  • m4-obfuscation-packing
  • w1-pe-deep-dive
  • PE structure (SizeOfImage, sections, entry point)
  • x64dbg + Scylla dump workflow
  • Hardware breakpoints (DR0-DR3)

Methodology

Investigation Methodology

1. Static Confirmation of Packing

Signal This Sample
UPX! signature at 0x20 Present
Sections UPX0 (empty) / UPX1 (payload) Present
High entropy in UPX1 Present (compressed data)
SizeOfImage >> file size Present
Entry point in UPX1 (stub) Present

2. UPX Section Layout

UPX0: Empty in file, R-X in memory (target for decompressed code)
UPX1: Compressed payload in file, R-X in memory (decompression stub + data)
  • UPX0 has SizeOfRawData = 0, but VirtualSize > 0
  • At runtime, UPX0 fills with decompressed code
  • Decompression writes into UPX0 (from UPX1)

3. Unpacking Workflow (Dynamic)

1. Load packed.exe in x64dbg
2. Set hardware breakpoint on WRITE to UPX0 region
   (or breakpoint at tail of stub — the jump to OEP)
3. Run — decompression writes to UPX0
4. Break when write to UPX0 occurs (stub is filling .text)
5. Find the final jump to OEP (e.g., jmp [orig_entry])
6. Break at OEP — code is fully decompressed
7. Dump memory (Scylla / OllyDump / x64dbg)
8. Fix imports (IAT is rebuilt — use Scylla)
9. Analyze dumped binary — strings, imports now visible

4. Finding OEP

Common UPX stub patterns:

; ... decompression loop ...
popad                    ; restore registers
jmp original_entry_point  ; jump to OEP

Look for:

  • popad / popfd then unconditional jmp
  • jmp [address] (indirect) = jump to OEP
  • push OEP / ret = jump via ret

5. Dump Techniques

Tool Method
Scylla x64dbg plugin, dump + IAT fix
OllyDump OllyDbg plugin
LordPE Process dump
Process Hacker Memory dump
procdump Sysinternals
gdb (Linux) dump memory

6. Import Reconstruction

  • IAT is rebuilt by the stub at runtime
  • After dump, imports point to correct addresses
  • Scylla scans for IAT, rebuilds import table
  • Alternative: use the packed binary's original imports (if not obfuscated)

7. Post-Unpack Verification

  • Strings now visible (C2, registry keys, mutexes)
  • Imports full (network, injection, persistence APIs)
  • CFG reconstructable
  • Compare hash of unpacked vs packed

Common Pitfalls

  • Dumping too early (before full decompression) — incomplete code
  • Dumping too late (after stub cleans up) — missing imports
  • Not fixing imports — dumped binary won't run/analyze correctly
  • Missing the OEP — jumping to wrong address
  • Breaking on READ instead of WRITE to UPX0
  • Not setting breakpoint at correct point (before stub finishes)

Tools

  • x64dbg + Scylla (dump + IAT fix)
  • OllyDbg + OllyDump
  • PE-bear / CFF Explorer (SizeOfImage, sections)
  • Detect It Easy (packer ID)
  • upx -d (for UPX only)
  • LordPE (dump)
  • Procmon (dynamic observation)

References

  • Lesson AR1: Packers & Unpacking
  • Lesson M4: Obfuscation & Packing
  • UPX Documentation (decompression stub analysis)
  • Scylla x64dbg plugin guide
  • Manual unpacking tutorials (x64dbg)

Extensions & Challenges

  • Unpack a real UPX sample with x64dbg + Scylla, compare to `upx -d` output
  • Analyze the UPX decompression stub — how does it work?
  • Research: How to unpack a modified UPX (corrupted headers)?
  • Build a Ghidra script to auto-detect UPX stub patterns
  • Practice: Unpack ASPack/Themida/VMProtect samples
  • Write a YARA rule for UPX stub + compressed payload signature