关于 wakaru
Wakaru 是面向开发者的命令行技能,用于检查生产环境中的 JavaScript。它可反编译压缩或转译代码、拆分受支持的打包文件,并提供源映射与 Bun 可执行文件提取流程。
主要功能
- 01反编译压缩和转译后的 JavaScript
- 02将受支持的打包文件拆分为模块
- 03提取 Bun 可执行文件中的文件
- 04借助源映射恢复名称
- 05重建 Vue 3 SFC 文件
- 06解码 React Server Components 载荷
适用场景
- 01检查压缩堆栈跟踪所指向的代码
- 02审计网站或依赖实际发布的文件
- 03不运行 Bun 可执行文件而提取内嵌 JavaScript
- 04查看恢复的 Vue 组件或 RSC 载荷
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pionxzh/ wakaru --skill wakaru安装后在 Claude Code 中输入/wakaru确认已加载。
详细介绍
Wakaru — JavaScript 反编译器和捆绑包解包工具
Wakaru 可从生产环境中的 JavaScript 还原出易读的源代码:将捆绑包拆分为模块,逆转转译器辅助函数(async/await、类、JSX、展开运算符、可选链等),并撤销压缩。它以确定性方式还原结构,只应用保守的重命名启发式规则——除非提供 source map,否则大多数混淆后的局部变量名仍会很短。
适用场景
- 文件只有一整行,或充斥着
_interopRequireDefault、__awaiter、e,t,r参数、void 0、!0/!1。 - 你有 webpack 捆绑包、受支持的 Vercel ncc CommonJS 输出(带 IIFE webpack 引导程序)、Turbopack(Next.js 15.3+)分块,或 esbuild/Bun/Metro/Browserify/Cocos Creator 2.x/Closure ModuleManager/SystemJS/AMD/Rollup/Vite 捆绑包,需要提取其中的独立模块。
- 你有一个 Bun 单文件 PE、Mach-O 或 ELF 可执行文件,需要在不运行它的情况下提取其中嵌入的 JavaScript。
- 你有一个 Google Tag Manager 容器(
gtm.js),需要将其中的 Custom HTML 和 Custom JavaScript 代码分别保存为文件:wakaru gtm.js --unpack -o out/会写入macros/、tags/和index.md,说明每个__gtm_macro_<n>的作用以及每个标签的触发时机。 - 你需要获取 Bun 单文件可执行文件中存储的所有文件,包括二进制资源、WebAssembly、原生扩展或嵌入式数据库。
- 你有已编译的 Vue 3 组件 JavaScript,希望生成
.vue文件(尽力还原)以供检查。 - 堆栈跟踪指向无法阅读的供应商代码或压缩代码。
- 你正在审计网站或依赖项实际提供的内容。
设置
需要使用 CLI。建议通过 npx 运行(无需全局安装):
npx wakaru --version
如果需要反复调用,可安装一次:npm install -g wakaru@latest。
本文档中的 wakaru 均指 npx wakaru,除非已全局安装。
核心工作流
1. 反编译单个文件
适用于单个已压缩或已转译的文件。使用 --json 可输出结构化内容。不使用
-o 时,反编译后的源代码会包含在 JSON 的 code 字段中;使用 -o 时,
文件仍会写入磁盘,且会省略 code:
echo '<code>' | wakaru --json
# → {"code":"...readable...","warnings":[],"elapsed_ms":N}
也可将文件写入另一个文件:wakaru input.js -o output.js(省略 -o 时输出到标准输出)。
2. 解包 bundle(重要)
一个 bundle 可能会展开成数千个模块——不要把它们全部 导入上下文。先解包到目录中,检查 JSON 输出,然后只打开 需要的文件:
wakaru bundle.js --unpack --json -o out/
# → {"detected_formats":["webpack4"],"modules":[{"filename":"module-0.js"},...],
# "total":42,"failed":0,"warnings":[],"elapsed_ms":N}
使用一个全新的输出目录。除非传入 --force,否则 Wakaru 不会写入非空
目录;只有确认可以覆盖其中的内容后,才使用 --force。
然后按需读取 out/ 中的特定文件(例如 out/module-0.js)。先按大小
筛选(ls -lS out/)——最大的模块通常是随应用打包的库;应用代码往往更小、
数量也更多。
变体:
wakaru dist/ --unpack --json -o out/ # scan a build-output directory
wakaru entry.js chunk.js --unpack -o out/ # explicit entry + chunk files
wakaru ./compiled-app --unpack --raw -o out/ # extract a Bun single-file executable safely
wakaru bun extract ./compiled-app -o raw/ # dump every embedded Bun file as the bundler emitted it
提取 Bun 单文件可执行文件时,必须显式指定可执行文件路径
(目录扫描和 stdin 仅支持 JavaScript)。--unpack 会选择类似 JavaScript 的记录,并将它们
送入 bundle 拆分流程。如果 stderr 显示 note: <input> embeds N original source file(s) in Bun source maps,请运行它指定的 wakaru bun extract 命令,并在反编译输出之前读取
sources/。比较随包发布的表示形式时,优先使用
--raw:
它仍会拆分语句和声明,使各个块能够作为 ESM 链接,因此当字节内容必须完全一致时,请使用
wakaru bun extract。
当任务需要容器本身时,请改用 wakaru bun extract。它会将每条经过验证的文件记录写入
raw/files/,并将加载器元数据和字节范围记录在 raw/manifest.json 中。文件以字节形式存储,但
"encoding": "utf16le" 的记录(Bun 1.4.1+ 中的非 ASCII 文本)会以 UTF-8 写入;其中的
bytes 和 executable_range 描述存储的 UTF-16 数据,而 output_bytes 描述写入文件的数据。
如果应用使用 --sourcemap 编译,raw/sources/ 会包含 bundle 之前的原始文件
(例如带类型和注释的 TypeScript),而清单的 sources 列表会将每个原始 path 映射到其
output_path。反编译前请先检查它:如果该目录存在,请读取其中的文件,而不要读取打包后的 JavaScript。路径中的
.. 组件会写为 %2E%2E。列在 skipped_sources 中的记录对应的映射文件无法被 Wakaru 读取;
其中缺少源文件,因此请改用其反编译后的 JavaScript。添加 --json 可在 stdout 上输出相同的清单。
--include-internals 还会输出不透明的 Bun source map、JavaScriptCore 字节码
和 module-info 区域;不要将 source-map.bunmap 视为 v3 JSON map。
不加此标志时会写入原始源文件。
提取器支持 Bun 1.3.3+。
除非 bundle 带有可用的命名提示(资源路径、依赖映射请求、原始输入路径),否则
模块文件名为 module-<id>.js;有命名提示时会生成易读的相对文件名,发生冲突时会确保文件名唯一。原始输出
会保留暂定的提取名称。
需要将恢复出的模块与输入进行核对时,请在解包命令中添加
--provenance。在 out/provenance.json 中查找该模块生成的文件名,以查看源输入和 [start, end) 字节范围。
3. 存在 map 时恢复名称 / 原始源文件
wakaru input.js --source-map input.js.map -o output.js # recover names
wakaru extract input.js.map -o src/ # dump sourcesContent
输入参数 --source-map 仅支持单文件,且不能与
--unpack 一起使用;提取出的模块不会保留 bundle 生成的坐标。
需要为解包后的输出生成 map 时,请使用 --emit-source-map。
4. 将 Vue 3 组件恢复为 SFC 工件
当输入是编译后的 Vue 3 组件 JavaScript 或可能包含此类内容的
bundle 时,使用 --vue-sfc。恢复采用尽力而为的方式,且只会添加内容:解包模式
仍会为每个模块写入 JavaScript,可恢复的 Vue 模块还会生成同级 .vue 工件。
wakaru input.js --vue-sfc -o output.js
wakaru input.js --vue-sfc -o App.vue
wakaru bundle.js --unpack --vue-sfc --json -o out/
处理单个文件时,使用 -o 写入恢复后的 Vue 输出;不使用时,标准输出
仍为 JavaScript。进行批量分析时,建议使用 --unpack --vue-sfc --json,并先
检查 JSON 输出。每个 modules 条目都描述一个输出工件。其 kind 为
javascript 或 vue_sfc;与 Vue 相关的 status 值为
recovered_vue_sfc、vue_sfc_source_js 和 vue_sfc_fallback_js。打开
恢复后的 .vue 文件检查模板,但如果恢复过程回退或结果看起来过于依赖启发式方法,
请保留配对的 JavaScript 工件。不要将恢复后的 SFC 当作原始源码展示。
5. 解码捕获的 React Server Components 载荷(实验性)
React Server Components 载荷(React 的 Flight 线格式)是数据,而不是
JavaScript:不要对其进行反编译或解包。Next.js 会在页面 HTML 中将其嵌入为
self.__next_f.push(...) 调用。
wakaru rsc page.html -o rsc.json # saved Next.js page or script
wakaru rsc payload.rsc -o rsc.json # raw payload rows
JSON 包含 rows(十六进制 id、tag、kind、原始 payload,以及
React 解析后的 json)、assets(载荷加载的脚本和样式表路径)、
scripts(页面的 <script src> 文件,其中包含载荷未指明的打包器运行时;下载这两个列表中的文件并传递给 --unpack),以及 problems(未能解码的行和 push 调用;其余内容仍会写入)。format 的值为 raw 或
next.__next_f。不含载荷的输入会报错。模型行会将 React 的 $
引用("$L3")保留为字符串:不会重建这些引用所描述的树。
输出内容可能在任何版本中发生变化。
重度混淆的输入
对于字符串数组编码、控制流扁平化、VM 保护器及类似混淆,先使用 webcrack 去除混淆。解包和反混淆交由 Wakaru 处理:
# 1. Strip the obfuscation; leave unpacking and unminifying to Wakaru.
npx webcrack --no-unpack --no-unminify obfuscated.js > deobfuscated.js
# 2. Recover readable modules.
npx wakaru deobfuscated.js --unpack -o out/
重写级别——根据意图选择
--level minimal— 几乎不改变语义。安全审查、审计或差异比较时优先使用, 以尽量降低语义风险,但不要将其输出视为正式的等价性保证。--level standard— 默认值;兼顾可读性和正确性。--level aggressive— 最大限度提升可读性;使用更强的启发式方法,可能会 改变边缘情况下的行为。只需理解代码时使用。--unpack=inspect— 递归保留更细粒度的作用域提升边界,以便进行 静态检查。生成的模块图可能无法保留运行时初始化顺序;每次使用此模式时,CLI 都会打印警告。 可另外添加--raw以跳过可读性处理流程;使用--raw时,--level不起作用。
默认情况下,Wakaru 只会移除自身转换引入的死代码,并保留输入中原有的死代码。
需要进行完整的可达性扫描时,使用 --dce。
解读输出
- 退出代码 0 = 成功,非零 = 致命错误(参数错误、I/O 错误)或至少出现一条错误级警告。错误会输出到 stderr;
--json的输出会写入 stdout。 - 检查每条 JSON 警告中的
is_error字段。is_error: false的条目不会导致致命错误。出现错误级警告时,命令会以非零代码退出,但 Wakaru 仍会写入 JSON 输出和所有产物;没有错误级警告的模块仍可使用。 - 使用
--diagnostics检测反编译或解包时产生的声明冲突,包括var与let/const冲突,以及无法重新解析的输出。duplicate_declaration和output_parse_*警告属于错误级警告;合法的重复var声明不会被视为错误。未使用--diagnostics时,不会重新解析生成的模块。 cross_module_class_call警告(非错误)表示该模块在运行时可能会不带new调用恢复出的类。如果输出必须能够执行,请使用--level minimal重新运行。commonjs_export_unrecovered警告(非错误)表示 ESM 输出模块仍通过exports或module.exports访问所列导出。这些访问在运行时会抛出ReferenceError,因此应将该模块的导出接口视为不完整。- 如果某个模块保留了
require()调用(例如延迟调用、条件调用或副作用之后的调用),它就会保持为 CommonJS:ESM 不支持require。commonjs_require_unrecovered警告(非错误)表示 ESM 输出模块仍会为所列说明符调用require;这些调用在运行时会抛出错误。 commonjs_require_of_esm警告(非错误)表示 CommonJS 输出模块要求加载一个现在已恢复为 ESM 的模块,因此require会返回该模块的命名空间;如果读取已被替换的module.exports值,或读取互操作处理已移除、或提供方没有默认导出的模块的默认导出,得到的会是命名空间;写入该命名空间则会失败。commonjs_exports_escape警告(非错误)表示某个模块将提供方的 exports 对象传递给了另一个模块中的函数,或传递给了 Wakaru 无法跟踪的函数,而该提供方现在是 ESM。如果该函数写入此对象,运行时就会抛出错误;运行输出前请检查该调用。missing_imported_name警告(非错误)表示 ESM 输出模块导入了其同级 ESM 模块未导出的名称。Node 无法链接该模块,因此应将该依赖边以及所有通过它导入的模块视为损坏的输出,而不是到其他位置查找缺失的导出。- 使用
--diagnostics时,es_source_kept_commonjs警告(非错误)会指出某个模块虽然输入看起来是从 ES 模块编译而来,却仍保留为 CommonJS,并提供依据和保留的 require 调用。其导入仍是require调用;请将它们视为导入处理。 .cjs或.cts输入会被反编译为 CommonJS:其require()调用和module.exports会保留,因此输出中没有可跟踪的导入。--unpack目前尚不适用此规则:.cjs输入或恢复出的模块仍可能生成 ESM 语法,而 Node 无法从.cjs文件加载该语法。- 使用打包器重新构建解包输出前,请检查默认导入了设置
__esModule的 CommonJS 同级模块的 ESM 模块:Node 会读取module.exports,而打包器会读取exports.default(通常为undefined)。将所有不含模块语法(import、export、import.meta或顶层await)的文件改名为.cjs,包括脚本文件;更新说明符,并在输出根目录添加{"type": "module"}。 runtime_residual警告(非错误)表示该模块仍会调用输出中未定义的打包器运行时辅助函数,例如__turbopack_context__.L(...)(Turbopack 分块加载)、__turbopack_context__.P(...)(路径解析)、延迟import()外层的 webpackrequire.e/require.t,或输出未链接任何模块的 webpackrequire(id)(消息会说明该 id 不在任何输入中、位于不透明模块中,还是存在于构建中的多个模块中)。照常阅读该模块;只有该调用尚未解析。对于 webpack,请确认包含所加载模块的分块文件已列入输入,且仅需确认一次。- 解包 JSON 中的
failed统计至少出现一条错误级警告的不同模块数量(反编译失败、声明冲突、输出解析失败);total是模块总数。failed > 0时,退出代码必定非零。如果failed < total,请照常阅读其他模块,并报告失败的模块。 - 使用
--vue-sfc时,recovered_vue_sfc表示已写入.vue产物;vue_sfc_source_js是该恢复模块对应的 JavaScript;vue_sfc_fallback_js表示该模块看起来像 Vue 模块,但仍以 JavaScript 形式保留。 - 如果没有源映射,输出中出现混淆后的短名称(
e、t、n)是正常的——Wakaru 只会在代码提供依据时重命名。如果名称很重要,请结合 LLM 重命名工具或源映射使用。
安全
仅反编译你获准分析的代码。阅读第三方发布的内容属于合法的安全研究和调试活动;未经同意将其用于攻击目标可能违法。你有责任遵守相关规定。