rea-reverse

WASM 模块分析与 WASM 转 WAT

打开 .wasm 文件,查看段(section)、导入、导出、工具链、特性和体积最大的函数;需要看代码时,再用 wabt 转成可读的 WAT 文本。

文件不会离开你的浏览器. 解析和反汇编都在一个禁止联网的 Web Worker 中本地完成,不上传任何内容。 如何自己验证

把 .wasm 文件拖到这里

或

文件在浏览器中读取,上限 256 MiB。

WebAssembly 模块是一个紧凑的二进制文件,但它并不神秘。它的结构按编号的 section 排列:用到哪些类型、从宿主环境导入哪些函数、导出哪些函数和内存、有哪些数据段,往往还有自定义段,写着它是哪个编译器生成的、各个函数叫什么名字。拿到一个陌生的 .wasm 文件,想知道的大部分信息都能从这些结构里读出来,一条指令都不用执行。

这个工具就在你的浏览器里读取这些结构。选择一个 .wasm 文件,马上就能看到结构化的分析报告;如果需要完整的文本格式,点一下就能把模块转成 WAT。文件不会被上传。

能做什么

输入。 一个 .wasm 文件,分析报告最大支持 256 MiB,WAT 转换最大支持 32 MiB。只支持 WebAssembly 核心模块(二进制版本 1),不支持 Component Model 组件。

分析报告。 页面自带一个专门编写的轻量二进制解析器来读取模块结构。它不执行模块,也不解码函数体。报告包括:

  • 模块概要:文件大小、二进制版本,以及类型、导入函数、定义函数、表、内存、全局变量、tag、start 函数、元素段、数据段的数量。
  • section 表:每个 section 的 id、名称、字节偏移和大小,包括 name、producers、target_features 这类自定义段。
  • 导入表和导出表:模块需要宿主提供什么、它向宿主提供什么。光看导入的模块名往往就能判断运行环境,例如 wasi_snapshot_preview1 或 env。
  • 工具链识别:在 Rust、wasm-bindgen、Emscripten、Clang、Go、TinyGo、AssemblyScript、WASI、.NET、Zig 之中给出推测,并附上每条推测所依据的证据(某个导入名、某种导出模式、某条 producers 记录)。
  • producers 和 target_features:存在时列出这两个自定义段的内容。
  • post-MVP 特性:能从模块结构上看出来的后续特性,例如多内存、用于异常处理的 tag、特定形式的导入和类型。
  • 最大的函数:按字节大小排名前 20 的函数体;模块带有 name section 时同时显示函数名。
  • 警告:解析器无法解码的 section 会作为警告列出,而不是悄悄跳过。

WAT 转换。 点击 生成 WAT 按钮,把模块转换成 WebAssembly 文本格式。只有点击时,页面才会加载 wabt.js 1.0.39(gzip 后约 218 KB,wabt 自身的 wasm 以 base64 形式内嵌在脚本里)。结果显示在一个 <pre> 块里,可以复制,也可以下载为 .wat 文件。wabt 支持的特性全部启用,包括 SIMD、threads、GC、memory64、exceptions 等,并读取 name section 生成可读的名字。输出超过 500 万字符时会截断并给出提示,更大的输出请用下载按钮或下文的命令行工具。

原理

WebAssembly 二进制格式以魔数 \0asm 和 4 字节版本号开头,后面是一个个 section。每个 section 有 1 字节的 id 和一个 LEB128 编码的长度,所以解析器不需要理解内容,也能从一个 section 跳到下一个。页面的解析器正是这样建立 section 表,然后解码描述模块“形状”的那些 section:类型、导入、函数、表、内存、全局、导出、start、元素、data count、tag,以及自定义段 name、producers 和 target_features。对于代码段,它只读取每个函数体的大小,并据此给最大的函数排名,从不解释指令。

工具链识别是作用在这些数据上的一组规则。每种工具链都会留下可辨认的指纹:wasm-bindgen 会添加特征性的导入和导出,Emscripten 从 env 导入辅助函数,Go 的运行时从 gojs 导入,WASI 模块从 wasi_snapshot_preview1 导入,很多编译器还会在 producers 段里写上自己的名字。报告会列出命中的证据,方便你自己判断每条推测是否可信。

