reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
Apache License 2.0 — see the repository root LICENSE file for the full text.
Copyright the AnalystAIPack contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0

View File

@@ -0,0 +1,94 @@
---
name: deobfuscating-malicious-javascript
description: 'Deobfuscates malicious JavaScript from droppers, web pages, and HTA/scriptlets:
unrolling string-array and char-code encodings, resolving eval/Function chains, and statically
recovering payloads and URLs without executing untrusted code. Activates for requests to
deobfuscate JavaScript, decode obfuscated JS, or analyze a malicious script dropper.'
domain: cybersecurity
subdomain: malware-analysis
tags:
- malware-analysis
- javascript
- deobfuscation
- document-malware
- droppers
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1059.007
- T1027
- T1140
d3fend:
- D3-FCR
- D3-DA
references:
- 'ECMAScript language specification — https://tc39.es/ecma262/'
- 'box-js malicious JavaScript sandbox — https://github.com/CapacitorSet/box-js'
---
# Deobfuscating Malicious JavaScript
## When to Use
- You have obfuscated JS (from a phishing page, HTA, `.js` dropper, or scriptlet) and need its real
behavior.
- You must recover hidden URLs, dropped commands, or a next-stage payload.
- You want to statically unroll common obfuscation rather than run untrusted code.
**Do not use** a real browser or `node` to execute the script for analysis — that runs the
malware. Use a sandboxed interpreter (box-js) or static transformation only.
## Prerequisites
- A safe analysis approach: static decoding, or a JS malware sandbox (box-js) in the lab.
- Familiarity with common obfuscation: string arrays, `String.fromCharCode`, hex/unicode escapes,
`eval`/`Function` chains, packers.
## Safety & Handling
- Treat the script as live code; never execute it outside an isolated sandbox.
- Defang recovered URLs and store dropped payloads password-protected.
## Workflow
### Step 1: Normalize and de-pack
Pretty-print the source and identify the obfuscation style (array-shuffle, eval-packer, charcode).
Decode static encodings first: hex/unicode escapes and base64 literals.
```bash
python scripts/analyst.py decode dropper.js
```
### Step 2: Unroll string arrays and char-code builds
Reconstruct strings built from arrays/`fromCharCode`/concatenation to reveal API names, URLs, and
commands.
### Step 3: Resolve eval/Function indirection — safely
Replace `eval`/`new Function` with logging (or a sandbox) so the constructed code is captured as
*data*, not executed, then recurse on the recovered layer.
### Step 4: Extract behavior and IOCs
Identify the dropper actions (WScript.Shell, ActiveX, fetch/XHR), recover URLs and dropped paths,
defang, and route payloads onward.
## Validation
- Static encodings (hex/unicode/base64) are fully decoded.
- String-array/charcode constructions are unrolled to readable strings.
- `eval`/`Function` layers are captured as data and recursed, with no untrusted execution.
## Pitfalls
- Running the script to "see what it does" and infecting the analysis host.
- Stopping at one layer when the dropper nests several.
- Missing environment-keyed branches (only acts on certain dates/locales) during static review.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the static JS decoder.
- ECMAScript spec and box-js (linked in frontmatter).

View File

@@ -0,0 +1,40 @@
# API Reference: Deobfuscating Malicious JavaScript
## Overview
`scripts/analyst.py` statically decodes common JS obfuscation: `\xHH`/`\uHHHH` escapes,
`String.fromCharCode(...)` sequences, and standalone base64 string literals, then extracts and
defangs URLs. It executes nothing; dynamic `eval`/`Function` layers require a sandbox (box-js).
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| (stdlib) | — | base64, regex, JSON, file IO |
## External tools
| Tool | Purpose |
|------|---------|
| box-js | Sandboxed execution of `eval`/`Function` layers without real browser/WScript |
## Core functions
### `decode(source)`
Applies escape, fromCharCode, and base64 decoding; returns a preview, decoded base64, and defanged
URLs.
### `_decode_escapes` / `_decode_fromcharcode` / `_decode_b64_literals`
The individual static-decoding passes.
## Usage
```bash
python scripts/analyst.py decode dropper.js
```
## Sources
- ECMAScript language specification — https://tc39.es/ecma262/
- box-js malicious JavaScript sandbox — https://github.com/CapacitorSet/box-js
- Common JS obfuscation families (string arrays, fromCharCode, eval-packers), established practice

View File

@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""Statically decode common JavaScript obfuscation layers.
Without executing anything, this resolves frequent static encodings: ``\\xHH`` and ``\\uHHHH``
escapes, ``String.fromCharCode(...)`` sequences, and standalone base64 string literals. It also
extracts URLs from the decoded text and defangs them. Intended as a first-pass static aid before
a sandbox (box-js) for dynamic layers.
"""
from __future__ import annotations
import argparse
import base64
import binascii
import json
import re
import sys
from pathlib import Path
RE_HEX = re.compile(r"\\x([0-9a-fA-F]{2})")
RE_UNI = re.compile(r"\\u([0-9a-fA-F]{4})")
RE_FROMCHARCODE = re.compile(r"String\.fromCharCode\(([^)]*)\)", re.I)
RE_B64 = re.compile(r"['\"]([A-Za-z0-9+/]{24,}={0,2})['\"]")
RE_URL = re.compile(r"https?://[^\s'\"<>)]+", re.I)
def _decode_escapes(text: str) -> str:
text = RE_HEX.sub(lambda m: chr(int(m.group(1), 16)), text)
text = RE_UNI.sub(lambda m: chr(int(m.group(1), 16)), text)
return text
def _decode_fromcharcode(text: str) -> str:
def repl(m: re.Match) -> str:
parts = re.split(r"[,\s]+", m.group(1).strip())
chars = []
for p in parts:
p = p.strip()
try:
chars.append(chr(int(p, 0)))
except (ValueError, TypeError):
return m.group(0)
return '"' + "".join(chars) + '"'
return RE_FROMCHARCODE.sub(repl, text)
def _decode_b64_literals(text: str) -> list[str]:
out = []
for m in RE_B64.finditer(text):
blob = m.group(1)
try:
dec = base64.b64decode(blob).decode("latin-1")
if sum(c.isprintable() for c in dec) > len(dec) * 0.8:
out.append(dec)
except (binascii.Error, ValueError):
continue
return out
def _defang(url: str) -> str:
return url.replace("http", "hxxp").replace(".", "[.]")
def decode(source: str) -> dict:
stage1 = _decode_escapes(source)
stage2 = _decode_fromcharcode(stage1)
b64 = _decode_b64_literals(stage2)
urls = sorted(set(RE_URL.findall(stage2)) | {u for d in b64 for u in RE_URL.findall(d)})
return {
"decoded_preview": stage2[:1500],
"base64_decoded": b64[:20],
"urls": [_defang(u) for u in urls],
"note": "static decode only; use box-js sandbox for eval/Function layers",
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Statically decode obfuscated JS")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("decode")
p.add_argument("file")
args = parser.parse_args(argv)
source = Path(args.file).read_text(encoding="utf-8-sig", errors="replace")
print(json.dumps(decode(source), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())