View8 is a static analysis tool designed to decompile serialized V8 bytecode objects (JSC files) into high-level readable code. To parse and disassemble these serialized objects, View8 utilizes a patched compiled V8 binary. As a result, View8 produces a textual output similar to JavaScript.
- Python 3.x
- Disassembler binary. Available versions:
- V8 Version
9.4.146.24(Used in Node V16.x) - V8 Version
10.2.154.26(Used in Node V18.x) - V8 Version
11.3.244.8(Used in Node V20.x)
For compiled versions, visit the releases page.
input_file: The input file name.output_file: The output file name.--path,-p: Path to disassembler binary (optional).--disassembled,-d: Indicate if the input file is already disassembled (optional).--export_format,-e: Specify the export format(s). Options arev8_opcode,translated, anddecompiled. Multiple options can be combined (optional, default:decompiled).
To decompile a V8 bytecode file and export the decompiled code:
python view8.py input_file output_fileBy default, view8 detects the V8 bytecode version of the input file (using VersionDetector.exe) and automatically searches for a compatible disassembler binary in the Bin folder. This can be changed by specifing a different disassembler binary, use the --path (or -p) option:
python view8.py input_file output_file --path /path/to/disassemblerTo skip the disassembling process and provide an already disassembled file as the input, use the --disassembled (or -d) flag:
python view8.py input_file output_file --disassembledSpecify the export format(s) using the --export_format (or -e) option. You can combine multiple formats:
v8_opcodetranslateddecompiled
For example, to export both V8 opcodes and decompiled code side by side:
python view8.py input_file output_file -e v8_opcode decompiledBy default, the format used is decompiled.
The V8 bytecode version is stored as a hash at the beginning of the file. Below are the options available for VersionDetector.exe:
-h: Retrieves a version and returns its hash.-d: Retrieves a hash (little-endian) and returns its corresponding version using brute force.-f: Retrieves a file and returns its version.
The v8 version of a .jsc file can be found using one of the following methods:
- https://j4k0xb.github.io/v8-version-analyzer
- VersionDetector.exe
- If the Node.js binary is available:
./path_to_node -p process.versions.v8 - If the Electron binary is available:
- Linux/Mac:
ELECTRON_RUN_AS_NODE=1 ./path_to_electron_app -p process.versions.v8 - Windows:
set ELECTRON_RUN_AS_NODE=1 && path_to_electron_app -p process.versions.v8
- Linux/Mac:
- If the Electron version is known: Find the
v8field in https://releases.electronjs.org/releases.json - If the Node version is known: Find the
v8field in https://nodejs.org/dist/index.json
Sometimes there isn't a matching v8 version because it has been edited. In this case, just select the closest one before.
Guide/disassembler/patch based on v8dasm and https://github.com/v8/v8/tree/10.6.194.26.
-
Check out your v8 version: https://v8.dev/docs/source-code
-
Apply the patch:
git apply -3 v8.patch
It's expected that a few merge conflicts occur for different versions, resolve them manually.
-
Create a build configuration:
python tools/dev/v8gen.py x64.release
-
Edit the build flags in
out.gn/x64.release/args.gn:dcheck_always_on = false is_component_build = false is_debug = false target_cpu = "x64" use_custom_libcxx = false v8_monolithic = true v8_use_external_startup_data = false v8_static_library = true v8_enable_disassembler = true v8_enable_object_print = true
- For Node: add
v8_enable_pointer_compression = false
- For Node: add
-
Build the static library:
ninja -C out.gn/x64.release v8_monolith
-
Compile the disassembler:
-
For Node:
clang++ v8dasm.cpp -g -std=c++20 -Iinclude -Lout.gn/x64.release/obj -lv8_libbase -lv8_libplatform -lv8_monolith -o v8dasm
-
For Electron:
clang++ v8dasm.cpp -g -std=c++20 -Iinclude -Lout.gn/x64.release/obj -lv8_libbase -lv8_libplatform -lv8_monolith -o v8dasm -DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX
-