WAT 转换用的是 wabt 的读取器和文本输出器,和命令行工具 wasm2wat 是同一套代码。

隐私是怎么保证的

文件不会被上传:

  • 分析在你设备上的 Web Worker 中进行。Worker 的内容安全策略(CSP)是 connect-src 'none',浏览器根本不允许它发出任何网络请求。
  • 页面加载完成后,分析报告在断网状态下也能使用。
  • WAT 转换所需的 wabt 脚本,只有在你点击 生成 WAT 时才会从本站下载。如果你打开页面后断了网,又是第一次点击这个按钮,转换就会失败。这是有意的取舍:大多数访客只需要分析报告,不应该为了一个用不到的功能下载约 800 KB 的工具代码。
  • 统计事件只有 wasm_analyze 和 wasm_wat,只包含成功或错误码、文件大小区间和耗时区间,绝不包含文件名或任何文件内容。完整清单见隐私政策。
  • 工具页不展示广告。

如何自己验证

  1. 选择文件之前,打开浏览器开发者工具,切到 Network(网络) 面板。做一次分析,愿意的话再生成一次 WAT,然后逐条查看请求:没有任何一条带着你的文件。点击 WAT 按钮唯一触发的请求,是从本站下载 wabt 脚本。
  2. 或者先打开本页,再断开网络(关闭 Wi-Fi,或在 Network 面板勾选 Offline),然后做分析,照样能完成。

局限

  • 不反编译成高级语言。 你得到的是结构信息和 WAT,不是 C、Rust 或 JavaScript 源码。
  • WAT 很长。 即使是小模块也会产生成千上万行,而且文本格式几乎就是指令级别的。先用分析报告决定从哪里看起。
  • 不做验证。 wabt 只负责读取模块、输出文本,不运行验证器(validator),所以无效的模块也可能转换成功。转换成功不代表模块合法。
  • 不支持 Component Model。 组件(较新的分层格式)不受支持,只支持版本 1 的核心模块。
  • 剥离过的模块没有名字。 压缩或混淆过的模块通常没有 name section,函数只能以编号显示。
  • 看不到运行时行为。 模块从不执行,因此运行时才决定的东西,例如实际调用了哪些导入、加载了什么数据,都看不到。
  • 工具链识别是启发式的。 它依赖指纹,可能漏判或误判,经过后处理的模块尤其如此。

常见问题

文件真的没有上传吗?

是的。负责分析的 Worker 完全不能联网。你可以用 Network 面板或断网的方式确认,具体做法见如何自己验证。

为什么断网时“生成 WAT”失败了?

wabt 脚本只在你第一次点击按钮时才下载。如果在那之前页面就断了网,脚本就无法加载。重新联网再试即可;分析报告本身不依赖它。

能打开 Component Model 的 .wasm 吗?

不能。只支持二进制版本 1 的核心模块。组件的文件头中 layer 字段不同,会被拒绝。

为什么看不到函数名?

函数名来自 name 自定义段,发布版本的构建经常会把它去掉。没有它时,函数只能以编号显示,例如 func 42。

WAT 输出提示被截断了,怎么拿到完整文本?

用下载按钮,或者在本地用 wabt 运行 wasm2wat module.wasm -o module.wat。页面上的显示在 500 万字符处截止,是为了不让浏览器卡死。

怎样离线复核报告?

安装 wabt,用 wasm-objdump -h module.wasm 查看 section 头,用 wasm-objdump -x module.wasm 查看导入、导出和其他 section 细节,用 wasm2wat --enable-all module.wasm 得到文本格式。结果应当和页面上的一致。

合规说明

请只用本工具分析你自己构建的模块、你获得授权分析的模块,或者公开分发的模块(例如检查你访问的网页加载了什么)。请遵守所分析软件的许可协议和适用于你的法律法规,包括其中限制逆向工程的条款。本工具不提供任何绕过授权、DRM 或其他保护措施的建议。

相关教程