WebAssembly 逆向分析:反编译 Wasm 二进制并修改游戏数据
WebAssembly 逆向分析主要涉及静态分析与动态调试。通过 wasm2wat 工具可将二进制转为文本格式,利用浏览器开发者工具可定位内存对象并篡改数值。若逻辑在栈中,需修改 WAT 代码后重编译。防御措施包括去除符号、控制流平坦化及服务器端校验。掌握这些技术有助于理解网页高性能黑盒背后的逻辑。

WebAssembly 逆向分析主要涉及静态分析与动态调试。通过 wasm2wat 工具可将二进制转为文本格式,利用浏览器开发者工具可定位内存对象并篡改数值。若逻辑在栈中,需修改 WAT 代码后重编译。防御措施包括去除符号、控制流平坦化及服务器端校验。掌握这些技术有助于理解网页高性能黑盒背后的逻辑。

WebAssembly 是一种基于堆栈虚拟机的二进制指令格式。它类似于汇编语言,但比 x86 汇编更抽象。
浏览器加载 .wasm 文件,编译为机器码运行。
逆向 Wasm 的两种核心思路:
.wasm 反汇编为 .wat (WebAssembly Text) 或伪 C 代码,分析逻辑。WebAssembly.Memory(线性内存)。Wasm 加载与逆向流程:
逆向攻击路径 -> Wasm 运行环境
1. 下载 game.wasm -> 解码 -> Imports (函数/内存) -> 读写
工具:wasm2wat -> 可读汇编代码 (.wat)
工具:Console -> 直接修改数值
服务器 -> 浏览器 -> Wasm 二进制 -> Wasm 模块 -> JS 胶水代码 -> 实例化对象 (Instance) -> 线性内存 (ArrayBuffer)
在开始之前,你需要准备以下工具:
wasm2wat: 将二进制转为人类可读的文本格式(S-表达式)。wat2wasm: 将修改后的文本重新编译为二进制。假设我们正在玩一个网页小游戏,每次点击按钮,金币 +1。我们要把它改成 +1000。
打开 Chrome DevTools -> Network 面板,刷新页面,过滤 .wasm。找到 game.wasm 并下载。
使用 wasm2wat 工具:
wasm2wat game.wasm -o game.wat
打开 game.wat,你会看到类似这样的代码:
(module(import"env""memory"(memory $0 1))(func $add_gold (param $p0 i32)(result i32)(local $l0 i32) local.get $p0 ;; 获取参数(当前金币) i32.const 1;; 加载常量 1 i32.add ;; 执行加法 local.set $l0 ;; 存入局部变量 local.get $l0 ;; 返回结果)(export"add_gold"(func $add_gold)))
注:真实环境中的函数名通常被 stripped 掉了,只显示 func $f12,你需要根据上下文推断。
Wasm 的内存模型非常简单:它就是一个巨大的、线性的 JavaScript ArrayBuffer。 这意味着,JS 可以随意读写 Wasm 的内存!这是最简单的破解方式。
在 Chrome Console 中,寻找 Wasm 的实例对象。通常在全局变量或者 imports 对象中。
// 假设游戏把实例挂载到了 window.gameInstance
const memBuffer = window.gameInstance.exports.memory.buffer;
const memView = new Int32Array(memBuffer);
就像使用 Cheat Engine 一样:
memView.forEach((v, i) => { if(v===100) console.log(i) }) -> 得到索引 1024。1024 的值:memView[1024] -> 确实是 101。// 直接把金币改成 999999
memView[1024]=999999;
页面上的金币瞬间暴涨。
如果金币逻辑没有暴露在全局内存中,或者是纯栈操作,我们就需要修改代码本身(Patch)。
回到刚才反编译的 game.wat 文件。
找到加法逻辑:
local.get $p0 i32.const 1;; <--- 这里是增加的数量 i32.add
我们将 1 修改为 1000:
local.get $p0 i32.const 1000;; <--- 修改为 1000 i32.add
wat2wasm game.wat -o game_hacked.wasm
我们不能直接替换服务器文件,但我们可以通过 Chrome 的 Local Overrides 功能,或者写一个 TamperMonkey 脚本拦截网络请求。
TamperMonkey 脚本思路:
const originalFetch = window.fetch;
window.fetch = async function(url, options){
if(url.includes('game.wasm')){
// 拦截请求,返回我们修改过的二进制数据
const response = await originalFetch('http://localhost:8000/game_hacked.wasm');
return response;
}
return originalFetch(url, options);
};
刷新网页,点击按钮,金币直接 +1000!
看到这里,你可能会觉得 Wasm 在裸奔。作为开发者,如何防御?
$func1, $func2 抓狂。if-else 变成复杂的 switch 跳转,破坏代码结构。Wasm 逆向正处于一个蓝海阶段。
它既不像 x86 汇编那样指令繁杂,也不像 JS 那样容易被混淆成乱码。
掌握了 wasm2wat 和线性内存的原理,你就能看穿网页中那些'高性能黑盒'背后的秘密。
Next Step: 找一个简单的在线 CTF 题目(WebAssembly 类),尝试不看 Writeup,使用 Chrome DevTools 的断点功能,追踪一个加密函数的输入输出,逆向出它的 Flag。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online