Install
$ agentstack add skill-mikaru0mystic-sectinel-analyzing-packed-malware-with-upx-unpacker ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Analyzing Packed Malware with UPX Unpacker
When to Use
- Static analysis reveals high entropy sections and minimal imports indicating the binary is packed
- PEiD, Detect It Easy, or PEStudio identifies UPX or another known packer
- The import table contains only LoadLibrary and GetProcAddress (runtime import resolution typical of packed binaries)
- You need to recover the original binary for proper disassembly and decompilation in Ghidra or IDA
- Automated UPX decompression fails because the malware author modified UPX magic bytes or headers
Do not use when dealing with custom packers, VM-based protectors (Themida, VMProtect), or samples where dynamic unpacking via debugging is more appropriate.
Prerequisites
- UPX (Ultimate Packer for eXecutables) installed (
apt install upx-uclor download from https://upx.github.io/) - Detect It Easy (DIE) for packer identification
- Python 3.8+ with
pefilelibrary for manual header repair - x64dbg or x32dbg for manual unpacking when automated tools fail
- PE-bear or CFF Explorer for PE header inspection and repair
- Isolated analysis VM without network connectivity
Workflow
Step 1: Identify the Packer
Determine if the sample is packed and identify the packer:
# Check with Detect It Easy
diec suspect.exe
# Check with UPX (test without unpacking)
upx -t suspect.exe
# Python-based entropy and packer detection
python3 8} Virtual: {virtual:>8}")
# Check for UPX section names
section_names = [s.Name.decode().rstrip('\x00') for s in pe.sections]
if 'UPX0' in section_names or 'UPX1' in section_names:
print("\n[!] UPX section names detected")
elif '.upx' in [s.lower() for s in section_names]:
print("\n[!] UPX variant section names detected")
# Check import count (packed binaries have very few)
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
total_imports = sum(len(e.imports) for e in pe.DIRECTORY_ENTRY_IMPORT)
print(f"\nTotal imports: {total_imports}")
if total_imports &1
# Verify the unpacked file
file unpacked.exe
diec unpacked.exe
Step 3: Repair Modified UPX Headers
If standard decompression fails, repair tampered magic bytes:
# Repair modified UPX headers
import struct
with open("suspect.exe", "rb") as f:
data = bytearray(f.read())
# UPX magic bytes: "UPX!" (0x55505821)
# Malware authors commonly modify these to prevent automatic unpacking
# Search for modified UPX signatures
upx_magic = b"UPX!"
modified_patterns = [b"UPX0", b"UPX\x00", b"\x00PX!", b"UPx!"]
# Find and restore section names
pe_offset = struct.unpack_from(" Follow in Dump
- Set hardware breakpoint on access at [ESP] address
- Run (F9) - breaks at POPAD before JMP to OEP
5. Step forward (F7/F8) until you reach the JMP to OEP
6. At OEP: Use Scylla plugin to dump and fix imports:
- Plugins -> Scylla -> OEP = current EIP
- Click "IAT Autosearch" -> "Get Imports"
- Click "Dump" to save unpacked binary
- Click "Fix Dump" to repair import table
Step 5: Validate Unpacked Binary
Verify the unpacked sample is valid and complete:
# Verify unpacked PE is valid
python3 10} bytes")
print(f"Unpacked: {unpacked_size:>10} bytes")
print(f"Ratio: {unpacked_size/packed_size:.1f}x")
PYEOF
Key Concepts
| Term | Definition | |------|------------| | Packing | Compressing or encrypting executable code to reduce file size and hinder static analysis; the binary contains an unpacking stub that restores code at runtime | | UPX | Ultimate Packer for eXecutables; open-source executable packer commonly abused by malware authors because it is free and effective | | Original Entry Point (OEP) | The real starting address of the malware code before packing; the unpacking stub decompresses code then jumps to the OEP | | Import Reconstruction | Process of rebuilding the import address table after dumping an unpacked process from memory using tools like Scylla or ImpRec | | PUSHAD/POPAD | x86 instructions that save/restore all general-purpose registers; UPX uses this pattern to preserve register state during unpacking | | Section Entropy | Randomness measure of PE section data; packed sections show entropy > 7.0 while normal code sections average 5.0-6.5 | | Magic Bytes | Signature bytes within a file identifying its format; UPX uses "UPX!" which malware authors modify to prevent automated decompression |
Tools & Systems
- UPX: Open-source executable packer with built-in decompression capability for properly packed files
- Detect It Easy (DIE): Packer, compiler, and linker detection tool that identifies protection on PE, ELF, and Mach-O files
- x64dbg/x32dbg: Open-source Windows debugger used for manual unpacking through dynamic execution and breakpoint-based OEP finding
- Scylla: Import reconstruction tool integrated with x64dbg for rebuilding IAT after memory dumping
- PE-bear: PE file viewer and editor for inspecting and repairing PE headers after unpacking
Common Scenarios
Scenario: Unpacking Malware with Modified UPX Headers
Context: A malware sample is identified as UPX-packed by section names (UPX0, UPX1) but upx -d fails with "CantUnpackException: header corrupted". The malware author modified the UPX magic bytes to prevent automated decompression.
Approach:
- Open the binary in a hex editor and search for the UPX header area (typically at the end of packed data)
- Identify the modified magic bytes (e.g., "UPX!" changed to "UPX\x00" or completely zeroed)
- Use the Python repair script to restore "UPX!" magic and correct section names
- Retry
upx -don the repaired binary - If repair fails, fall back to manual unpacking with x64dbg (PUSHAD -> hardware BP on ESP -> POPAD -> JMP OEP)
- Validate the unpacked binary has proper imports and reasonable entropy values
- Import into Ghidra or IDA for full static analysis
Pitfalls:
- Assuming UPX is the only packer; the binary may be double-packed (UPX + custom layer)
- Modifying the original packed sample instead of working on a copy
- Not reconstructing imports after manual memory dump (the dumped binary will crash without IAT fix)
- Forgetting to check for overlay data appended after the UPX-packed PE sections
Output Format
UNPACKING ANALYSIS REPORT
===========================
Sample: suspect.exe
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
Packer: UPX 3.96 (modified headers)
PACKED BINARY
Sections: UPX0 (entropy: 0.00) UPX1 (entropy: 7.89) .rsrc (entropy: 3.45)
Imports: 2 (kernel32.dll: LoadLibraryA, GetProcAddress)
File Size: 98,304 bytes
UNPACKING METHOD
Method: Header repair + UPX -d
Header Fix: Restored UPX! magic at offset 0x1F000
Command: upx -d suspect_fixed.exe -o unpacked.exe
Result: SUCCESS
UNPACKED BINARY
Sections: .text (entropy: 6.21) .rdata (entropy: 4.56) .data (entropy: 3.12) .rsrc (entropy: 3.45)
Imports: 147 (kernel32, user32, advapi32, wininet, ws2_32)
File Size: 245,760 bytes (2.5x expansion)
OEP: 0x00401000
VALIDATION
PE Valid: Yes
Imports Resolved: Yes (147 functions across 8 DLLs)
Executable: Yes (runs without crash in sandbox)
NEXT STEPS
- Import unpacked.exe into Ghidra for full disassembly
- Run YARA rules against unpacked binary
- Submit unpacked binary to VirusTotal for improved detection
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Mikaru0Mystic
- Source: Mikaru0Mystic/sectinel
- License: Apache-2.0
- Homepage: https://agentskills.io
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.