Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
jsc_deobfuscator — Static deobfuscation toolkit for compiled V8 JavaScript bytecode, focusing on JSCeal payloads. Provides pattern-driven filters, control-flow unflattening, string reconstruction, and optional LLM-assisted function renaming for analysis. | Kitploit
Tools/GitHubGitHub/hasherezade/jsc_deobfuscator
Static AnalysisReverse EngineeringMalware AnalysisBinary AnalysisLearning & Education
GitHubhasherezade/jsc_deobfuscator

jsc_deobfuscator

Static deobfuscation toolkit for compiled V8 JavaScript bytecode, focusing on JSCeal payloads. Provides pattern-driven filters, control-flow unflattening, string reconstruction, and optional LLM-assisted function renaming for analysis.

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
View Repository
Website
62512120 days agoReviewed by Kitploit
Share

JSC Deobfuscator

This tool is dedicated to statically deobfuscating compiled V8 JavaScript bytecode that was protected with javascript-obfuscator.

It operates on pseudocode produced by View8, rather than on the original JavaScript source. The project was developed and tested on JSCeal payloads.

The filters are pattern-driven and intended primarily as a research toolkit and reference implementation. The tool is not a general-purpose JavaScript deobfuscator, does not reconstruct the original source code, and does not produce runnable JavaScript. Its output remains View8 pseudocode intended for static inspection, searching, comparison, and function-tree export.

📖 Read Wiki

Safety notes

  • View8 serialized files use Python pickle. Loading a malicious or untrusted .pkl file can execute code. Only load serialized files that you generated locally with View8.
  • LLM-generated function names are hypotheses. Verify every important name against the function body, strings, APIs, paths, and data flow.

Requirements

  • Python 3.10 or newer;
  • Python dependencies from requirements.txt;
  • a V8 disassembler compatible with the exact V8 version used by the payload;
  • the brotli command-line utility for the Linux batch unpacking workflow;
  • Node.js only when using the included Brotli decompression fallback;
  • an API key or a reachable local model server when generating new LLM-assisted names. Applying an existing rename CSV does not require an LLM backend.

Create an isolated Python environment:

python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt

The OpenAI backend in deobf_ai.py additionally requires the OpenAI Python package:

python3 -m pip install openai

The Anthropic backend uses the HTTP API through requests. The Ollama backend expects a reachable Ollama server.

Deobfuscating JSCeal

1. Decompress the payload

The original JSCeal app.jsc payload is Brotli-compressed. On Linux, it can be decompressed with the brotli utility:

brotli -d app.jsc -o app.decompressed.jsc

The batch workflow under scripts/ performs this step with scripts/unpack_all.sh.

On Windows, or when the brotli command-line utility is unavailable, the included Node.js helper can be used as a fallback. It only decompresses the input and does not execute it:

node Utils/decompress-jsc.js app.jsc

It writes:

app.jsc.decompressed.jsc

2. Disassemble the V8 code cache

V8 code cache is version-specific. Use a disassembler built for the same V8 version as the payload.

The JSCeal samples used during development were based on V8 10.2.154.26. Default disassemblers from an unrelated V8 build will not work correctly.

The source tree contains the disassembler source and required V8 patches under:

Utils/disasm/v8dasm.cpp
Utils/disasm/patches/

A prebuilt Linux binary is distributed with the project release, while the source tree contains the source and patches needed to rebuild it. Detailed description is available on the project Wiki. After obtaining or building the matching v8dasm, run:

/path/to/v8dasm app.decompressed.jsc > app.jsc.disasm.txt

3. Decompile the disassembly with View8

Feed the disassembled file to view8.py and produce both serialized output for further processing and human-readable pseudocode:

mkdir -p decompiled

python3 View8/view8.py \
  --input_format disassembled \
  --inp app.jsc.disasm.txt \
  --normalize \
  --out decompiled/app.dec.txt \
  --export_format decompiled serialized

