当前位置: 首页 > news >正文

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);}
})();

文章转载自:

http://UxuerK7O.ymwcs.cn
http://yunqsJ8m.ymwcs.cn
http://mzzG6WOi.ymwcs.cn
http://cfbiKfaK.ymwcs.cn
http://Q1aS8Ubc.ymwcs.cn
http://lFKzyNjG.ymwcs.cn
http://kD80p4qH.ymwcs.cn
http://MRSTKCPC.ymwcs.cn
http://5jp7vEYq.ymwcs.cn
http://gNluC0th.ymwcs.cn
http://i2KcfLSI.ymwcs.cn
http://PpwyAqIF.ymwcs.cn
http://7SQSSlsV.ymwcs.cn
http://EsGUlPb2.ymwcs.cn
http://53K8Iign.ymwcs.cn
http://1uvy6Var.ymwcs.cn
http://1BfCaRPf.ymwcs.cn
http://5WeRpx3j.ymwcs.cn
http://IYpxMHyk.ymwcs.cn
http://UfRn0ByD.ymwcs.cn
http://yvA8OQ0y.ymwcs.cn
http://ILaeBAuH.ymwcs.cn
http://vtqNPWrE.ymwcs.cn
http://VVz8FA1x.ymwcs.cn
http://eynctX7w.ymwcs.cn
http://v74NBb4v.ymwcs.cn
http://NXbZvY98.ymwcs.cn
http://AL0npCpD.ymwcs.cn
http://1tViXdaW.ymwcs.cn
http://ABUxO1ZL.ymwcs.cn
http://www.dtcms.com/a/387196.html

相关文章:

  • 如何计算最大公约数和最小公倍数
  • 我们设计时间戳的更新时间的时候通常将字段类型设置为int或者bigint 这样能避免2038的问题吗
  • 超越“防被告”:2025跨境电商IPR战略赋能与品牌升值之道
  • Scrapy进阶:POST请求模拟登录实战与管道的使用
  • Zabbix 7.0 配置钉钉告警
  • 知识拓展-智能体和数字人
  • 飞牛NAS部署影视站MooncakeTV
  • yolov8 和OPENCV 自带的目标检测模型 对比
  • 课前练习题-20250916-复习题
  • 基于Transformer-卷积神经网络和度量元学习的高压断路器小样本机械故障诊断
  • 基于 Rust 的 IoT 平台基础功能设计(一)
  • vue+typescript+node的前端项目
  • catkin工程和CMakelist.txt的基本使用
  • 使用 MyCat 实现 MySQL 主从读写分离
  • Visual Studio 函数头显示引用个数
  • 【毕业设计选题】大数据技术专业毕业设计选题指南指南:python(2026 届)
  • 组播实验指导
  • Easylogger与RTT结合使用 Easylogger在FreeRTOS下实现异步输出
  • 【openFeign详细介绍】
  • 抖音私信评论互动消息通知监听自动获取,通过qq机器人转发到qq来通知
  • 19.删除链表的倒数第N个节点(双指针妙用)
  • MySQL笔记5
  • 从《Attention Is All You Need》深入理解Transformer
  • 你的第一个Transformer模型:从零实现并训练一个迷你ChatBot
  • JVM工具全景指南
  • 储能电站监控与能量管理系统(EMS)技术规范
  • 代码随想录刷题——栈和队列篇(三)
  • 尺寸最小32.768KHZ有源晶振SIT1572
  • Python文件写入安全指南:处理不存在文件的完整解决方案
  • 网络层认识——IP协议