WebAssembly (WASM) Werkzeuge Cheat Sheet
Überblick
WebAssembly (WASM) ist ein binäres Befehlsformat für eine stapelbasierte virtuelle Maschine, die als tragbares Compilationsziel für Programmiersprachen konzipiert ist. Da WASM in Webanwendungen und sogar Malware immer häufiger verbreitet wird, sind spezialisierte Tools für Analyse, Dekompilation und Sicherheitsforschung unerlässlich.
RECHT *Key Tools: wasm-decompile, Binaryen, WABT (WebAssembly Binary Toolkit), wasm2c, wasm-objdump und verschiedene Browser-basierte Analysetools für umfassende WASM binäre Analyse.
Installation und Inbetriebnahme
WABT (WebAssembly Binary Toolkit)
```bash
Install via package manager (Ubuntu/Debian)
sudo apt-get update sudo apt-get install wabt
Install via Homebrew (macOS)
brew install wabt
Build from source
git clone --recursive https://github.com/WebAssembly/wabt cd wabt mkdir build && cd build cmake .. cmake --build .
Add to PATH
export PATH=$PATH:/path/to/wabt/build
Verify installation
wasm-objdump --version wasm2wat --version wat2wasm --version
Install additional tools
sudo apt-get install nodejs npm npm install -g @webassembly/wabt ```_
Binary
```bash
Install via package manager
sudo apt-get install binaryen
Install via npm
npm install -g binaryen
Build from source
git clone https://github.com/WebAssembly/binaryen.git cd binaryen cmake . && make
Verify installation
wasm-opt --version wasm-dis --version wasm-as --version
Install Python bindings
pip install binaryen
Test installation
python -c "import binaryen; print('Binaryen installed successfully')" ```_
wasm-decompile und zusätzliche Tools
```bash
Install wasm-decompile (part of WABT)
Already included with WABT installation
Install wasm2c
git clone https://github.com/WebAssembly/wasm2c cd wasm2c make
Install Wasmer (WASM runtime)
curl https://get.wasmer.io -sSfL | sh source ~/.wasmer/wasmer.sh
Install Wasmtime (another WASM runtime)
curl https://wasmtime.dev/install.sh -sSf | bash
Install wasm-pack (for Rust)
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
Install Emscripten (for C/C++ to WASM)
git clone https://github.com/emscripten-core/emsdk.git cd emsdk ./emsdk install latest ./emsdk activate latest source ./emsdk_env.sh
Verify all tools
which wasm-objdump wasm-decompile wasm-opt wasmer wasmtime ```_
Browserbasierte Tools Setup
```bash
Install browser extensions and tools
Chrome DevTools WASM debugging (built-in)
Firefox Developer Tools WASM support (built-in)
Install wasm-pack for web development
npm install -g wasm-pack
Install wasmtime-js for Node.js
npm install @bytecodealliance/wasmtime
Set up local web server for WASM analysis
python3 -m http.server 8000
or
npx serve .
Install additional analysis tools
npm install -g wasm-strip npm install -g wasm-snip npm install -g twiggy # WASM code size profiler ```_
Grundlegende WASM Analyse
Dateiinformationen und Struktur
```bash
Get basic file information
file sample.wasm hexdump -C sample.wasm | head -20
Check WASM magic number (0x00 0x61 0x73 0x6d)
xxd sample.wasm | head -1
Get WASM module information
wasm-objdump -h sample.wasm
Display all sections
wasm-objdump -s sample.wasm
Show section details
wasm-objdump -x sample.wasm
Display imports and exports
wasm-objdump -j import sample.wasm wasm-objdump -j export sample.wasm
Show function signatures
wasm-objdump -j type sample.wasm
Display function bodies
wasm-objdump -j code sample.wasm
Show data sections
wasm-objdump -j data sample.wasm
Display custom sections
wasm-objdump -j custom sample.wasm
Get detailed disassembly
wasm-objdump -d sample.wasm
Show relocation information
wasm-objdump -r sample.wasm
Display symbol table
wasm-objdump -t sample.wasm ```_
WASM zu WAT-Umrechnung
```bash
Convert WASM binary to WAT (WebAssembly Text)
wasm2wat sample.wasm -o sample.wat
Convert with verbose output
wasm2wat sample.wasm -v -o sample.wat
Convert with function names
wasm2wat sample.wasm --generate-names -o sample.wat
Convert with inline exports
wasm2wat sample.wasm --inline-exports -o sample.wat
Convert with folded expressions
wasm2wat sample.wasm --fold-exprs -o sample.wat
Convert specific sections only
wasm2wat sample.wasm --no-debug-names -o sample.wat
Convert with custom formatting
wasm2wat sample.wasm --no-check -o sample.wat
Batch conversion
for file in *.wasm; do wasm2wat "$file" -o "${file%.wasm}.wat" done
Convert WAT back to WASM
wat2wasm sample.wat -o sample.wasm
Validate WASM file
wat2wasm sample.wat --validate ```_
WASM-Dekompilation
```bash
Decompile WASM to C-like pseudocode
wasm-decompile sample.wasm -o sample.dcmp
Decompile with function names
wasm-decompile sample.wasm --generate-names -o sample.dcmp
Decompile with inline exports
wasm-decompile sample.wasm --inline-exports -o sample.dcmp
Decompile with variable names
wasm-decompile sample.wasm --name-all -o sample.dcmp
Advanced decompilation options
wasm-decompile sample.wasm \ --generate-names \ --inline-exports \ --fold-exprs \ --name-all \ -o sample_detailed.dcmp
Decompile specific functions
wasm-decompile sample.wasm --func-index=0 -o function0.dcmp wasm-decompile sample.wasm --func-name=main -o main_function.dcmp
Batch decompilation
for file in *.wasm; do echo "Decompiling $file..." wasm-decompile "$file" --generate-names -o "${file%.wasm}.dcmp" done
Compare original and decompiled
diff -u original.c sample.dcmp ```_
Erweiterte Analysetechniken
Binary-Analyse-Tools
```bash
Optimize WASM binary
wasm-opt sample.wasm -O3 -o sample_optimized.wasm
Analyze optimization opportunities
wasm-opt sample.wasm --print-features
Remove debug information
wasm-opt sample.wasm --strip-debug -o sample_stripped.wasm
Minify WASM
wasm-opt sample.wasm -Oz --strip-debug -o sample_minified.wasm
Validate WASM module
wasm-opt sample.wasm --validate
Print module structure
wasm-opt sample.wasm --print
Print function CFG
wasm-opt sample.wasm --print-function-map
Analyze memory usage
wasm-opt sample.wasm --print-stack-ir
Dead code elimination
wasm-opt sample.wasm --dce -o sample_dce.wasm
Inline functions
wasm-opt sample.wasm --inline-functions-with-loops -o sample_inlined.wasm
Constant folding
wasm-opt sample.wasm --const-hoisting -o sample_const.wasm
Loop optimization
wasm-opt sample.wasm --optimize-level=3 --shrink-level=1 -o sample_loops.wasm ```_
Speicher- und Datenanalyse
```bash
Extract data sections
wasm-objdump -j data sample.wasm > data_sections.txt
Analyze memory layout
wasm-objdump -s sample.wasm | grep -A 10 "Contents of section data"
Extract strings from WASM
strings sample.wasm > extracted_strings.txt
Search for specific patterns
| hexdump -C sample.wasm | grep -i "password\ | secret\ | key" |
Analyze imports for API calls
| wasm-objdump -j import sample.wasm | grep -E "(func | memory | table | global)" |
Check for suspicious imports
| wasm-objdump -j import sample.wasm | grep -E "(eval | document | window | fetch | XMLHttpRequest)" |
Analyze exports
wasm-objdump -j export sample.wasm
Extract function names
| wasm-objdump -j export sample.wasm | grep "func" | awk '{print $4}' |
Analyze global variables
wasm-objdump -j global sample.wasm
Check memory configuration
wasm-objdump -j memory sample.wasm
Analyze table sections
wasm-objdump -j table sample.wasm
Extract custom sections
wasm-objdump -j custom sample.wasm ```_
Steuerungsflussanalyse
```bash
Generate control flow graph
wasm-opt sample.wasm --print-function-map > cfg.txt
Analyze function calls
wasm-objdump -d sample.wasm | grep "call"
Find indirect calls
wasm-objdump -d sample.wasm | grep "call_indirect"
Analyze branches
| wasm-objdump -d sample.wasm | grep -E "(br | br_if | br_table)" |
Find loops
| wasm-objdump -d sample.wasm | grep -E "(loop | block)" |
Analyze exception handling
| wasm-objdump -d sample.wasm | grep -E "(try | catch | throw)" |
Extract function boundaries
awk '/^[0-9a-f]+.*func/ {print $0}' sample.wat
Analyze stack operations
| wasm-objdump -d sample.wasm | grep -E "(local. | global. | i32. | i64. | f32. | f64.)" |
Find return statements
wasm-objdump -d sample.wasm | grep "return"
Analyze unreachable code
wasm-objdump -d sample.wasm | grep "unreachable" ```_
Sicherheitsanalyse
Techniken der Malware-Analyse
```bash
Check for obfuscation indicators
| wasm-objdump -h sample.wasm | grep -E "(custom | unknown)" |
Analyze suspicious function names
| wasm2wat sample.wasm --generate-names | grep -E "(eval | exec | shell | cmd)" |
Check for dynamic code generation
| wasm-objdump -d sample.wasm | grep -E "(memory.grow | table.grow)" |
Analyze memory access patterns
| wasm-objdump -d sample.wasm | grep -E "(load | store)" | head -20 |
Check for anti-analysis techniques
| wasm-objdump -d sample.wasm | grep -E "(unreachable | trap)" |
Analyze imports for suspicious APIs
| wasm-objdump -j import sample.wasm | grep -v -E "(Math | console | Date)" |
Check for encrypted/encoded data
| hexdump -C sample.wasm | grep -E "([0-9a-f]{2} ){16}" | head -10 |
Analyze function complexity
| wasm-decompile sample.wasm | grep -c "if\ | while\ | for" |
Check for self-modification
| wasm-objdump -d sample.wasm | grep -E "(memory.copy | memory.fill)" |
Analyze exception handling for evasion
| wasm-objdump -d sample.wasm | grep -E "(try | catch)" -A 5 -B 5 | ```_
Schwachstellenerkennung
```bash
Check for buffer overflow vulnerabilities
| wasm-objdump -d sample.wasm | grep -E "(memory.size | memory.grow)" -A 3 -B 3 |
Analyze bounds checking
| wasm-decompile sample.wasm | grep -E "bounds | check | limit" |
Check for integer overflow
| wasm-objdump -d sample.wasm | grep -E "(add | mul | div)" | head -10 |
Analyze memory safety
| wasm-opt sample.wasm --print-stack-ir | grep -E "load | store" |
Check for use-after-free patterns
| wasm-decompile sample.wasm | grep -E "free | malloc | realloc" -A 5 -B 5 |
Analyze type confusion
wasm-objdump -j type sample.wasm
Check for format string vulnerabilities
strings sample.wasm | grep -E "%[sdxp]"
Analyze input validation
| wasm-decompile sample.wasm | grep -E "validate | sanitize | check" |
Check for race conditions
| wasm-objdump -d sample.wasm | grep -E "(atomic | shared)" |
Analyze cryptographic usage
| strings sample.wasm | grep -E "(crypto | hash | encrypt | decrypt | key | iv)" | ```_
Sandbox Escape Analyse
```bash
Check for DOM manipulation
| wasm-objdump -j import sample.wasm | grep -E "(document | window | DOM)" |
Analyze file system access
| wasm-objdump -j import sample.wasm | grep -E "(file | read | write | open)" |
Check for network access
| wasm-objdump -j import sample.wasm | grep -E "(fetch | xhr | websocket | http)" |
Analyze process creation
| wasm-objdump -j import sample.wasm | grep -E "(exec | spawn | process)" |
Check for memory access outside sandbox
| wasm-objdump -d sample.wasm | grep -E "memory.(load | store)" -A 2 | grep -E "offset=" |
Analyze shared memory usage
wasm-objdump -j memory sample.wasm | grep "shared"
Check for worker thread creation
| wasm-objdump -j import sample.wasm | grep -E "(worker | thread)" |
Analyze timing attacks
| wasm-objdump -j import sample.wasm | grep -E "(performance | time | date)" |
Check for side-channel attacks
| wasm-decompile sample.wasm | grep -E "cache | timing | power" | ```_
Dynamische Analyse
Laufzeitanalyse mit Wasmer
```bash
Run WASM with Wasmer
wasmer run sample.wasm
Run with arguments
wasmer run sample.wasm -- arg1 arg2 arg3
Run with environment variables
ENV_VAR=value wasmer run sample.wasm
Enable debugging
wasmer run sample.wasm --debug
Run with memory limits
wasmer run sample.wasm --max-memory=1GB
Run with CPU limits
wasmer run sample.wasm --max-time=30s
Enable tracing
wasmer run sample.wasm --trace
Run with custom imports
wasmer run sample.wasm --mapdir=/host:/guest
Profile execution
time wasmer run sample.wasm
Run with different engines
wasmer run sample.wasm --backend=cranelift wasmer run sample.wasm --backend=llvm wasmer run sample.wasm --backend=singlepass ```_
Laufzeitanalyse mit Abfallzeit
```bash
Run WASM with Wasmtime
wasmtime run sample.wasm
Run with arguments
wasmtime run sample.wasm -- arg1 arg2 arg3
Enable debugging
wasmtime run --debug sample.wasm
Run with memory limits
wasmtime run --max-memory=1073741824 sample.wasm # 1GB
Enable optimization
wasmtime run --optimize sample.wasm
Run with fuel limits (instruction counting)
wasmtime run --fuel=1000000 sample.wasm
Enable epoch interruption
wasmtime run --epoch-interruption sample.wasm
Run with WASI support
wasmtime run --wasi-modules=wasi_snapshot_preview1 sample.wasm
Profile execution
wasmtime run --profile=jitdump sample.wasm
Run with custom configuration
wasmtime run --config wasmtime.toml sample.wasm
Enable memory profiling
wasmtime run --profile=perfmap sample.wasm ```_
Browserbasierte dynamische Analyse
```javascript // Load and analyze WASM in browser async function analyzeWasm(wasmUrl) { try { // Fetch WASM binary const response = await fetch(wasmUrl); const wasmBytes = await response.arrayBuffer();
// Compile WASM module
const wasmModule = await WebAssembly.compile(wasmBytes);
// Get module imports
const imports = WebAssembly.Module.imports(wasmModule);
console.log('Imports:', imports);
// Get module exports
const exports = WebAssembly.Module.exports(wasmModule);
console.log('Exports:', exports);
// Create instance with instrumented imports
const instrumentedImports = createInstrumentedImports();
const wasmInstance = await WebAssembly.instantiate(wasmModule, instrumentedImports);
// Analyze exported functions
for (const exp of exports) {
if (exp.kind === 'function') {
console.log(`Function: ${exp.name}`);
// Hook function calls
const originalFunc = wasmInstance.exports[exp.name];
wasmInstance.exports[exp.name] = function(...args) {
console.log(`Calling ${exp.name} with args:`, args);
const result = originalFunc.apply(this, args);
console.log(`${exp.name} returned:`, result);
return result;
};
}
}
return wasmInstance;
} catch (error) {
console.error('WASM analysis failed:', error);
}
}
// Create instrumented imports for monitoring function createInstrumentedImports() { return { env: { // Hook memory operations memory: new WebAssembly.Memory({ initial: 256, maximum: 256 }),
// Hook console operations
console_log: function(ptr, len) {
const memory = new Uint8Array(this.memory.buffer);
const str = new TextDecoder().decode(memory.slice(ptr, ptr + len));
console.log('WASM console.log:', str);
},
// Hook mathematical operations
Math_random: function() {
const value = Math.random();
console.log('WASM Math.random():', value);
return value;
},
// Hook date operations
Date_now: function() {
const value = Date.now();
console.log('WASM Date.now():', value);
return value;
}
},
// Hook WASI operations
wasi_snapshot_preview1: {
fd_write: function(fd, iovs, iovs_len, nwritten) {
console.log(`WASM fd_write: fd=${fd}, iovs_len=${iovs_len}`);
return 0;
},
proc_exit: function(code) {
console.log(`WASM proc_exit: code=${code}`);
}
}
};
}
// Memory analysis functions function analyzeWasmMemory(wasmInstance) { const memory = wasmInstance.exports.memory; if (!memory) return;
const buffer = new Uint8Array(memory.buffer);
// Search for strings
const strings = [];
let currentString = '';
for (let i = 0; i < buffer.length; i++) {
if (buffer[i] >= 32 && buffer[i] <= 126) {
currentString += String.fromCharCode(buffer[i]);
} else {
if (currentString.length > 4) {
strings.push(currentString);
}
currentString = '';
}
}
console.log('Found strings:', strings);
// Analyze memory patterns
const patterns = {
nullBytes: 0,
highEntropy: 0,
repeatingPatterns: 0
};
for (let i = 0; i < buffer.length; i++) {
if (buffer[i] === 0) patterns.nullBytes++;
if (buffer[i] > 127) patterns.highEntropy++;
if (i > 0 && buffer[i] === buffer[i-1]) patterns.repeatingPatterns++;
}
console.log('Memory patterns:', patterns);
}
// Function call tracing function traceWasmExecution(wasmInstance) { const callStack = [];
// Hook all exported functions
for (const [name, func] of Object.entries(wasmInstance.exports)) {
if (typeof func === 'function') {
wasmInstance.exports[name] = function(...args) {
callStack.push({ function: name, args: args, timestamp: Date.now() });
console.log(`→ ${name}(${args.join(', ')})`);
try {
const result = func.apply(this, args);
console.log(`← ${name} returned: ${result}`);
return result;
} catch (error) {
console.log(`← ${name} threw: ${error}`);
throw error;
} finally {
callStack.pop();
}
};
}
}
return callStack;
} ```_
Automatisierte Analyseskripte
Umfassende WASM Analyse Script
```python
!/usr/bin/env python3
""" Comprehensive WASM Analysis Tool Analyzes WebAssembly binaries for security issues and malware indicators """
import os import sys import subprocess import json import hashlib import re from pathlib import Path
class WasmAnalyzer: def init(self, wasm_file): self.wasm_file = Path(wasm_file) self.analysis_results = { 'file_info': {}, 'structure': {}, 'security': {}, 'strings': [], 'functions': [], 'imports': [], 'exports': [], 'suspicious_indicators': [] }
def analyze(self):
"""Perform comprehensive WASM analysis"""
print(f"Analyzing WASM file: {self.wasm_file}")
# Basic file analysis
self.analyze_file_info()
# Structure analysis
self.analyze_structure()
# Security analysis
self.analyze_security()
# Extract strings
self.extract_strings()
# Analyze functions
self.analyze_functions()
# Analyze imports/exports
self.analyze_imports_exports()
# Generate report
self.generate_report()
return self.analysis_results
def analyze_file_info(self):
"""Analyze basic file information"""
stat = self.wasm_file.stat()
with open(self.wasm_file, 'rb') as f:
content = f.read()
self.analysis_results['file_info'] = {
'size': stat.st_size,
'md5': hashlib.md5(content).hexdigest(),
'sha1': hashlib.sha1(content).hexdigest(),
'sha256': hashlib.sha256(content).hexdigest(),
'magic': content[:4].hex() if len(content) >= 4 else '',
'valid_magic': content[:4] == b'\x00asm'
}
def analyze_structure(self):
"""Analyze WASM structure"""
try:
# Get section information
result = subprocess.run(['wasm-objdump', '-h', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
sections = []
for line in result.stdout.split('\n'):
if 'Section Details:' in line or line.strip().startswith('Type'):
continue
if line.strip() and not line.startswith('Sections:'):
sections.append(line.strip())
self.analysis_results['structure']['sections'] = sections
# Get detailed structure
result = subprocess.run(['wasm-objdump', '-x', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
self.analysis_results['structure']['detailed'] = result.stdout
except FileNotFoundError:
print("Warning: wasm-objdump not found. Install WABT for detailed analysis.")
def analyze_security(self):
"""Perform security analysis"""
security_issues = []
# Check for suspicious imports
try:
result = subprocess.run(['wasm-objdump', '-j', 'import', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
suspicious_imports = [
'eval', 'Function', 'document', 'window', 'XMLHttpRequest',
'fetch', 'WebSocket', 'Worker', 'SharedArrayBuffer'
]
for imp in suspicious_imports:
if imp in result.stdout:
security_issues.append(f"Suspicious import: {imp}")
except FileNotFoundError:
pass
# Check for obfuscation indicators
with open(self.wasm_file, 'rb') as f:
content = f.read()
# High entropy check (possible encryption/obfuscation)
entropy = self.calculate_entropy(content)
if entropy > 7.5:
security_issues.append(f"High entropy detected: {entropy:.2f}")
# Check for unusual section names
try:
result = subprocess.run(['wasm-objdump', '-j', 'custom', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0 and result.stdout.strip():
security_issues.append("Custom sections detected (possible obfuscation)")
except FileNotFoundError:
pass
self.analysis_results['security']['issues'] = security_issues
def calculate_entropy(self, data):
"""Calculate Shannon entropy of data"""
if not data:
return 0
# Count byte frequencies
frequencies = {}
for byte in data:
frequencies[byte] = frequencies.get(byte, 0) + 1
# Calculate entropy
entropy = 0
data_len = len(data)
for count in frequencies.values():
probability = count / data_len
if probability > 0:
entropy -= probability * (probability.bit_length() - 1)
return entropy
def extract_strings(self):
"""Extract strings from WASM binary"""
try:
result = subprocess.run(['strings', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
strings = [s.strip() for s in result.stdout.split('\n') if len(s.strip()) > 3]
self.analysis_results['strings'] = strings[:100] # Limit to first 100
# Check for suspicious strings
suspicious_patterns = [
r'password', r'secret', r'key', r'token', r'auth',
r'eval\(', r'document\.', r'window\.', r'\.exe',
r'cmd\.exe', r'powershell', r'bash', r'sh\s'
]
for string in strings:
for pattern in suspicious_patterns:
if re.search(pattern, string, re.IGNORECASE):
self.analysis_results['suspicious_indicators'].append(
f"Suspicious string: {string}"
)
except FileNotFoundError:
print("Warning: strings command not found")
def analyze_functions(self):
"""Analyze WASM functions"""
try:
# Get function information
result = subprocess.run(['wasm-objdump', '-j', 'code', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
functions = []
current_function = None
for line in result.stdout.split('\n'):
if 'func[' in line:
if current_function:
functions.append(current_function)
current_function = {'name': line.strip(), 'instructions': []}
elif current_function and line.strip():
current_function['instructions'].append(line.strip())
if current_function:
functions.append(current_function)
self.analysis_results['functions'] = functions
except FileNotFoundError:
pass
def analyze_imports_exports(self):
"""Analyze imports and exports"""
try:
# Analyze imports
result = subprocess.run(['wasm-objdump', '-j', 'import', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
imports = []
for line in result.stdout.split('\n'):
if 'import[' in line or 'func' in line or 'memory' in line:
imports.append(line.strip())
self.analysis_results['imports'] = imports
# Analyze exports
result = subprocess.run(['wasm-objdump', '-j', 'export', str(self.wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
exports = []
for line in result.stdout.split('\n'):
if 'export[' in line or 'func' in line:
exports.append(line.strip())
self.analysis_results['exports'] = exports
except FileNotFoundError:
pass
def generate_report(self):
"""Generate analysis report"""
report_file = self.wasm_file.with_suffix('.analysis.json')
with open(report_file, 'w') as f:
json.dump(self.analysis_results, f, indent=2)
print(f"Analysis report saved to: {report_file}")
# Print summary
print("\n=== WASM Analysis Summary ===")
print(f"File: {self.wasm_file}")
print(f"Size: {self.analysis_results['file_info']['size']} bytes")
print(f"SHA256: {self.analysis_results['file_info']['sha256']}")
print(f"Valid WASM: {self.analysis_results['file_info']['valid_magic']}")
if self.analysis_results['security']['issues']:
print(f"\nSecurity Issues ({len(self.analysis_results['security']['issues'])}):")
for issue in self.analysis_results['security']['issues']:
print(f" - {issue}")
if self.analysis_results['suspicious_indicators']:
print(f"\nSuspicious Indicators ({len(self.analysis_results['suspicious_indicators'])}):")
for indicator in self.analysis_results['suspicious_indicators'][:10]:
print(f" - {indicator}")
print(f"\nFunctions: {len(self.analysis_results['functions'])}")
print(f"Imports: {len(self.analysis_results['imports'])}")
print(f"Exports: {len(self.analysis_results['exports'])}")
print(f"Strings: {len(self.analysis_results['strings'])}")
def main():
if len(sys.argv) != 2:
print("Usage: python wasm_analyzer.py
wasm_file = sys.argv[1]
if not os.path.exists(wasm_file):
print(f"Error: File {wasm_file} not found")
sys.exit(1)
analyzer = WasmAnalyzer(wasm_file)
results = analyzer.analyze()
if name == "main": main() ```_
Batch WASM AnalyseScript
```bash
!/bin/bash
Batch WASM analysis script
WASM_DIR="$1" OUTPUT_DIR="$2"
| if [ -z "$WASM_DIR" ] | | [ -z "$OUTPUT_DIR" ]; then |
echo "Usage: $0
mkdir -p "$OUTPUT_DIR"
echo "Starting batch WASM analysis..." echo "Input directory: $WASM_DIR" echo "Output directory: $OUTPUT_DIR"
Find all WASM files
find "$WASM_DIR" -name "*.wasm" -type f | while read -r wasm_file; do echo "Processing: $wasm_file"
# Create output subdirectory
rel_path=$(realpath --relative-to="$WASM_DIR" "$wasm_file")
output_subdir="$OUTPUT_DIR/$(dirname "$rel_path")"
mkdir -p "$output_subdir"
# Base name for output files
base_name=$(basename "$wasm_file" .wasm)
output_base="$output_subdir/$base_name"
# Basic analysis
echo " - Basic analysis..."
wasm-objdump -h "$wasm_file" > "${output_base}_headers.txt" 2>/dev/null
wasm-objdump -x "$wasm_file" > "${output_base}_details.txt" 2>/dev/null
# Disassembly
echo " - Disassembly..."
wasm-objdump -d "$wasm_file" > "${output_base}_disasm.txt" 2>/dev/null
# Decompilation
echo " - Decompilation..."
wasm-decompile "$wasm_file" -o "${output_base}_decompiled.c" 2>/dev/null
# WAT conversion
echo " - WAT conversion..."
wasm2wat "$wasm_file" -o "${output_base}.wat" 2>/dev/null
# String extraction
echo " - String extraction..."
strings "$wasm_file" > "${output_base}_strings.txt" 2>/dev/null
# Security analysis
echo " - Security analysis..."
{
echo "=== IMPORTS ==="
wasm-objdump -j import "$wasm_file" 2>/dev/null
echo -e "\n=== EXPORTS ==="
wasm-objdump -j export "$wasm_file" 2>/dev/null
echo -e "\n=== SUSPICIOUS STRINGS ==="
| strings "$wasm_file" | grep -E -i "(eval | document | window | fetch | xhr | websocket | crypto | password | secret | key)" 2>/dev/null | } > "${output_base}_security.txt"
# File hash
echo " - Computing hashes..."
{
echo "MD5: $(md5sum "$wasm_file" | cut -d' ' -f1)"
echo "SHA1: $(sha1sum "$wasm_file" | cut -d' ' -f1)"
echo "SHA256: $(sha256sum "$wasm_file" | cut -d' ' -f1)"
echo "Size: $(stat -c%s "$wasm_file") bytes"
} > "${output_base}_hashes.txt"
echo " - Complete!"
done
Generate summary report
echo "Generating summary report..." { echo "WASM Batch Analysis Summary" echo "==========================" echo "Analysis Date: $(date)" echo "Input Directory: $WASM_DIR" echo "Output Directory: $OUTPUT_DIR" echo ""
total_files=$(find "$WASM_DIR" -name "*.wasm" -type f | wc -l)
echo "Total WASM files analyzed: $total_files"
echo ""
echo "File Sizes:"
| find "$WASM_DIR" -name "*.wasm" -type f -exec stat -c"%s %n" {} \; | sort -n | tail -10 |
echo ""
echo "Most Common Imports:"
| find "$OUTPUT_DIR" -name "*_security.txt" -exec grep -h "import[" {} \; | sort | uniq -c | sort -nr | head -10 |
echo ""
echo "Most Common Exports:"
| find "$OUTPUT_DIR" -name "*_security.txt" -exec grep -h "export[" {} \; | sort | uniq -c | sort -nr | head -10 |
} > "$OUTPUT_DIR/analysis_summary.txt"
echo "Batch analysis complete!" echo "Summary report: $OUTPUT_DIR/analysis_summary.txt" ```_
Integration mit Reverse Engineering Workflows
WASM in Malware Analyse Pipeline
```python
!/usr/bin/env python3
""" WASM Malware Analysis Pipeline Integrates WASM analysis into broader malware analysis workflow """
import os import json import subprocess import tempfile from pathlib import Path
class WasmMalwareAnalyzer: def init(self, sample_path): self.sample_path = Path(sample_path) self.temp_dir = Path(tempfile.mkdtemp()) self.analysis_results = {}
def analyze_sample(self):
"""Analyze WASM sample for malware indicators"""
# Extract WASM from various containers
wasm_files = self.extract_wasm_files()
if not wasm_files:
print("No WASM files found in sample")
return
# Analyze each WASM file
for wasm_file in wasm_files:
print(f"Analyzing WASM file: {wasm_file}")
analysis = {
'static_analysis': self.static_analysis(wasm_file),
'behavioral_analysis': self.behavioral_analysis(wasm_file),
'threat_assessment': self.threat_assessment(wasm_file)
}
self.analysis_results[str(wasm_file)] = analysis
# Generate IOCs
self.generate_iocs()
# Create YARA rules
self.create_yara_rules()
return self.analysis_results
def extract_wasm_files(self):
"""Extract WASM files from various containers"""
wasm_files = []
# Direct WASM file
if self.sample_path.suffix == '.wasm':
return [self.sample_path]
# Extract from HTML/JS files
if self.sample_path.suffix in ['.html', '.htm', '.js']:
wasm_files.extend(self.extract_from_web_files())
# Extract from archives
if self.sample_path.suffix in ['.zip', '.tar', '.gz']:
wasm_files.extend(self.extract_from_archives())
# Search for embedded WASM
wasm_files.extend(self.find_embedded_wasm())
return wasm_files
def extract_from_web_files(self):
"""Extract WASM from HTML/JS files"""
wasm_files = []
with open(self.sample_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# Look for WASM loading patterns
patterns = [
r'fetch\(["\'](https://[^"\']*\.wasm)["\']',
r'WebAssembly\.instantiateStreaming\([^,]*["\'](https://[^"\']*\.wasm)["\']',
r'new\s+WebAssembly\.Module\([^)]*["\'](https://[^"\']*\.wasm)["\']'
]
import re
for pattern in patterns:
matches = re.findall(pattern, content)
for match in matches:
wasm_path = self.sample_path.parent / match
if wasm_path.exists():
wasm_files.append(wasm_path)
return wasm_files
def extract_from_archives(self):
"""Extract WASM from archive files"""
wasm_files = []
extract_dir = self.temp_dir / "extracted"
extract_dir.mkdir(exist_ok=True)
try:
if self.sample_path.suffix == '.zip':
subprocess.run(['unzip', '-q', str(self.sample_path), '-d', str(extract_dir)])
elif self.sample_path.suffix in ['.tar', '.gz']:
subprocess.run(['tar', '-xf', str(self.sample_path), '-C', str(extract_dir)])
# Find WASM files in extracted content
for wasm_file in extract_dir.rglob('*.wasm'):
wasm_files.append(wasm_file)
except subprocess.CalledProcessError:
pass
return wasm_files
def find_embedded_wasm(self):
"""Find embedded WASM in binary files"""
wasm_files = []
with open(self.sample_path, 'rb') as f:
content = f.read()
# Look for WASM magic bytes
wasm_magic = b'\x00asm'
offset = 0
while True:
pos = content.find(wasm_magic, offset)
if pos == -1:
break
# Extract potential WASM module
wasm_data = self.extract_wasm_module(content, pos)
if wasm_data:
wasm_file = self.temp_dir / f"embedded_{pos:08x}.wasm"
with open(wasm_file, 'wb') as f:
f.write(wasm_data)
wasm_files.append(wasm_file)
offset = pos + 4
return wasm_files
def extract_wasm_module(self, data, start_pos):
"""Extract complete WASM module from binary data"""
if start_pos + 8 > len(data):
return None
# Check magic and version
if data[start_pos:start_pos+4] != b'\x00asm':
return None
version = int.from_bytes(data[start_pos+4:start_pos+8], 'little')
if version != 1:
return None
# Parse sections to find module end
pos = start_pos + 8
while pos < len(data):
if pos + 1 > len(data):
break
section_id = data[pos]
pos += 1
# Parse LEB128 size
size, size_bytes = self.parse_leb128(data, pos)
if size is None:
break
pos += size_bytes
if pos + size > len(data):
break
pos += size
# If we've read all standard sections, we're done
if section_id == 0: # Custom section at end
break
return data[start_pos:pos]
def parse_leb128(self, data, pos):
"""Parse LEB128 encoded integer"""
result = 0
shift = 0
size = 0
while pos + size < len(data):
byte = data[pos + size]
size += 1
result |= (byte & 0x7f) << shift
shift += 7
if (byte & 0x80) == 0:
break
if size > 5: # Prevent infinite loop
return None, 0
return result, size
def static_analysis(self, wasm_file):
"""Perform static analysis on WASM file"""
analysis = {
'file_info': {},
'structure': {},
'suspicious_indicators': [],
'capabilities': []
}
# File information
stat = wasm_file.stat()
with open(wasm_file, 'rb') as f:
content = f.read()
analysis['file_info'] = {
'size': stat.st_size,
'sha256': hashlib.sha256(content).hexdigest(),
'entropy': self.calculate_entropy(content)
}
# Analyze imports for capabilities
try:
result = subprocess.run(['wasm-objdump', '-j', 'import', str(wasm_file)],
capture_output=True, text=True)
if result.returncode == 0:
imports = result.stdout
# Check for suspicious capabilities
if 'fetch' in imports or 'XMLHttpRequest' in imports:
analysis['capabilities'].append('network_access')
analysis['suspicious_indicators'].append('Network access capability')
if 'document' in imports or 'window' in imports:
analysis['capabilities'].append('dom_manipulation')
analysis['suspicious_indicators'].append('DOM manipulation capability')
if 'eval' in imports or 'Function' in imports:
analysis['capabilities'].append('code_execution')
analysis['suspicious_indicators'].append('Dynamic code execution capability')
if 'crypto' in imports:
analysis['capabilities'].append('cryptography')
if 'Worker' in imports:
analysis['capabilities'].append('worker_threads')
analysis['suspicious_indicators'].append('Worker thread capability')
except FileNotFoundError:
pass
# Check for obfuscation
if analysis['file_info']['entropy'] > 7.5:
analysis['suspicious_indicators'].append('High entropy (possible obfuscation)')
return analysis
def behavioral_analysis(self, wasm_file):
"""Perform behavioral analysis using sandboxed execution"""
analysis = {
'execution_trace': [],
'network_activity': [],
'file_operations': [],
'api_calls': []
}
# Create instrumented environment
instrumented_js = self.create_instrumented_environment()
# Run WASM in controlled environment
try:
with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
f.write(instrumented_js)
js_file = f.name
# Execute with Node.js
result = subprocess.run(['node', js_file, str(wasm_file)],
capture_output=True, text=True, timeout=30)
if result.returncode == 0:
# Parse execution trace
for line in result.stdout.split('\n'):
if line.startswith('TRACE:'):
analysis['execution_trace'].append(line[6:])
elif line.startswith('NETWORK:'):
analysis['network_activity'].append(line[8:])
elif line.startswith('API:'):
analysis['api_calls'].append(line[4:])
os.unlink(js_file)
except (subprocess.TimeoutExpired, FileNotFoundError):
analysis['execution_trace'].append('Execution timeout or Node.js not available')
return analysis
def create_instrumented_environment(self):
"""Create instrumented JavaScript environment for WASM execution"""
return """
const fs = require('fs'); const path = require('path');
// Instrumented WebAssembly implementation const originalInstantiate = WebAssembly.instantiate; WebAssembly.instantiate = async function(source, imports) { console.log('TRACE: WebAssembly.instantiate called');
// Instrument imports
if (imports) {
for (const [module, funcs] of Object.entries(imports)) {
for (const [name, func] of Object.entries(funcs)) {
if (typeof func === 'function') {
imports[module][name] = function(...args) {
console.log(`API: ${module}.${name}(${args.join(', ')})`);
return func.apply(this, args);
};
}
}
}
}
const result = await originalInstantiate.call(this, source, imports);
// Instrument exports
if (result.instance && result.instance.exports) {
for (const [name, func] of Object.entries(result.instance.exports)) {
if (typeof func === 'function') {
result.instance.exports[name] = function(...args) {
console.log(`TRACE: Calling exported function ${name}(${args.join(', ')})`);
return func.apply(this, args);
};
}
}
}
return result;
};
// Instrument fetch for network monitoring
global.fetch = function(url, options) {
console.log(NETWORK: fetch(${url})
);
return Promise.reject(new Error('Network access blocked in sandbox'));
};
// Load and run WASM file
async function runWasm() {
try {
const wasmFile = process.argv[2];
if (!wasmFile) {
console.error('Usage: node script.js
const wasmBuffer = fs.readFileSync(wasmFile);
console.log(`TRACE: Loading WASM file: ${wasmFile} (${wasmBuffer.length} bytes)`);
const wasmModule = await WebAssembly.instantiate(wasmBuffer, {
env: {
console_log: (ptr, len) => console.log('TRACE: console.log called'),
memory: new WebAssembly.Memory({ initial: 256, maximum: 256 })
}
});
console.log('TRACE: WASM module loaded successfully');
// Try to call main function if it exists
if (wasmModule.instance.exports.main) {
console.log('TRACE: Calling main function');
wasmModule.instance.exports.main();
}
} catch (error) {
console.log(`TRACE: Error: ${error.message}`);
}
}
runWasm(); """
def threat_assessment(self, wasm_file):
"""Assess threat level of WASM file"""
threat_score = 0
threat_indicators = []
# Get analysis results
static = self.analysis_results.get(str(wasm_file), {}).get('static_analysis', {})
behavioral = self.analysis_results.get(str(wasm_file), {}).get('behavioral_analysis', {})
# Score based on capabilities
capabilities = static.get('capabilities', [])
if 'network_access' in capabilities:
threat_score += 30
threat_indicators.append('Network access capability')
if 'code_execution' in capabilities:
threat_score += 40
threat_indicators.append('Dynamic code execution')
if 'dom_manipulation' in capabilities:
threat_score += 20
threat_indicators.append('DOM manipulation')
if 'worker_threads' in capabilities:
threat_score += 15
threat_indicators.append('Worker thread creation')
# Score based on suspicious indicators
suspicious = static.get('suspicious_indicators', [])
threat_score += len(suspicious) * 10
# Score based on entropy
entropy = static.get('file_info', {}).get('entropy', 0)
if entropy > 7.5:
threat_score += 25
threat_indicators.append('High entropy (obfuscation)')
# Determine threat level
if threat_score >= 80:
threat_level = 'HIGH'
elif threat_score >= 50:
threat_level = 'MEDIUM'
elif threat_score >= 20:
threat_level = 'LOW'
else:
threat_level = 'MINIMAL'
return {
'threat_level': threat_level,
'threat_score': threat_score,
'threat_indicators': threat_indicators
}
def generate_iocs(self):
"""Generate Indicators of Compromise"""
iocs = {
'file_hashes': [],
'network_indicators': [],
'behavioral_indicators': []
}
for wasm_file, analysis in self.analysis_results.items():
# File hash IOCs
file_info = analysis.get('static_analysis', {}).get('file_info', {})
if 'sha256' in file_info:
iocs['file_hashes'].append(file_info['sha256'])
# Network IOCs
network_activity = analysis.get('behavioral_analysis', {}).get('network_activity', [])
iocs['network_indicators'].extend(network_activity)
# Behavioral IOCs
capabilities = analysis.get('static_analysis', {}).get('capabilities', [])
iocs['behavioral_indicators'].extend(capabilities)
# Save IOCs
ioc_file = self.temp_dir / 'iocs.json'
with open(ioc_file, 'w') as f:
json.dump(iocs, f, indent=2)
print(f"IOCs saved to: {ioc_file}")
return iocs
def create_yara_rules(self):
"""Create YARA rules for detected threats"""
yara_rules = []
for wasm_file, analysis in self.analysis_results.items():
threat = analysis.get('threat_assessment', {})
if threat.get('threat_level') in ['HIGH', 'MEDIUM']:
rule_name = f"WASM_Malware_{Path(wasm_file).stem}"
rule = f"""
rule {rule_name} {{ meta: description = "Suspicious WASM file detected" threat_level = "{threat.get('threat_level')}" threat_score = {threat.get('threat_score')}
strings:
$magic = {{ 00 61 73 6D }} // WASM magic
condition:
$magic at 0
}} """ yara_rules.append(rule)
# Save YARA rules
if yara_rules:
yara_file = self.temp_dir / 'wasm_malware.yar'
with open(yara_file, 'w') as f:
f.write('\n'.join(yara_rules))
print(f"YARA rules saved to: {yara_file}")
return yara_rules
def main():
if len(sys.argv) != 2:
print("Usage: python wasm_malware_analyzer.py
sample_file = sys.argv[1]
if not os.path.exists(sample_file):
print(f"Error: File {sample_file} not found")
sys.exit(1)
analyzer = WasmMalwareAnalyzer(sample_file)
results = analyzer.analyze_sample()
# Print summary
print("\n=== WASM Malware Analysis Summary ===")
for wasm_file, analysis in results.items():
threat = analysis.get('threat_assessment', {})
print(f"\nFile: {wasm_file}")
print(f"Threat Level: {threat.get('threat_level', 'UNKNOWN')}")
print(f"Threat Score: {threat.get('threat_score', 0)}")
indicators = threat.get('threat_indicators', [])
if indicators:
print("Threat Indicators:")
for indicator in indicators:
print(f" - {indicator}")
if name == "main": main() ```_
Ressourcen und Dokumentation
Offizielle Mittel
- WebAssembly Offizielle Website - Offizielle WebAssembly-Dokumentation
- WABT GitHub Repository - WebAssembly Binary Toolkit
- Binaryen GitHub Repository - WebAssembly Optimierer und Compiler
- WebAssembly Specification - Offizielle WASM-Spezifikation
Lernressourcen
- WebAssembly MDN Dokumentation - umfassende WASM-Führung
- WebAssembly Studio - Online WASM Entwicklungsumgebung
- Awesome WebAssembly - Curated list of WASM Resources
- WebAssembly Security - Sicherheitsorientierte WASM-Ressourcen
Sicherheitsforschung
- WASM Malware Analysis - Malware-Analysetechniken
- WASM Reverse Engineering - RE Methoden
- Browser Security and WASM - Sicherheitsüberlegungen für Browser
Werkzeuge und Anwendungen
- Wasmer - Universal WebAssembly Laufzeit
- Warmtime - Standalone WebAssembly Laufzeit
- wasm-pack - Rust to WebAssembly Workflow
- Emscripten - C/C++ zu WebAssembly Compiler