Dynamic Analysis (Wasabi)
WASMShark integrates Wasabi — an ASPLOS 2019 Best Paper dynamic instrumentation framework for WebAssembly — to confirm static analysis predictions with actual runtime evidence.
How It Works
Instrument — Wasabi inserts low-level hooks into every WASM instruction
Execute — The instrumented binary runs under Node.js with import stubs
Collect — WASMShark’s analysis hooks record runtime behavior
Correlate — Runtime observations are compared against static findings
python3 wasmshark.py sample_cryptominer.wasm \
--rules ./rules/ --wasabi -q
Runtime Metrics Collected
Metric |
Description |
|---|---|
Total instructions |
Total instruction count executed at runtime |
XOR ops |
XOR operations executed (encryption confirmation) |
Rotate ops |
Rotate operations (hash round confirmation) |
NOP ops |
NOPs executed (NOP sled confirmation) |
Memory reads/writes |
Memory access counts |
memory.grow calls |
Dynamic memory expansion count |
Branches taken/not taken |
Branch coverage ratio |
Indirect calls |
Obfuscated dispatch confirmation |
Start function |
Auto-execution confirmation |
Call graph |
Actual runtime call relationships |
Suspicious constants |
Known crypto constants observed at runtime |
Static ↔ Dynamic Correlations
WASMShark automatically correlates runtime observations with static findings:
Correlation |
Trigger |
|---|---|
|
Static XOR > 20 AND runtime XOR > 50 |
|
Static predicted start function AND runtime confirms it ran |
|
Static found call_indirect AND runtime confirms they executed |
|
CRYPTOMINER rule + high runtime XOR |
|
Obfuscation rule + runtime indirect calls |
|
Ransomware rule + runtime memory.grow calls |
Example Output
WASABI DYNAMIC ANALYSIS
──────────────────────────────────────────────────────
Total instructions executed : 196
XOR ops at runtime : 0
NOP ops at runtime : 90
Start func ran : 5
Runtime call graph (1 callers):
func[5] → ['func[0]']
STATIC ↔ DYNAMIC CORRELATIONS
──────────────────────────────────────────────────────
✓ [HIGH] CONFIRMED_AUTORUN
Static predicted auto-exec func[5] — runtime confirms it ran
State Machine Extraction
WASMShark builds a state machine from the runtime call sequence:
Each executed function is a state
Each function call is a transition
Back edges indicate loops
Terminal states have no outgoing calls
State Machine
States (unique functions) : 2
Transitions observed : 1
Initial state : func[0]
Terminal states : [0]
Dynamic CFG Reconstruction
WASMShark reconstructs the control flow graph from runtime observations and compares it against the static CFG:
Finding |
Description |
|---|---|
Dead code confirmed |
Functions in static CFG that never executed |
Hidden call paths |
Runtime edges not present in static CFG |
Unexpected functions |
Functions executed outside static call graph |
Coverage |
Percentage of static functions that actually ran |
# Generate and view dynamic CFG
python3 wasmshark.py sample_cryptominer.wasm --wasabi -q
dot -Tpng sample_cryptominer_dynamic_cfg.dot \
-o sample_cryptominer_dynamic_cfg.png
eog sample_cryptominer_dynamic_cfg.png
CFG Node Colors
Color |
Meaning |
|---|---|
Red |
Executed, suspicious (score > 20) |
Green |
Executed, clean |
Blue (ellipse) |
Import that was called |
Grey dashed |
Never executed (dead code) |
Orange |
Executed but not in static CFG (unexpected) |
Supported Samples
Sample |
Wasabi |
Notes |
|---|---|---|
|
✓ Works |
196 instructions, start func[5] confirmed |
|
✓ Works |
191 instructions, start func[8] confirmed |
|
✓ Works |
211 instructions, WASI stubs applied |
|
✗ Fails |
Uses tail call extension (Wasabi 0.3.0 limitation) |
Note
The obfuscated loader uses WebAssembly tail call instructions which Wasabi 0.3.0 does not support. Static analysis still detects it with MALICIOUS 100/100 — demonstrating the value of combining both approaches.