跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端算法

WebAssembly 逆向分析:反编译与内存篡改实战

介绍 WebAssembly(Wasm)的逆向分析方法。Wasm 是二进制指令格式,非加密手段。核心思路包括静态分析(反编译为 WAT 或伪代码)和动态调试(修改线性内存)。工具涵盖 Chrome 浏览器、WABT 套件及 Ghidra。实战步骤涉及捕获 wasm 文件、转化为可读代码、定位内存地址并篡改数值,或通过修改 WAT 代码重编译进行补丁。防御方面建议去除符号、控制流平坦化及服务器端校验关键数据。掌握这些技术有助于理解网页高性能黑盒背后的逻辑。

清心发布于 2026/4/5更新于 2026/9/994 浏览
WebAssembly 逆向分析:反编译与内存篡改实战

WebAssembly 逆向分析:反编译与内存篡改实战

前言:Wasm 不是加密,只是二进制

WebAssembly 是一种基于堆栈虚拟机的二进制指令格式。它类似于汇编语言,但比 x86 汇编更抽象。 浏览器加载 .wasm 文件,编译为机器码运行。

逆向 Wasm 的两种核心思路

  1. 静态分析:将 .wasm 反汇编为 .wat (WebAssembly Text) 或伪 C 代码,分析逻辑。
  2. 动态调试:利用浏览器开发者工具挂载断点,或直接修改 WebAssembly.Memory(线性内存)。

Wasm 加载与逆向流程

  1. 下载 game.wasm
  2. 解码 Imports (函数/内存)
  3. 读写操作
  4. 工具:wasm2wat 生成可读汇编代码 (.wat)
  5. 工具:Console 直接修改数值

一、兵器库:逆向工具准备

在开始之前,你需要准备以下工具:

  1. Chrome 浏览器:最强大的 Wasm 调试器。
  2. WABT (The WebAssembly Binary Toolkit):
    • wasm2wat: 将二进制转为人类可读的文本格式(S-表达式)。
    • wat2wasm: 将修改后的文本重新编译为二进制。
  3. Ghidra (可选):安装 Wasm 插件后,可以生成伪 C 代码。

二、实战第一步:捕获与反编译

假设我们正在玩一个网页小游戏,每次点击按钮,金币 +1。我们要把它改成 +1000。

1. 获取 Wasm 文件

打开 Chrome DevTools -> Network 面板,刷新页面,过滤 .wasm。找到 game.wasm 并下载。

2. 转化为可读代码 (WAT)

使用 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,你需要根据上下文推断。


三、实战第二步:内存篡改 (Memory Hacking)

Wasm 的内存模型非常简单:它就是一个巨大的、线性的 JavaScript ArrayBuffer。 这意味着,JS 可以随意读写 Wasm 的内存!这是最简单的破解方式。

1. 定位内存对象

在 Chrome Console 中,寻找 Wasm 的实例对象。通常在全局变量或者 对象中。

imports
// 假设游戏把实例挂载到了 window.gameInstance
const memBuffer = window.gameInstance.exports.memory.buffer;
const memView = new Int32Array(memBuffer);

2. 搜索数值 (CE 搜内存法)

就像使用 Cheat Engine 一样:

  1. 当前金币是 100。
  2. 在 Console 输入:memView.forEach((v, i) => { if(v===100) console.log(i) }) -> 得到索引 1024。
  3. 玩游戏,金币变成 101。
  4. 检查索引 1024 的值:memView[1024] -> 确实是 101。
  5. 找到地址了!

3. 修改数值

// 直接把金币改成 999999
memView[1024]=999999;

页面上的金币瞬间暴涨。


四、实战第三步:二进制补丁 (Binary Patching)

如果金币逻辑没有暴露在全局内存中,或者是纯栈操作,我们就需要修改代码本身(Patch)。

1. 修改 WAT 代码

回到刚才反编译的 game.wat 文件。 找到加法逻辑:

