Advanced Static Analysis
Deep dive into advanced static analysis techniques including IDA Pro disassembly, Ghidra decompilation, and identifying malicious code patterns without executing the binary.
Contents
- 1. Tool Selection — Which Disassembler to Use
- 2. Loading a Binary into Cutter / Ghidra
- Cutter Workflow
- Ghidra Workflow
- 3. Identifying Key Functions
- Finding main()
- Recognizing Important Functions
- 4. Control Flow Analysis
- Reading the Graph View
- Common Patterns in Graph View
- 5. String Analysis in Disassemblers
- Where to Find Strings
- What Strings Reveal
- 6. Import & Export Analysis
- Imports Table
- Suspicious Import Combinations
- Exports Table
- 7. Cross-References (XREF) Analysis
- Why XREFs Matter
- 8. Identifying Packed / Obfuscated Binaries
- Signs of Packing
- Common Packers
- Entropy Analysis
- 9. Advanced Techniques
- Identifying Encryption Algorithms
- Reconstructing Structures
- Patching Binaries
- 10. Static Analysis Workflow Checklist
- Pro Tips
Advanced Static Analysis
Goal: Understand what a binary does without ever running it — using disassemblers, decompilers, and manual code analysis.
1. Tool Selection — Which Disassembler to Use
| Tool | Type | Best For | Cost |
|---|---|---|---|
| Ghidra | Disassembler + Decompiler | Full RE, malware, CTF | Free (NSA) |
| IDA Pro | Disassembler + Decompiler | Industry standard, best x86 analysis | $$$$ |
| IDA Free | Disassembler only | Quick disassembly, no decompiler | Free |
| Cutter / Rizin | Disassembler + Decompiler (r2-based) | Lightweight, Linux-friendly, CTF | Free |
| Binary Ninja | Disassembler + Decompiler | Clean UI, good HLIL | $$ |
| x64dbg | Debugger (dynamic) | Runtime analysis on Windows | Free |
| radare2 | CLI Disassembler | Scripting, automation, CTF | Free |
2. Loading a Binary into Cutter / Ghidra
Cutter Workflow
- Open Cutter and load
FileName.exe - Select analysis options (keep defaults for most malware)
- Wait for auto-analysis to complete
- Locate the main function — this is the entry point of the program
- Switch between Disassembly, Graph, and Decompiler views
Ghidra Workflow
- Create a new project → Import File → select the binary
- Double-click the file → opens CodeBrowser
- Say Yes to auto-analysis when prompted
- Navigate to
entry→ follow call to__libc_start_main→ first argument =main - Use the Decompile window (right panel) to read pseudo-C code
3. Identifying Key Functions
Finding main()
- PE (Windows): Look for
entry→__mainCRTStartup→mainorWinMain - ELF (Linux):
entry→__libc_start_main(main, argc, argv, ...)— first arg ismain - Stripped binaries: No symbol names — look for the function called by the entry stub
Recognizing Important Functions
| What You See | What It Probably Does |
|---|---|
CreateFile / WriteFile | File operations (dropper, ransomware) |
VirtualAlloc + memcpy | Shellcode unpacking/injection |
socket / connect / send / recv | Network C2 communication |
RegSetValueEx | Registry persistence |
CreateProcess / ShellExecute | Spawning child processes |
CryptEncrypt / CryptDecrypt | Crypto operations (ransomware) |
| XOR loops in a tight function | Custom encryption / obfuscation |
LoadLibrary + GetProcAddress | Dynamic API resolution (evasion) |
IsDebuggerPresent | Anti-debugging check |
4. Control Flow Analysis
Reading the Graph View
The graph view (CFG — Control Flow Graph) shows basic blocks connected by arrows:
- Green arrow = conditional branch TAKEN (true)
- Red arrow = conditional branch NOT TAKEN (false)
- Blue arrow = unconditional jump
Common Patterns in Graph View
If/Else:
[cmp eax, 0]
/ \
[jne] [je]
| |
[block A] [block B]
\ /
[continue]
While Loop:
[condition check] <----+
| |
[loop body] --------+
|
[exit loop]
Switch/Case:
[cmp/ja → jump table]
/ | | | \
[c0][c1][c2][c3][default]
5. String Analysis in Disassemblers
Where to Find Strings
- Ghidra: Window → Defined Strings (or
Search → For Strings) - Cutter: Strings panel (izz/iz)
- IDA: View → Open Subviews → Strings (Shift+F12)
What Strings Reveal
| String Pattern | Intelligence |
|---|---|
http://, https:// | C2 server URLs |
cmd.exe, /bin/sh | Shell command execution |
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run | Persistence registry key |
password, credential, login | Credential stealer |
encrypt, decrypt, AES, RSA | Crypto/ransomware |
Base64 blobs (= padding) | Encoded payloads or configs |
mutex_, Global\ | Mutex for singleton check |
| Error messages with developer paths | Developer machine info leak |
.onion, tor | Tor-based C2 |
6. Import & Export Analysis
Imports Table
The Import Address Table (IAT) tells you which DLL functions the binary uses statically:
In Ghidra: Window → Symbol Table → filter by “EXTERNAL”
In Cutter: Imports panel
In IDA: View → Open Subviews → Imports
Suspicious Import Combinations
| Import Combination | Likely Behavior |
|---|---|
VirtualAllocEx + WriteProcessMemory + CreateRemoteThread | Process injection |
OpenProcess + ReadProcessMemory | Memory reading (credential theft) |
InternetOpenA + InternetConnectA + HttpSendRequestA | HTTP C2 |
WSAStartup + socket + connect | Raw socket C2 |
CryptAcquireContext + CryptEncrypt | Encryption (ransomware) |
Only LoadLibrary + GetProcAddress | Dynamic resolution — hiding real API usage |
NtQuerySystemInformation | Anti-analysis / system enumeration |
Exports Table
- Legitimate DLLs export functions for other programs to use
- Malicious DLLs often export functions like
DllMain,ServiceMain, or names that mimic legit software - Look for exported functions with suspicious names or ordinals-only exports
7. Cross-References (XREF) Analysis
Cross-references show who calls a function and what a function calls:
- Ghidra: Right-click → References → Show References To
- IDA: Press
xon any function/address - Cutter: Right-click → Show X-Refs
Why XREFs Matter
- Find all callers of
VirtualAlloc→ trace shellcode allocation - Find all callers of
send()→ trace C2 exfiltration - Find what calls a decryption function → trace payload unpacking
- Dead code (functions with 0 XREFs) → possibly unused or dynamically resolved
8. Identifying Packed / Obfuscated Binaries
Signs of Packing
| Indicator | What It Means |
|---|---|
Very few imports (only LoadLibrary, GetProcAddress) | Packed — real imports resolved at runtime |
Section names like .upx0, .aspack, .themida | Known packer sections |
| High entropy (>7.0) in sections | Compressed/encrypted data |
| Virtual size >> raw size in PE sections | Unpacking will expand data in memory |
Entry point in non-standard section (not .text) | Stub executes before real code |
| Very few strings | Strings encrypted or compressed |
Common Packers
| Packer | Detection | Unpacking |
|---|---|---|
| UPX | upx -t file.exe, section names .UPX0/.UPX1 | upx -d file.exe |
| ASPack | PEiD, Detect It Easy | Manual or ASPackDie |
| Themida | PEiD, section .themida | Very hard, use dynamic analysis |
| VMProtect | .vmp sections, virtualized code | Extremely hard |
| Custom packers | No signature match, weird entropy | Dump from memory at OEP |
Entropy Analysis
- Normal code (.text section): entropy ~5.0–6.5
- Packed/encrypted: entropy ~7.0–8.0
- Use Detect It Easy (DiE) or pestudio for entropy visualization
9. Advanced Techniques
Identifying Encryption Algorithms
- Look for magic constants:
0x67452301,0xEFCDAB89→ MD50x6A09E667→ SHA-256- Rijndael S-box (
0x63, 0x7C, 0x77, 0x7B...) → AES 0x9E3779B9→ TEA/XTEA
- Ghidra: Use
FindCryptplugin to auto-detect crypto constants - IDA: Use
FindCrypt2orSignsrch
Reconstructing Structures
- Identify clusters of data accesses at fixed offsets from a base pointer
- Create a struct in Ghidra: Data Type Manager → right-click → New Structure
- Apply the struct to the pointer → code becomes readable
Patching Binaries
- Ghidra: Right-click instruction → Patch Instruction → Export patched binary
- Cutter: Edit → Patch → write bytes
- Common patches:
NOPout anti-debug checks, changeJEtoJMPto skip password checks
10. Static Analysis Workflow Checklist
□ 1. File identification (file, DIE, PEiD)
□ 2. Check if packed → unpack if needed
□ 3. Hash the sample (MD5/SHA256) → check VirusTotal
□ 4. Extract strings (strings/FLOSS)
□ 5. Analyze imports/exports → categorize behavior
□ 6. Load into disassembler (Ghidra/IDA/Cutter)
□ 7. Find entry point → locate main()
□ 8. Read decompiled code for high-level understanding
□ 9. Follow XREFs for critical functions
□ 10. Identify crypto, C2, persistence, injection
□ 11. Extract IOCs (IPs, domains, file paths, registry keys)
□ 12. Document findings → write report
Pro Tips
Rename everything — As you identify functions, rename them (
decrypt_payload,connect_c2,inject_shellcode). Future you will thank present you.
Comment liberally — Add comments in the disassembler for every discovery. Analysis is iterative.
Cross-reference with dynamic analysis — Static tells you what CAN happen. Dynamic tells you what DOES happen. Use both.
Use YARA rules — Write YARA signatures from your static findings to detect variants of the same malware family.