浅析新时代的wasm逆向思路-由源鲁杯入门题和N1junior零解题开始
字数 1423 2025-08-23 18:31:18
WebAssembly逆向工程实战指南
1. WebAssembly简介
WebAssembly(简称Wasm)是一种新兴的低级字节码格式,设计用于提升Web应用程序的性能和效率。主要特点包括:
- 接近原生代码的执行速度
- 跨平台特性(浏览器、服务器、嵌入式设备)
- 紧凑的二进制格式
- 内存安全沙箱环境
Wasm逆向工程已成为CTF竞赛和实际安全研究中的重要技能。
2. Wasm逆向工程方法论
2.1 工具链准备
必备工具:
- WABT工具包(WebAssembly Binary Toolkit):
- wasm2wat:将.wasm转换为可读的.wat文本格式
- wasm2c:将.wasm转换为C代码
反编译工具:
-
IDA Pro 9.0+:
- 支持Wasm反汇编
- 目前缺乏反编译功能(截至2024年)
-
Ghidra + Wasm插件:
- 提供完整的反编译支持
- 插件地址:https://github.com/nneonneo/ghidra-wasm-plugin/
-
动态分析工具:
- Chrome开发者工具
- VSCode + Node.js插件
2.2 逆向流程
方法一:WABT + IDA组合
$ ./wasm2wat wasm.wasm -o wasm.wat # 转换为文本格式
$ ./wasm2c wasm.wasm -o wasm.c # 转换为C代码
优势:利用IDA强大的分析能力
劣势:流程较为繁琐
方法二:Ghidra插件"一把梭"
优势:
- 安装简单
- 快速反编译
- 适合快速分析
劣势:
- 反编译质量有时不理想
- 复杂代码处理能力有限
方法三:动态调试
- Chrome开发者工具:
- 支持设置断点
- 实时查看内存和调用栈
- 参考资源:https://panda0s.top/2021/05/14/WebAssembly-Reverse/
3. 实战案例分析
3.1 2024源鲁杯Round2 Wasm题目分析
题目特征:
- 提供单个wasm文件
- 使用Ghidra插件直接反编译
关键函数分析:
undefined4 unnamed_function_7(void) {
// 变量声明和初始化
gzflag = unnamed_function_14("GZCTF_FLAG");
length = unnamed_function_20(gzflag);
// 处理换行符
if ((length != 0) && (*(char *)(gzflag + length -1) == '\n')) {
*(undefined *)(gzflag + length -1) = 0;
}
// 第一轮处理:字符转换
for (i = 0; *(char *)(gzflag + i) != '\0'; i++) {
if (是小写字母) {
转换为大写;
应用模运算: (char - 0x3a) % 0x1a + 'A';
} else if (是大写字母) {
转换为小写;
应用模运算: (char - 0x5a) % 0x1a + 'a';
}
}
// 第二轮处理:输出校验
for (i = 0; *(char *)(gzflag + i) != '\0'; i++) {
local_20[0] = (int)*(char *)(gzflag + i);
unnamed_function_15(0x43a, local_20);
}
return 0;
}
解题脚本:
def decrypt_flag(gzflag):
decrypted = []
for char in gzflag:
if 'A' <= chr(char) <= 'Z':
# 大写字母处理
char = char - ord('A')
char = char - 0x20
char = (char - ord('A') + 0x5a) % 26 + ord('a')
elif 'a' <= chr(char) <= 'z':
# 小写字母处理
char = char - ord('a')
char = char + 0x20
char = (char - ord('a') + 0x3a) % 26 + ord('A')
decrypted.append(chr(char))
return ''.join(decrypted)
# 测试数据
gzflag = [0x66, 0x73, 0x6a, 0x61, 0x6d, 0x7b, 0x48, 0x31, 0x30, 0x49, 0x38,
0x33, 0x30, 0x37, 0x2d, 0x36, 0x35, 0x4c, 0x4b, 0x2d, 0x34, 0x4c,
0x35, 0x36, 0x2d, 0x49, 0x30, 0x37, 0x39, 0x2d, 0x30, 0x31, 0x32,
0x37, 0x38, 0x4b, 0x4d, 0x49, 0x30, 0x32, 0x31, 0x4b, 0x7d]
print(decrypt_flag(gzflag))
3.2 2024 N1junior Wasm题目分析
题目特征:
- 使用Ghidra插件分析
- 关键函数:main.slice
反编译关键代码:
undefined4 main.slice(int param1, ...) {
// 多层嵌套的字符检查
if (*(char *)uVar5 == 'Y') {
if (*(char *)((int)uVar5 + 1) == '3') {
if (*(char *)((int)uVar5 + 2) == 'R') {
// ... 省略多层检查 ...
if (*(char *)((int)uVar5 + 0x2e) == 'Z') {
// 验证通过
}
}
}
}
}
解题思路:
- 提取所有被检查的字符位置和对应值
- 组合成疑似Base64编码的字符串
- Base64解码获取flag
提取的Base64字符串:
Y3RmcHVua3tXQVNNXzY2NjY2NjZfR09BTE5HXzY2NjY2NjZ9
解码结果:
ctfpunk{WASM_6666666_GOALNG_6666666}
4. 最佳实践建议
-
工具选择:
- 快速分析:优先使用Ghidra+Wasm插件
- 深度分析:结合wasm2c和IDA Pro
- 动态调试:Chrome开发者工具
-
分析技巧:
- 注意内存操作函数(如unnamed_function_14可能是malloc)
- 关注字符串操作和字符转换逻辑
- 识别常见的加密模式(如凯撒变种、Base64等)
-
效率提升:
- 建立Wasm分析模板
- 熟悉常见Wasm运行时函数
- 结合静态分析和动态调试
-
常见模式识别:
- 字符转换循环(如大小写转换)
- 模运算加密(常见于CTF题目)
- 多层嵌套判断(可能是简单比对)
5. 总结
WebAssembly逆向工程在2024年已经发展出成熟的方法论:
- Ghidra插件显著降低了入门门槛
- 静态分析结合动态调试是最佳实践
- Wasm题目常包含字符操作和简单加密
- Base64编码在Wasm题目中频繁出现
随着Wasm应用越来越广泛,掌握其逆向技术将成为安全研究人员的必备技能。