Static Analysis
- Static Analysis
Static analysis is the examination of a binary without executing it. It is the safest form of analysis and often yields a great deal of information with no risk of infection.
File Identification and Triage
Before deep analysis, perform quick triage to understand what you’re working with.
File Type Identification
The file command reads magic bytes to identify file type regardless of extension:
$ file sample.exe
sample.exe: PE32 executable (GUI) Intel 80386, for MS Windows
$ file sample
sample: ELF 64-bit LSB executable, x86-64, dynamically linked
Hashing
Always compute and record hashes before analysis. The hash serves as the unique identifier for the sample.
$ sha256sum sample.exe
$ md5sum sample.exe # legacy, but still used in threat intel feeds
$ ssdeep sample.exe # fuzzy hash — useful for finding similar samples
String Extraction
The strings command extracts printable ASCII/Unicode sequences. This often reveals URLs, file paths, registry keys, error messages, and C2 addresses embedded in plaintext.
$ strings -n 6 sample.exe | less # minimum length 6
$ strings -el sample.exe | less # 16-bit little-endian (common in Windows)
FLOSS (FireEye Labs Obfuscated String Solver) goes further by also recovering stack strings, encoded strings, and tight loops that concatenate characters:
$ floss sample.exe
PE File Format (Windows)
The Portable Executable (PE) format is used by Windows executables (.exe, .dll, .sys). Understanding the structure is essential for static analysis.
PE Structure Overview
┌──────────────────────┐
│ DOS Header │ MZ magic bytes, legacy stub
├──────────────────────┤
│ PE Header (COFF) │ machine type, section count, timestamps
├──────────────────────┤
│ Optional Header │ entry point, image base, subsystem, data directories
├──────────────────────┤
│ Section Table │ .text, .data, .rsrc, .rdata, ...
├──────────────────────┤
│ Sections │ actual code and data
└──────────────────────┘
Examining the PE with pev
The pev toolkit provides focused views of PE structure:
$ pestr sample.exe # strings with offset and section
$ pehash sample.exe # multiple hash types
$ pepack sample.exe # packing detection (entropy, section names)
$ pesec sample.exe # security features (ASLR, DEP, CFG, SafeSEH)
$ pedis sample.exe # disassemble entry point region
$ peres sample.exe # resource section contents
Imports and Exports
The Import Address Table (IAT) lists functions the binary calls from external DLLs. This is one of the most valuable pieces of static information:
$ objdump -p sample.exe | grep -A 100 "Import"
Common suspicious import patterns:
| Category | Functions |
|---|---|
| Process injection | VirtualAllocEx, WriteProcessMemory, CreateRemoteThread |
| Persistence | RegSetValueEx, CreateService, SHGetSpecialFolderPath |
| Network | WSAStartup, connect, InternetOpen, HttpSendRequest |
| Crypto | CryptEncrypt, CryptHashData, BCrypt APIs |
| Anti-analysis | IsDebuggerPresent, GetTickCount, QueryPerformanceCounter |
ELF File Format (Linux)
ELF (Executable and Linkable Format) is used on Linux and most Unix-like systems.
$ readelf -h sample # ELF header (architecture, entry point, etc.)
$ readelf -S sample # section headers
$ readelf -d sample # dynamic section (shared library dependencies)
$ readelf -s sample # symbol table (if not stripped)
$ nm sample 2>/dev/null # symbol names (works on unstripped binaries)
$ objdump -d sample | less # disassembly
Disassembly and Decompilation
We use two tools depending on the binary format:
- IDA Classroom (free educational IDA Pro) — primary tool for PE/Windows analysis
- Cutter (Rizin GUI) — primary tool for ELF/Linux analysis; rizin and radare2 are the underlying CLI tools
IDA Classroom — PE Workflow
- Launch
ida64(64-bit) orida(32-bit) - Open the binary; accept auto-analysis
- Navigate to
mainvia the Functions window or the Imports tab - Press
F5in any function to open the Hex-Rays pseudocode decompiler - Press
Nto rename functions and variables; press;for comments - Press
Xon any name to show all cross-references
IDA’s type library contains all standard Windows API definitions — argument names and types appear automatically for known functions.
Cutter / Rizin / radare2 — ELF Workflow
Rizin is a community fork of radare2 with a cleaner API; Cutter is its GUI. Both tools share the same command vocabulary — commands from one work in the other.
Launch cutter, open the binary, and accept the analysis defaults. The Console pane accepts Rizin commands directly:
# Rizin CLI (preferred) or radare2 CLI (compatible):
$ rizin -A sample # rizin
$ r2 -A sample # radare2 (same result)
[0x00401000]> afl # list all functions
[0x00401000]> pdf @main # disassemble main
[0x00401000]> pdg @main # decompile main (rz-ghidra)
[0x00401000]> iz # strings in data sections
[0x00401000]> ii # imports
Entropy Analysis
High-entropy sections indicate packed, encrypted, or compressed data:
$ binwalk -E sample.exe
A .text section with entropy > 7.0 is a strong indicator of packing. In Cutter, the Dashboard shows a per-section entropy bar chart.
Useful Resources
- Practical Malware Analysis — Sikorski & Honig (the standard textbook)
- PE Format reference
- IDA Classroom registration
- Cutter documentation
- Rizin documentation
- radare2 book