Extracting & Analyzing VBA Macros (olevba, oledump)
oletools -- The Essential Toolkit
The oletools Python package by Philippe Lagadec is the industry-standard toolkit for analyzing malicious Office documents. It provides a comprehensive set of utilities:
| Tool | Purpose | When to Use |
|---|---|---|
| olevba | Extract and analyze VBA macros | First-pass macro analysis |
| oledump.py | Analyze OLE2 streams (Didier Stevens) | Deep stream-level inspection |
| oleid | Quick risk indicator check | Initial triage |
| rtfobj | Extract embedded objects from RTF | RTF file analysis |
| oleobj | Extract embedded OLE objects | Embedded payload extraction |
| msodde | Detect DDE links | DDE-based attacks |
| mraptor | Detect auto-executing macros | Quick auto-exec detection |
# Install oletools
pip install oletools
# Verify installation
olevba --help
oledump.py --help
olevba -- VBA Macro Extraction and Analysis
Basic Usage
# Extract and display all VBA macro source code
olevba suspicious.doc
# Quick detection only (no extraction)
olevba --detect suspicious.doc
# Decode obfuscated strings and show analysis
olevba --decode suspicious.doc
# Reveal all VBA code including hidden attributes
olevba --reveal suspicious.doc
# Analyze an OOXML file (works the same way)
olevba suspicious.docm
Understanding olevba Output Structure
olevba output has three sections:
Section 1: OLE/VBA Information
olevba 0.60.2 - https://decalage.info/oletools
FILE: suspicious.doc
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls
in file: suspicious.doc - OLE stream: 'Macros/VBA/ThisDocument'
Section 2: VBA Source Code (the actual macro code is printed here)
Section 3: Keyword Analysis Summary
+----------+--------------------+---------------------------------------------+
|Type |Keyword |Description |
+----------+--------------------+---------------------------------------------+
|AutoExec |AutoOpen |Runs when the Word document is opened |
|AutoExec |Document_Open |Runs when the Word document is opened |
|Suspicious|Shell |May run an executable file or a system cmd |
|Suspicious|WScript.Shell |May run an executable file or a system cmd |
|Suspicious|powershell |May run PowerShell commands |
|Suspicious|CreateObject |May create an OLE object |
|Suspicious|Environ |May read system environment variables |
|Suspicious|Hidden |May hide the application |
|IOC |http://cdn.evil[.]c |URL (potential C2 or payload source) |
|Hex String|48656C6C6F |Hex-encoded string |
|Base64 |cG93ZXJzaGVsbA== |Base64 encoded string (decoded: powershell) |
+----------+--------------------+---------------------------------------------+
olevba Keyword Categories Explained
| Category | Meaning | Analyst Action |
|---|---|---|
| AutoExec | Macro runs automatically on open/close | Identify the trigger mechanism |
| Suspicious | Dangerous VBA keywords detected | Trace how these are used in the code |
| IOC | URLs, IPs, file paths found | Add to IOC list immediately |
| Hex Strings | Hex-encoded data in the macro | Decode and analyze the content |
| Base64 Strings | Base64-encoded payloads | Decode and check for commands/PE files |
| Dridex | Dridex-style obfuscation patterns | Apply Dridex-specific deobfuscation |
| VBA Stomping | P-code differs from VBA source | Extract P-code with pcodedmp for truth |
oledump.py -- Stream-Level Analysis
Didier Stevens' oledump.py provides granular control over OLE2 stream inspection. While olevba gives you the big picture, oledump lets you examine individual streams at the byte level.
Listing All Streams
# List streams with the -i (info) parameter for details
oledump.py suspicious.doc -i
# Example output:
# 1: 114 '\x01CompObj'
# 2: 4096 '\x05DocumentSummaryInformation'
# 3: 4096 '\x05SummaryInformation'
# 4: 7427 '1Table'
# 5: 489 'Macros/PROJECT'
# 6: 65 'Macros/PROJECTwm'
# 7: M 6947 'Macros/VBA/NewMacros'
# 8: m 985 'Macros/VBA/ThisDocument'
# 9: 7117 'Macros/VBA/_VBA_PROJECT'
# 10: 574 'Macros/VBA/dir'
Stream Markers
| Marker | Meaning |
|---|---|
| M | Stream contains VBA macro source code |
| m | Stream references VBA macro code (attribute stream) |
| E | Stream contains an executable or PE file |
| O | Stream contains an OLE embedded object |
| (none) | Stream has no special markers |
Extracting Macro Code
# Extract a specific VBA macro stream (decompressed)
oledump.py -s 7 -v suspicious.doc
# Extract ALL macro streams at once
oledump.py -s a -v suspicious.doc
# Extract and pipe through grep to remove comments
oledump.py -s 7 -v suspicious.doc | grep -v "^Attribute "
# Dump raw bytes from a stream (for binary analysis)
oledump.py -s 7 -d suspicious.doc > stream7.bin
Using oledump Plugins
oledump supports plugins for advanced analysis:
# Use the VBA decompression plugin
oledump.py -p plugin_vba_dco.py suspicious.doc
# Use the strings plugin on a specific stream
oledump.py -s 7 -S suspicious.doc
Analyzing Obfuscated Macros
Real-world maldocs almost always use obfuscation to evade detection and slow analysis. Understanding common patterns is essential.
Obfuscation Technique 1: String Concatenation
' Instead of "powershell", build the string dynamically
Dim cmd As String
cmd = "pow" & "ersh" & "ell" & " -w hi" & "dden -ep by" & "pass"
Obfuscation Technique 2: Chr() Encoding
' Each character encoded as its ASCII value
Dim s As String
s = Chr(112) & Chr(111) & Chr(119) & Chr(101) & Chr(114) & _
Chr(115) & Chr(104) & Chr(101) & Chr(108) & Chr(108)
' Resolves to: "powershell"
Deobfuscation helper -- Use numbers-to-string.py (Didier Stevens):
echo "112 111 119 101 114 115 104 101 108 108" | numbers-to-string.py
# Output: powershell
Obfuscation Technique 3: Array-Based URL Assembly
' URLs split across an array, reassembled at runtime
Dim urls(2) As String
urls(0) = "hXXp://cdn" & ".update" & "-srv[.]com/payload"
urls(1) = "hXXp://backup" & ".api-check[.]net/dl"
urls(2) = "hXXp://static" & ".res-cdn[.]org/get"
Deobfuscation approach -- Pipe olevba output through helper tools:
olevba suspicious.doc | grep -i "http" | re-search.py -n "https?://[^\"'\s]+"
Obfuscation Technique 4: UserForm Hidden Data
Attackers hide payloads in UserForm control properties (text boxes, labels, captions) that are not visible in the VBA editor code listing:
# olevba extracts UserForm strings automatically
olevba suspicious.doc | grep -A2 "UserForm"
# Check for Base64 strings hidden in form controls
olevba --decode suspicious.doc
Obfuscation Technique 5: Environment Variable Abuse
' Build paths from environment variables
Dim comspec As String
comspec = Environ("COMSPEC") ' Resolves to C:\Windows\system32\cmd.exe
Shell comspec & " /c " & payload, vbHide
Obfuscation Technique 6: ChrW and Multi-Byte Encoding
' Unicode-aware character encoding
Dim s As String
s = ChrW(104) & ChrW(116) & ChrW(116) & ChrW(112)
' Resolves to: "http"
Deobfuscation with numbers-to-string.py:
# Extract ChrW values and decode
olevba suspicious.doc | grep "ChrW" | numbers-to-string.py
Step-by-Step De-obfuscation Workflow
Step 1: EXTRACT macro code
olevba suspicious.doc > macro_code.txt
Step 2: IDENTIFY obfuscation patterns
- Search for Chr(), ChrW(), StrReverse(), Replace()
- Look for eval-like constructs: Shell, Exec, Run
- Check for Base64 strings and hex-encoded data
Step 3: RESOLVE simple substitutions
- Chr()/ChrW() -> use numbers-to-string.py
- String concatenation -> manually join strings
- StrReverse() -> reverse the string
- Replace() -> apply the replacement
Step 4: CHECK UserForms for hidden payloads
- olevba --decode automatically extracts form data
- Look for long Base64 strings in form controls
Step 5: TRACE execution flow
- Start at AutoOpen/Document_Open
- Follow function calls to identify the payload
- Map the full execution chain
Step 6: EXTRACT final IOCs
- URLs, IPs, domains
- File paths (dropped files, persistence)
- Registry keys
- Process names and command lines
ViperMonkey -- VBA Emulation Engine
For heavily obfuscated macros that resist static analysis, ViperMonkey can emulate VBA execution:
# Install ViperMonkey
pip install vipermonkey
# Emulate macro execution
vmonkey suspicious.doc
# Output shows:
# - Which functions were called
# - String values after deobfuscation
# - Shell commands that would be executed
# - Files that would be written
Pro Tip: ViperMonkey is not perfect -- it may fail on complex obfuscation. Use it as one tool in your arsenal alongside manual analysis.
Password-Protected VBA Projects
Some maldocs protect the VBA project with a password to prevent inspection:
# Method 1: Use olevba (ignores VBA password)
olevba protected.doc
# olevba can extract macros even from password-protected projects
# Method 2: Use evilclippy to remove protection
evilclippy -uu protected.doc
# Creates a new file with VBA project password removed
# Method 3: Hex-edit approach
# Find "DPB=" in the binary and change to "DPx="
# This corrupts the password hash, Office ignores it
Cobalt Strike Shellcode Detection in Macros
When macros contain shellcode (often Base64-encoded), use specialized tools to identify Cobalt Strike beacons:
# Extract Base64 payload from macro
olevba suspicious.doc | base64dump.py -s 1 -d > shellcode.bin
# Analyze with scdbg (shellcode emulator)
scdbg /f shellcode.bin
# Check for Cobalt Strike signatures
python 1768.py shellcode.bin
# Output: Cobalt Strike beacon config if detected
# Use YARA rules for Cobalt Strike detection
yara-rules/cobalt_strike.yar shellcode.bin
Deliverable Checklist
After analyzing a malicious document, your report should include:
- File hash (MD5, SHA256) and file type
- Macro trigger mechanism (AutoOpen, Document_Open, etc.)
- Full deobfuscated macro code with annotations
- Extracted payload description (downloader, dropper, etc.)
- Complete IOC list (URLs, IPs, file paths, registry keys)
- ATT&CK technique mapping
- Recommended detection signatures (YARA, Sigma)
ATT&CK Mapping
| Technique | ID | Relevance |
|---|---|---|
| Phishing: Spearphishing Attachment | T1566.001 | Delivery mechanism |
| User Execution: Malicious File | T1204.002 | Victim enables macros |
| Command and Scripting: VBA | T1059.005 | Macro execution |
| Obfuscated Files or Information | T1027 | Macro obfuscation |
| Deobfuscate/Decode Files | T1140 | Runtime string assembly |
| Ingress Tool Transfer | T1105 | Payload download |
