Skip to main content

reverse-engineer-js

Reverse-engineer minified or obfuscated JavaScript bundles. Primary tool: humanify (humanifyjs) — uses an LLM to rename mangled identifiers back to meaningful names. Default model: gemini-3.8-flash. Use when the user says 'deobfuscate this bundle', 'humanify this', 'rename minified vars', 'reverse engineer this JS', 'what does bundle.js do', or is working in a project with a deobfuscated `og/` or `modules/` folder fed by humanify. Covers humanify CLI invocation, the pseudo-TTY workaround for cursorTo crashes, single-module extraction from a bundle, and chaining with beautifiers.

跳到安装

来源信息

仓库
vladmdgolam/agent-skills
最近来源活动
2026年9月7日 21:06
检测到的 SKILL.md 语言
英语
星标
8
分支
1

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
reverse-engineer-js
description
Reverse-engineer minified or obfuscated JavaScript bundles. Primary tool: humanify (humanifyjs) — uses an LLM to rename mangled identifiers back to meaningful names. Default model: gemini-3.8-flash. Use when the user says 'deobfuscate this bundle', 'humanify this', 'rename minified vars', 'reverse engineer this JS', 'what does bundle.js do', or is working in a project with a deobfuscated `og/` or `modules/` folder fed by humanify. Covers humanify CLI invocation, the pseudo-TTY workaround for cursorTo crashes, single-module extraction from a bundle, and chaining with beautifiers.
# Reverse Engineer JS LLM-assisted deobfuscation of minified / mangled JavaScript using [humanifyjs](https://github.com/jehna/humanify) plus surrounding tooling for extracting and reintegrating modules. # Tools at a glance | Tool | Purpose | When | |------|---------|------| | `humanifyjs` (npx) | Rename mangled vars/functions via LLM | Mangled but already valid JS | | `prettier` / `js-beautify` | Reformat single-line minified code | Before humanify, if needed | | `webcrack` | Unpack webpack / browserify bundles into per-module files | When bundle is one big file | | Source-map sleuthing | `// # sourceMappingURL=...` may exist next to the bundle | Always check first — beats LLM rename | Always check for a sourcemap (`bundle.js.map` or `sourceMappingURL` comment in the file) **before** spending tokens on humanify. If found, original sources are recoverable for free. # Default humanify invocation Use Gemini unless the user says otherwise: ```bash npx humanifyjs gemini -m "gemini-3.8-flash" -o <outputDir> <inputFile> ``` Requires `GEMINI_API_KEY` in env (the project's root `.env` is the usual place). Other backends: ```bash # OpenAI npx humanifyjs openai --apiKey="$OPENAI_API_KEY" --model gpt-4.1-mini bundle.js # Local (slower, free) npx humanifyjs local bundle.js ``` # Critical gotchas ## 1. Pseudo-TTY required in non-interactive shells humanify calls `process.stdout.cursorTo(...)` for its progress bar. In Claude Code / CI / piped contexts, stdout is not a TTY and the call **crashes with `TypeError: process.stdout.cursorTo is not a function`**. Wrap the call in `script -q /dev/null`: ```bash script -q /dev/null npx humanifyjs gemini -m "gemini-3.8-flash" -o "$OUT" "$IN" ``` (macOS/BSD `script` syntax. On Linux: `script -qc "<cmd>" /dev/null`.) ## 2. Output filename is fixed humanify always writes its result as `<outputDir>/deobfuscated.js` regardless of input filename. Don't expect `module_1234.js` in → `module_1234.js` out. ## 3. Long files = long runs humanify processes top-level declarations sequentially with one LLM call each. A 5 MB bundle can take 30+ minutes. Strategies: - Run on **single modules** extracted from the bundle, not the whole thing - Pre-split with `webcrack` first if the bundle is webpacked - Pick the cheapest model that still reads the code well. `gemini-3.8-flash` is the default here; on a very large bundle a lite variant (`gemini-3.5-flash-lite`) cuts the per-declaration cost, at some accuracy cost on dense code ## 4. Keep an archive of the original Before any rewrite, copy the pristine bundle to `archive/bundle.original.js`. humanify is non-deterministic and you may want to re-run with a different model. # Workflow A: Whole-bundle deobfuscation When the bundle is small (<500 KB) or you have time: ```bash mkdir -p archive out cp bundle.js archive/bundle.original.js script -q /dev/null npx humanifyjs gemini \ -m "gemini-3.8-flash" \ -o out bundle.js # result: out/deobfuscated.js ``` Then optionally run `prettier --write out/deobfuscated.js` for nicer formatting. # Workflow B: Single-module extraction (large bundles) Common in fxhash / generative-art bundles: a single bundle contains many `id: (params) => { ... }` modules and you only want to humanify a few interesting ones. 1. **Identify the module ID** — search the bundle for distinctive strings, then trace back to the enclosing `<id>: (e, t, n) => {` opener. 2. **Extract the module body** — match the opener, count braces (respecting strings) until the matching `}`. 3. **Wrap as a standalone arrow** — write `(e, t, n) => { <body> }` to a temp file. humanify needs valid top-level code. 4. **Run humanify** — `script -q /dev/null npx humanifyjs gemini -m "gemini-3.8-flash" -o "$OUT" "$IN"`. 5. **Unwrap** — strip the `(e, t, n) => { ... }` shell back off the result. 6. **Save and stub** — write the deobf'd body to `modules/module_<id>_<name>.js`, replace the body in the bundle with a stub like `<id>: (e, t, n) => { window.DEOBF[<id>](e, t, n); }`. If the project already has a `scripts/deobfuscate.js` (or similar), reuse it — the brace-counting / string-escape logic is finicky enough that re-deriving it for each new bundle is a waste. A typical script: takes a numeric module ID, extracts the body from `bundle.js`, runs humanify on the wrapped function, unwraps, and writes `modules/module_<id>_<name>.js`. # Workflow C: Webpack bundle → per-module files When dealing with a webpack bundle, [webcrack](https://github.com/j4k0xb/webcrack) splits modules cleanly before humanify even runs: ```bash npx webcrack bundle.js -o webcracked/ # Then humanify each module of interest: script -q /dev/null npx humanifyjs gemini \ -m "gemini-3.8-flash" \ -o humanified webcracked/modules/123.js ``` # Examples ## Example 1: deobfuscate a small fxhash bundle **User says:** "humanify the bundle.js in this fxhash project" **Actions:** 1. Check for sourcemap: `head -c 4096 bundle.js | tail -c 200` — look for `sourceMappingURL`. None? Continue. 2. Confirm `GEMINI_API_KEY` in `.env`. Source it: `set -a; source .env; set +a`. 3. Archive: `mkdir -p archive && cp bundle.js archive/bundle.original.js`. 4. Run: `mkdir -p out && script -q /dev/null npx humanifyjs gemini -m "gemini-3.8-flash" -o out bundle.js`. 5. Beautify: `npx prettier --write out/deobfuscated.js`. **Result:** `out/deobfuscated.js` with renamed vars, ready to read. ## Example 2: deobfuscate one module out of a giant bundle **User says:** "Deobfuscate module 3658 from `og/bundle.js`, name it `treeGenerator`" **Actions:** 1. If the project already has a deobfuscation helper (e.g. `scripts/deobfuscate.js`), run it: `node scripts/deobfuscate.js 3658 treeGenerator`. 2. Otherwise: extract the module body by brace-counting, wrap as `(e, t, n) => { ... }`, run humanify with `script -q /dev/null`, unwrap, save to `modules/module_3658_treeGenerator.js`, stub the bundle. **Result:** New file in `modules/` with a readable version of the function; `bundle.js` shrunk by stubbing. ## Example 3: humanify crashed with `cursorTo is not a function` **User says:** "humanify just dies immediately" **Diagnosis:** Non-TTY stdout (this is the default in Claude Code's bash tool). **Fix:** Re-run wrapped in `script -q /dev/null <cmd>` (macOS) or `script -qc "<cmd>" /dev/null` (Linux). # Troubleshooting ## `cursorTo is not a function` **Cause:** stdout is not a TTY. **Fix:** wrap in `script -q /dev/null`. ## `GEMINI_API_KEY` not set **Cause:** humanify reads from process env, not from the project `.env` automatically. **Fix:** `set -a; source .env; set +a` in the same shell, or pass inline: `GEMINI_API_KEY=... npx humanifyjs gemini ...`. ## Output is identical to input (no renames) **Cause:** humanify only renames identifiers it considers mangled (short, single-letter). Already-readable code is left alone. **Fix:** confirm the input is actually obfuscated; if names like `useState` survive that's expected, not a bug. ## Rate limits / quota errors from Gemini **Cause:** large file, many top-level functions → many sequential LLM calls. **Fix:** switch to `local` backend for free local rename, or extract a single module (Workflow B) instead of the whole bundle. ## humanify takes hours **Cause:** big bundle, sequential per-function calls. **Fix:** pre-split with `webcrack`, or only humanify the modules you actually need. ## Output directory contains stale `deobfuscated.js` **Cause:** humanify writes to a fixed filename. A failed second run will pick up the previous good output. **Fix:** `rm -f $OUT/deobfuscated.js` before each run.
在 GitHub 查看