local.get $p0 i32.const 1;; <--- 这里是增加的数量 i32.add 

我们将 1 修改为 1000:

local.get $p0 i32.const 1000;; <--- 修改为 1000 i32.add 

2. 重编译为 Wasm

wat2wasm game.wat -o game_hacked.wasm 

3. 替换运行 (浏览器端 Hook)

我们不能直接替换服务器文件,但我们可以通过 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?

看到这里,你可能会觉得 Wasm 在裸奔。作为开发者,如何防御?

  1. Strip Symbols:发布时务必去除调试符号(函数名、变量名),让逆向者面对 $func1, $func2 抓狂。
  2. 控制流平坦化 (Control Flow Flattening):使用 LLVM 的混淆插件(如 Obfuscator-LLVM),把清晰的 if-else 变成复杂的 switch 跳转,破坏代码结构。
  3. 服务器校验:永远不要相信客户端。 像金币这种关键数据,Wasm 只能做展示,计算和存储必须在服务器端完成。

总结

Wasm 逆向正处于一个蓝海阶段。 它既不像 x86 汇编那样指令繁杂,也不像 JS 那样容易被混淆成乱码。 掌握了 wasm2wat 和线性内存的原理,你就能看穿网页中那些'高性能黑盒'背后的秘密。

下一步建议: 找一个简单的在线 CTF 题目(WebAssembly 类),尝试不看 Writeup,使用 Chrome DevTools 的断点功能,追踪一个加密函数的输入输出,逆向出它的 Flag。

目录

  1. WebAssembly 逆向分析:反编译与内存篡改实战
  2. 前言:Wasm 不是加密,只是二进制
  3. 逆向 Wasm 的两种核心思路
  4. Wasm 加载与逆向流程
  5. 一、兵器库:逆向工具准备
  6. 二、实战第一步:捕获与反编译
  7. 1. 获取 Wasm 文件
  8. 2. 转化为可读代码 (WAT)
  9. 三、实战第二步:内存篡改 (Memory Hacking)
  10. 1. 定位内存对象
  11. 2. 搜索数值 (CE 搜内存法)
  12. 3. 修改数值
  13. 四、实战第三步:二进制补丁 (Binary Patching)
  14. 1. 修改 WAT 代码
  15. 2. 重编译为 Wasm
  16. 3. 替换运行 (浏览器端 Hook)
  17. 五、防御:开发者如何保护 Wasm?
  18. 总结

更多推荐文章

查看全部
  • Go Web 开发核心理论指南
  • C++ STL 算法详解:非修改、修改、排序及数值操作
  • 开源大模型选型指南:如何构建合适的技术底座
  • 练习开发Skill——网页内容抓取Skill(website-content-fetch)
  • OpenClaw 结合 cpolar 实现公网访问与应用场景
  • 双指针算法进阶:三角形与多数之和
  • Angular 应用 Chrome 调用高德地图 API 定位超时问题解析与安全方案
  • Windows 环境 Git 安装与配置指南
  • 企业级图像 AIGC 技术观察:Seedream 4.0 能力与应用场景分析
  • Qwen-Image-Edit-2511 与 Stable Diffusion 图像编辑能力对比分析
  • Cursor 配置网络代理设置教程
  • Visual C++ MFC 基础图形绘制实战:点线面与投影
  • Java ArrayList 核心解析:底层结构、使用方法与扩容机制
  • 鸿蒙金融理财全栈项目:生态合作与用户运营优化
  • Hibernate 一对多映射实战:Customer 与 Order 实体配置详解
  • Go Channel 深入解析
  • Miloco 本地大模型智能家居部署与使用记录
  • 基于 HomeAssistant 实现跨品牌智能家居联动
  • AI 辅助生成前端原型:从需求到交互的自动化流程
  • Elasticsearch 核心概念、Kibana 测试与 C++ 客户端封装实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online