Obfuscation and Packing
Malware hides its real logic to hinder analysis and evade signature-based detection. Two main techniques: obfuscation (transforming code/strings so they’re unreadable but functionally the same) and packing (compressing/encrypting the whole executable, which only decompresses in memory at runtime). For the analyst, deobfuscating and unpacking is the step before understanding the sample; for the defender, both techniques break simple static signatures.
Packing (executable packing/encryption)
Section titled “Packing (executable packing/encryption)”# a packer wraps the original binary: on disk you see the "stub" + encrypted data;# at runtime, the stub decompresses/decrypts the real code in memory and jumps to it (OEP)# signs of packing (static):- high entropy in sections (encrypted/compressed data)- few imports (resolved at runtime), tiny IAT- odd section names (UPX0, .packed) or RWX sections- almost no strings statically but many at runtime# detection toolsDetect It Easy (DIE), PEiD, PEstudio -> identify the packerUnpacking
Section titled “Unpacking”# standard packersupx -d sample.exe # UPX (if not modified)# custom/commercial packers (VMProtect, Themida, ...) -> dynamic:1. run under a debugger until the OEP (after unpacking in memory)2. dump the now-unpacked process (see rev-dynamic) pe-sieve / Scylla / Process Hacker -> dump3. rebuild the IAT and analyze the dump statically# automated: sandboxes (CAPE) often dump the unpacked payloadCode obfuscation
Section titled “Code obfuscation”control flow flattening flatten the flow -> the graph is unreadableopaque predicates always-T/F conditions that confuse analysisdead code / junk junk instructionsAPI hashing instead of API names, hashes resolved at runtime -> breaks import-based analysis (you must resolve the hashes)code virtualization a custom interpreter runs custom bytecode (the hardest)API hashing is very common: the malware doesn’t import VirtualAlloc by name (which would be an IOC), but computes a hash of the name and resolves it at runtime, hiding which APIs it uses from static analysis.
String obfuscation
Section titled “String obfuscation”# encrypted/stacked strings built at runtime# static: FLOSS extracts them (see mal-static); or locate the decryption routine# dynamic: run and dump memory -> the strings appear decryptedScript obfuscation (PowerShell/JS/VBA)
Section titled “Script obfuscation (PowerShell/JS/VBA)”# techniques: base64, concatenation, character replacement, compression (Gzip/Deflate),# indirect invocation (IEX), environment variables, encoding# deobfuscate:- CyberChef (the swiss-army knife: base64, gunzip, XOR, etc. chained)- PowerShell: replace IEX with Write-Output to SEE the script instead of running it- box-js / malware-jail for JavaScript; olevba for VBA# Script Block Logging (4104) captures the already-deobfuscated PowerShell (see fund-ps)For the defense
Section titled “For the defense”- Behavior detection (not static signature): obfuscation/packing breaks signatures, but runtime behavior (injection, network, encryption) is still EDR-detectable.
- AMSI / Script Block Logging: capture scripts after deobfuscation (the key moment).
- YARA rules over memory (not just disk): the unpacked sample in memory does have signatures (YARA Rules).
- Detection of packers/high entropy and API hashing as suspicious signals.
Testing checklist
Section titled “Testing checklist”- Detect packing (entropy, few imports, DIE/PEiD)
- Unpack (UPX -d; or dynamic: OEP + dump)
- Rebuild IAT and analyze the dump
- Identify code obfuscation (flattening, API hashing)
- Resolve API hashing (scripts/plugins)
- Extract obfuscated strings (FLOSS / memory dump)
- Deobfuscate scripts (CyberChef, olevba, Script Block Logging)
- YARA over memory after unpacking (YARA Rules)