This produces:

decompiled/app.dec.txt
decompiled/app.dec.pkl

The --normalize option makes generated function identifiers reproducible across repeated disassembly and decompilation runs.

4. Apply all deobfuscation passes

There are separate filters for the individual obfuscation layers. They can be applied together to the serialized View8 output with deobf_all.py:

mkdir -p deobfuscated

python3 deobf_all.py \
  --inp decompiled/app.dec.pkl \
  --out deobfuscated/app.deobf.txt \
  --export_format decompiled serialized

The default string filter is variant 2, used by the majority of analyzed JSCeal payloads. To select the simpler string scheme explicitly, add:

--str_deobf 1

Typical outputs are:

deobfuscated/app.deobf.txt
deobfuscated/app.deobf.pkl
deobfuscated/app.deobf.txt.strings.txt
decompiled/app.dec.resolved_funcs.csv

The resolved-functions CSV is a sample-specific cache. When it is absent, the string pass recovers the required decoder configuration, writes the CSV, and continues deobfuscating strings in the same run. Later runs reuse the cache and are normally faster.

Do not reuse a resolved-functions CSV with a different decompiled payload.

5. Rename functions with an LLM

After all structural deobfuscation filters have been applied, deobf_ai.py can propose names that describe function behavior. It supports Anthropic, OpenAI, and Ollama backends.

Pass the model explicitly so that runs remain reproducible.

Anthropic

export ANTHROPIC_API_KEY='...'

python3 deobf_ai.py \
  --inp deobfuscated/app.deobf.pkl \
  --out deobfuscated/app.renamed.txt \
  --llm_backend anthropic \
  --model '<model-id>' \
  --export_format decompiled serialized

OpenAI

export OPENAI_API_KEY='...'

python3 deobf_ai.py \
  --inp deobfuscated/app.deobf.pkl \
  --out deobfuscated/app.renamed.txt \
  --llm_backend openai \
  --model '<model-id>' \
  --export_format decompiled serialized

Ollama

python3 deobf_ai.py \
  --inp deobfuscated/app.deobf.pkl \
  --out deobfuscated/app.renamed.txt \
  --llm_backend ollama \
  --model '<local-model>' \
  --ollama_url http://localhost:11434 \
  --export_format decompiled serialized

In the default mode, the renamer builds a direct-call tree starting from the entry function and renames only functions reached through calls. Add --greedy to include all visible function references, including callbacks and assigned handlers.

Resume from a rename CSV

The generated two-column CSV acts as a cache and allows an interrupted run to continue. Select an existing cache explicitly with --csv:

python3 deobf_ai.py \
  --inp deobfuscated/app.deobf.pkl \
  --out deobfuscated/app.renamed.txt \
  --csv deobfuscated/app.deobf.renamed_funcs.greedy.example-model.csv \
  --llm_backend anthropic \
  --model '<model-id>' \
  --greedy \
  --export_format decompiled serialized

In the normal mode, the CSV is treated as a potentially partial cache. Cached names are applied first, functions already covered by the cache are removed from the selected call or reference tree, and the LLM is invoked only for functions that remain unresolved. If the CSV completely covers that tree, no API key or LLM connection is required. If it covers only part of the tree, the selected backend is initialized and the newly generated mappings are appended to the same CSV.

Use the same tree mode that was used when the CSV was created. A CSV produced from a --greedy run normally needs --greedy again if the goal is to continue that run rather than only reuse the direct-call subset.

Apply an existing CSV without an LLM

Use --apply-csv-only when the CSV already contains the labels you want to apply, including reviewed, edited, imported, or rebased mappings:

python3 deobf_ai.py \
  --inp deobfuscated/app.deobf.pkl \
  --out deobfuscated/app.renamed.txt \
  --csv renamed_functions.normalized.csv \
  --apply-csv-only \
  --export_format decompiled serialized

This mode:

Download Tool