Unpacking
Analysis
Packers compress and obfuscate executables to evade detection. Unpacking recovers the original code for analysis.
Isolate Before You Analyse
Every step below executes the sample. Never unpack unknown malware on a production or networked host:
use a dedicated virtual machine with no shared folders or clipboard and with a host-only adapter or no
networking, and snapshot it before execution so you can revert. Assume the sample may be evasive enough
to detect the debugger or VM and destructive enough to damage the guest — the unpacking stub is often
where both behaviours are decided.
UPX Unpacking
upx-unpack.sh
# UPX - Most common packer
# Detect UPX
file packed.exe
# Output: PE32 executable, UPX compressed
# Unpack with UPX
upx -d packed.exe -o unpacked.exe
# Modified UPX stubs reject -d; fall back to the manual process below
# Common UPX indicators:
# - Section names: UPX0, UPX1
# - Small .text section, large UPX1 section
# - Entry point in UPX1 sectionManual Unpacking Process
The same five steps cover almost every custom packer; only the tells in the first step change:
-
Identify the packer. Look for section names that are not compiler defaults, sections
whose entropy is near-random, an entry point outside
.text, and an import table holding little more thanLoadLibraryandGetProcAddress. Confirm against a signature database with Detect It Easy (DIE) or pestudio. -
Find the original entry point. Break on
VirtualAllocandVirtualProtectto catch the stub allocating memory and marking it executable, then follow the writes into that region. The tail jump is the transfer out of the stub and into the code it has just written. - Dump at the OEP. With execution stopped at the original entry point, use the Scylla plugin inside x64dbg to dump the image from process memory rather than from disk.
- Rebuild the import table. The dumped image points at the stub's resolved addresses, so run IAT Autosearch, then Get Imports, then Fix Dump to write a working import directory back into the copy.
- Verify the result. Check section permissions and headers in PE-bear, and confirm the dump loads in a disassembler without unresolved imports.
Breakpoint Strategy
Break on the stack pointer rather than hunting for the tail jump by eye. On 32-bit packers the stub
typically saves every register with
PUSHAD and
restores them with
POPAD immediately
before the jump, so a hardware breakpoint on esp
taken after the save fires on the restore — which lands you at the OEP jump.
PUSHAD and
POPAD are 32-bit
only instructions: 64-bit packers save registers one at a time instead, so break on writes to
rsp in the stub
and on VirtualProtect
for that case.