WASM逆向
首先找到wasm初始化的位置,然后hook初始化后的实例
// === 封装:一键读取 WASM 内存中的字符串(修复版)===
(function initWasmStringReader() {try {const instance = window.wasmInstance;if (!instance) {console.error('❌ window.wasmInstance 未定义,请先加载 WASM 实例');return;}// 🔧 修复点:支持 .e 和通用查找const exportedMemory = instance.exports.e || // 你的实际导出名instance.exports.memory || // 标准名Object.values(instance.exports).find(val => val instanceof WebAssembly.Memory);if (!exportedMemory) {console.error('❌ 未找到 WebAssembly.Memory,当前导出项:', Object.keys(instance.exports));return;}const memory = exportedMemory;const u8 = new Uint8Array(memory.buffer);// 核心函数:通过地址读取字符串window.readWasmStr = function readWasmStr(ptr, maxLen = 1024) {// 输入校验if (typeof ptr !== 'number' || ptr < 0) {console.warn('⚠️ 无效地址:', ptr);return null;}if (ptr === 0) {console.log('📌 [0x0] null pointer');return null;}// 检查地址是否越界if (ptr >= u8.length) {console.warn(`⚠️ 地址 0x${ptr.toString(16)} 超出内存范围 (最大 0x${u8.length.toString(16)})`);return null;}// 查找 \0 结束符let end = ptr;let len = 0;while (len < maxLen && u8[end] !== 0 && end < u8.length) {end++;len++;}// 解码 UTF-8 字符串const str = new TextDecoder('utf-8').decode(u8.subarray(ptr, end));// 打印带格式的结果console.log(`📌 0x${ptr.toString(16)} (${ptr}):`, str);return str;};// ✅ 增强提示:显示内存大小const totalPages = memory.buffer.byteLength / 65536;console.log(`✅ readWasmStr(addr) 已就绪!内存页数: ${totalPages} (≈${(totalPages * 64).toFixed(1)}MB)`);console.log('📝 示例:readWasmStr(7798784)');console.log('🔍 提示:内存来自 exports.e,支持读取字符串');} catch (err) {console.error('❌ 初始化失败:', err);}
})();
因为我做的是图像解密,他的解密是在wasm中做的,我采用的是倒推的方式找的解密后js是在哪个交互函数中拿到结果的。同样进行hook
// 在 Console 中执行
const canvas = document.getElementById('click-grid-0');
const ctx = canvas.getContext('2d');// 保存原始方法
const originalPutImageData = ctx.putImageData;
ctx.putImageData = function(...args) {console.debug('putImageData called with:', args);// 创建一个临时 canvas 来存放 ImageDataconst tempCanvas = document.createElement('canvas');tempCanvas.width = args[0].width; // ImageData widthtempCanvas.height = args[0].height; // ImageData height// 获取上下文并绘制 ImageDataconst tempCtx = tempCanvas.getContext('2d');tempCtx.putImageData(args[0], 0, 0);// 转换为 Base64(PNG 格式)const base64 = tempCanvas.toDataURL('image/png');// 输出 Base64 字符串console.log('Base64 URL:');console.log(base64);// 可选:在页面上显示该图片const img = document.createElement('img');img.src = base64;img.style.margin = '10px';img.style.border = '1px solid #ccc';document.body.appendChild(img);debugger; // 断点在这里,查看调用栈return originalPutImageData.apply(this, args);
};
因为wasm会开辟一块线下地址和js进行交互。实例化的时候会会返回wasm导出的地址。我们挂载到全局,然后封装一个方法,对内存的值进行读取,因为wasm基本都是对内存进行操作。
// === 封装:一键读取 WASM 内存中的字符串(修复版)===
(function initWasmStringReader() {try {const instance = window.wasmInstance;if (!instance) {console.error('❌ window.wasmInstance 未定义,请先加载 WASM 实例');return;}// 🔧 修复点:支持 .e 和通用查找const exportedMemory = instance.exports.e || // 你的实际导出名instance.exports.memory || // 标准名Object.values(instance.exports).find(val => val instanceof WebAssembly.Memory);if (!exportedMemory) {console.error('❌ 未找到 WebAssembly.Memory,当前导出项:', Object.keys(instance.exports));return;}const memory = exportedMemory;const u8 = new Uint8Array(memory.buffer);// 核心函数:通过地址读取字符串window.readWasmStr = function readWasmStr(ptr, maxLen = 1024) {// 输入校验if (typeof ptr !== 'number' || ptr < 0) {console.warn('⚠️ 无效地址:', ptr);return null;}if (ptr === 0) {console.log('📌 [0x0] null pointer');return null;}// 检查地址是否越界if (ptr >= u8.length) {console.warn(`⚠️ 地址 0x${ptr.toString(16)} 超出内存范围 (最大 0x${u8.length.toString(16)})`);return null;}// 查找 \0 结束符let end = ptr;let len = 0;while (len < maxLen && u8[end] !== 0 && end < u8.length) {end++;len++;}// 解码 UTF-8 字符串const str = new TextDecoder('utf-8').decode(u8.subarray(ptr, end));// 打印带格式的结果console.log(`📌 0x${ptr.toString(16)} (${ptr}):`, str);return str;};// ✅ 增强提示:显示内存大小const totalPages = memory.buffer.byteLength / 65536;console.log(`✅ readWasmStr(addr) 已就绪!内存页数: ${totalPages} (≈${(totalPages * 64).toFixed(1)}MB)`);console.log('📝 示例:readWasmStr(7798784)');console.log('🔍 提示:内存来自 exports.e,支持读取字符串');} catch (err) {console.error('❌ 初始化失败:', err);}
})();