reverse-eng-js
Reverse front-end JavaScript end to end: trace which script fires a given request, capture a signing/encryption function's real inputs at runtime, then rebuild the algorithm locally in Node.js with ev
Files2
View on GitHubSKILL.mdskills/reverse-engineering/reverse-eng-js/SKILL.md
GitHubFront-end JavaScript reverse engineering
When it applies
An in-scope web app computes something in JavaScript that you need to understand or reproduce:
a request signature, an encrypted body, anti-bot / risk-control fields, or a hidden WebSocket
protocol. web-client-side-signing-bypass covers the fast attack-side path (prove the guard is
client-side, get one replayable request); load this skill when you need the full algorithm
recovered and running locally in Node — for sustained fuzzing, logic audit, or documentation.
Target must be in scope.txt (tradecraft-scope-roe); observe only your own session.
Why it works
The page must run the algorithm in the browser before the request leaves, so both the code and every input to it are observable at runtime — minification only slows you down, it can't hide execution. Break on the outgoing request, walk the call stack to the signing function, lift it into Node, and the only thing left is the handful of browser globals it touches — which you shim strictly from observed errors, never from imagination.
Method
Principles: observe first · hook before you breakpoint, breakpoint last · rebuild from page evidence · one minimal patch at a time.
- Observe. Open the page with DevTools Network recording (Burp/mitmproxy upstream for the
raw view). Identify the target request and its computed params, then read the request's
Initiator stack to find the calling scripts. Global-search all loaded sources
(
Ctrl+Shift+Fin DevTools) for the param name and the usual suspects:sign,encrypt,md5,sha256,hmac,CryptoJS. - Capture. Set an XHR/fetch breakpoint on a unique URL substring (Sources panel).
When it pauses, walk up the call stack out of library frames into app code and read
locals/arguments — you want the signing function, the raw input string, and any key/secret
in scope. Lighter hooks (console overrides of
fetch,XMLHttpRequest.prototype.send,JSON.stringify) often yield the same evidence with less noise — snippets incheatsheet.md. - Rebuild. Copy the signing function plus its closure dependencies into a local Node
script. Before writing a single shim, confirm from page evidence: the real entry function,
the call order, where each parameter comes from, which browser objects it touches, and
whether it depends on time, randomness, storage, cookies, UA, canvas, or
crypto. Run it and record the first exception / first divergence — that, not intuition, drives step 4. - Patch the environment, strictly error-driven: shim only what the failure proves is
missing, one minimal causal unit per step — a plain value first, then a function stub, then
an object contract (
cheatsheet.mdhas a starter shim set). Re-run after every patch; success means the first divergence moved forward. - Deep-dive (optional). Only once the script reproduces the parameter stably: prettify
and deobfuscate for readability or logic audit (
reverse-eng-deobfuscationfor JSVMP, control-flow flattening, string-array ciphers, anti-debug). If all you needed was the parameter, skip this phase.
When a phase stalls, fall back one rung instead of forcing it: breakpoint → plain request observation; source guessing → runtime evidence; Node env-rebuild → back to the page for more forensics; deep deobfuscation → minimal reproducible chain.
Gotchas
- Never guess-shim
window/document/navigatorup front — evidence-first is the whole discipline; a shim list growing past ~10 objects means you picked the wrong entry point. - Time/random-dependent signatures — stub
Date.now()/Math.random()to the captured sample's values for a byte-identical comparison, then check the server's tolerance window. - Webpack code-splitting — the signer may live in a lazily loaded chunk: perform the action once, then search sources.
- Anti-debug (
debugger;loops, devtools-detection, timing checks) — neutralize the check itself or "Deactivate breakpoints"; heavy cases go toreverse-eng-deobfuscation. - WebSocket per-message signing follows the same path — hook the socket's
send.
Verify success
Given the same inputs (with time/nonce pinned to a captured sample), your Node script outputs
the identical signature or encrypted body as the page did. Then sign a fresh, unseen
payload, send it outside the browser, and the server accepts it — the endpoint is now as
fuzzable as an unsigned one; hand off to api-fuzzing or web-client-side-signing-bypass
step 5.
References
Chrome DevTools Sources/CDP docs; web-client-side-signing-bypass,
reverse-eng-deobfuscation, recon-js-analysis in this library.
Portions adapted from reverse-skill by zhaoxuya520, MIT License.