When to use / When not to use
- Use: when you get an unknown sample, first confirm whether it is packed and determine the packer name to choose an unpacking path; static triage finds high entropy / abnormal section names / extremely small import table (see [[re-triage]] output) and further confirmation is needed
- Use: before dynamic analysis to determine "whether the observed behavior is the packer's or the program's"
- Don't use: the target is already a clean sample, directly inspect the logic (go to [[re-binary-core]])
- Don't use: the exact packer name is already known and only the unpacking action remains (directly [[re-unpack-simple]] / [[re-unpack-advanced]], the identification step can be skipped)
- Note:Failure to identify ≠ no packer(incomplete signature library / niche packer), use feature combinations to judge, and if necessary follow the manual process for an unknown packer
Tool preparation
Static identification can be sandbox-free ([[re-analyze/platform-tips]] highest principle: static analysis can be sandbox-free); verify tools before use.
Detect It Easy (DIE, cross-platform main tool)
- Linux: official GitHub release
Horsicq/Detect-It-Easydownloaddie_lin64_portable_<ver>.tar.gzextract and use (CLIdiec/ GUIdie); Debian/Ubuntu can alsoapt install die(the repository version is older; use the official version when the signature library is incomplete) - macOS:
brew install --cask detect-it-easy - Windows: official release
die_win64_portable_<ver>.zipextract, GUIdie.exe/ CLIdiec.exe - Verify:
diec --version
PEiD (Windows veteran tool, supplements DIE)
- Windows-only (can also run under Wine): download PEiD 0.95 (GitHub mirror), recommended with
PEiD 0.96/0.97signature library update package; use it for cross-validation when DIE cannot identify - Verify: open PEiD and load the sample to display the packer name / entry point features
file / strings (initial features)
- Linux:
apt install file binutils/dnf install file binutils/pacman -S file binutils - macOS: bundled with Xcode Command Line Tools (
xcode-select --install) - Windows/WSL: use the Linux package inside WSL
- Verify:
file --version、strings --version
Entropy calculation (mainly python3, ent/binwalk optional)
- python3:
apt install python3/ bundled with most systems; verifypython3 --version - ent (optional):
apt install ent/brew install ent; verifyent(prints usage with no arguments) - binwalk (optional, entropy graph): for installation see [[re-fw-extract]]; verify
binwalk -E sample.exe | head
pefile (optional, PE section/EP/import table script)
- All platforms:
pip install pefile - Verify:
python3 -c "import pefile"
Procedure
Execute in order and record the results of each step (evidence path + sha256, see [[re-triage]]). The identification conclusion (packer name / unknown packer / no packer + OEP clues) is the input for the unpacking path.
-
Initial feature collection (file/strings):
file sample.exe sha256sum sample.exe strings -n 6 sample.exe | head -30Packed samples usually: very few readable strings, packer signatures near the EP (the UPX header has the
UPX!magic, ASPack and other section name features); clean samples have abundant strings. -
Signature library scanning (DIE/PEiD):
diec sample.exe # CLI 扫描;GUI 用 diePEiD (Windows): drag in the sample and look at the four columns of signatures: packer name / Entrypoint / Section / Overlay. Results fall into three grades:clear packer name(UPX 0.89~3.xx / ASPack / FSG / VMProtect…)、suspicious features(only entry point or section name hit),unidentified. Unidentified does not mean clean (see pitfall 1).
-
Abnormal section name check:
objdump -h sample.exe | head -30Features:
UPX0/UPX1、.aspack、.adata、.petite, an all-uppercase custom section name, an anomalous section table count or ordering. Section names can be disguised as.text/.data(see pitfall 2), and even if the section names look normal, you still need to combine steps 4-6. -
Entry point target check (whether the EP is in a non-first section):
objdump -f sample.exe # 看 start address python3 - <<'EOF' import pefile pe = pefile.PE('sample.exe') ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint for s in pe.sections: va, vs = s.VirtualAddress, s.Misc_VirtualSize if va <= ep < va + vs: print("EP 位于节:", s.Name.rstrip(b'\x00').decode(), hex(va)) EOFIn a normal PE, the EP points to the first section
.text;EP pointing to a non-first section / writable section → strong packer indicator。 -
Entropy > 7 check:
ent sample.exe # 整文件熵(可选) binwalk -E sample.exe | head -20 # 熵分布图,高熵段 = 压缩/加密 python3 - <<'EOF' import math, collections d = open('sample.exe','rb').read() c = collections.Counter(d); n = len(d) h = -sum((v/n) * math.log2(v/n) for v in c.values()) print(f"entropy = {h:.3f} bits/byte") EOFEntropy > 7.0 bits/byte → suspected packing/encryption; per-section entropy is more meaningful (a mixed distribution with a high-entropy packer section and a low-entropy code section is also a packer indicator).
-
Very small import table indicator:
objdump -p sample.exe | grep -A6 'DLL Name' | head -20Normal PEs import hundreds to thousands of APIs; packed PEs often import only
kernel32.dllofLoadLibraryA/GetProcAddressand a few other APIs (the rest are resolved dynamically at runtime). Very small import table + high entropy → packing can almost certainly be concluded. -
Record OEP clues first (do it during the identification phase, don't wait until unpacking):
objdump -d sample.exe | sed -n '1,20p' # EP 附近指令The entry of a simple compression packer often begins with
pushad/pusha(the premise of the ESP law); the entry of a strong packer is often in the formpush imm32; mov reg, imm; jmp vm_handler.Record the entry instruction sequence and entry address, and use them directly as breakpoints and the basis for OEP determination during unpacking.
Cross-domain combination
- [[re-anti-analysis]]: step 1 of the workflow (packer identification) always invokes this skill; the identification conclusion determines the unpack-simple / unpack-advanced branch
- Invoked by the triage "sample is packed / unpack" path in [[re-analyze]] (re-anti-analysis → re-packer-id)
- [[re-malware]]: for packed samples, identify the packer first before deciding the unpacking path
- [[re-mobile]] / [[re-apk]]: after hardening identification, confirm the packer category (Android hardening packer)
- [[re-triage]]: when entropy is anomalous / section names are suspicious, switch to this skill for confirmation
- [[re-crypto-id]]: packer-layer constants contaminate fingerprints—identify the packer first, unpack, then do constant-table fingerprinting
- Identified as a strong packer / unknown packer → [[re-unpack-advanced]]; simple compression packer → [[re-unpack-simple]]; no packer → switch back to [[re-binary-core]]
Common pitfalls and traps
- Incomplete signature database → miss new packers: Symptom—DIE/PEiD reports "Not found", but the sample has entropy 7.8 and only 3 APIs in the import table; Cause—private / niche packers are not in the signature database; Countermeasure—do not rely on a single signature, use the four-feature combination of section names + EP + entropy + import table to judge, and if it is judged an "unknown packer", follow the manual unpacking workflow
- Disguised section names: Symptom—the section names are all
.text/.dataand show no anomaly, but entropy is high and the EP points to the second section; Cause—the packer deliberately renames the section table; Countermeasure—treat section names only as clues, not as evidence, and cross-validate the EP location + entropy + import table - Packer nesting: Symptom—identified as UPX but after
upx -dis unpacked,filestill reports packer indicators; Cause—multi-layer packing (e.g., Themida wrapped inside UPX); Countermeasure—unpack one layer, re-identify one layer,recheck the four elements layer by layer in a loop: PE header (new EP location / section table structure / header fields), section names (whether new packer section characteristics appear), entropy distribution (whether there are new high-entropy sections), import table (whether it is still extremely small / only GetProcAddress dynamic calls remain)—only when all four elements are normal is it considered fully unpacked; if any item is anomalous, go back to this skill and run it again - Not recording OEP clues during the identification phase: Symptom — when unpacking reaches the halfway point and you need the "packer entry instruction / EP address," you're in a scramble, and breakpoint locations are all guesswork; Cause — it wasn't recorded during identification; Countermeasure — in step 7, record the entry instruction (pushad, etc.) and address during the identification phase, for direct use with the ESP law
- Identifying the packer name ≠ all packer options enabled: Symptom — when DIE reports VMProtect/Themida, you default to running the full strong-packer workflow, even though the actual sample is just simple compression or virtualization isn't enabled; Cause — the packer name only indicates "what packer was applied"; whether virtualization/anti-debugging is enabled is a build-time configuration option; Countermeasure — the identification report should include version and configuration clues (
.vmp0/.vmp1/.themidawhether the section exists, whether the entry is a VM dispatch type or a normal stub, bitness), leaving it to [[re-anti-analysis]] to decide whether to follow the [[re-unpack-simple]] or [[re-unpack-advanced]] workflow - Automated unpacking tools are sensitive to version/bitness: Symptom — automated tools such as x64Unpack/Magicmida have no effect on the target, and the dump is corrupted; Cause — unpackers are implemented for specific packer versions and bitness (Magicmida only supports 32-bit and does not fix VM reverse dumps; x64Unpack has only been verified against Themida 2.4.6/VMProtect 3.4); Countermeasure — during the identification phase, record the packer name + version + bitness (DIE version field/deep scan), check the support matrix before choosing a tool, and if unsupported, follow the manual workflow