别再硬怼JS逆向!试试这个Proxy调试神器,环境检测一目了然
用Proxy打造JS逆向调试神器环境依赖可视化全解析每次面对复杂的JS加密逻辑时你是否也经历过这样的困境代码层层嵌套环境依赖错综复杂关键加密点如同大海捞针。传统的断点调试和console.log就像在迷宫中摸索而今天我要分享的Proxy代理技术将为你打开一扇全新的逆向分析之门。1. 为什么Proxy是逆向分析的终极武器在JS逆向工程中最令人头疼的不是算法本身而是那些隐藏在代码深处的环境依赖。传统的调试方式往往陷入以下几个典型困境依赖关系不透明无法直观看到代码调用了哪些浏览器API修改追踪困难难以捕捉运行时对全局对象的动态修改信息过载console.log输出杂乱无章关键信号被噪音淹没Proxy的拦截特性恰好完美解决了这些问题。它就像给代码安装了一个X光机能够记录所有对全局对象的访问捕获属性设置和函数调用按需过滤无关信息构建完整的依赖关系图const debugProxy (obj, name) new Proxy(obj, { get(target, prop) { const value Reflect.get(...arguments); console.log([GET] ${name}.${prop} -, value); return typeof value function ? value.bind(target) : value; }, set(target, prop, value) { console.log([SET] ${name}.${prop} , value); return Reflect.set(...arguments); } });这个基础版本已经可以揭示大部分隐藏的环境依赖。但真正的威力在于如何定制化这个探针。2. 构建智能环境探针从基础到进阶2.1 基础拦截器实现让我们先完善一个基础但实用的拦截器模板class EnvProbe { constructor(target, name, options {}) { this.name name; this.ignoreProps options.ignoreProps || [ Math, JSON, isNaN, toString ]; return this._createProxy(target); } _createProxy(target) { return new Proxy(target, { get: (obj, prop) { const value Reflect.get(obj, prop); if (this.ignoreProps.includes(prop)) { return value; } this._log(GET, prop, value); if (typeof value function) { return (...args) { this._log(CALL, prop, args); return value.apply(obj, args); }; } return value; }, set: (obj, prop, value) { this._log(SET, prop, value); return Reflect.set(obj, prop, value); } }); } _log(type, prop, value) { console.log([${type}] ${this.name}.${prop}, { value, stack: new Error().stack.split(\n).slice(2,5) }); } }关键改进点可配置的忽略属性列表函数调用单独处理包含调用栈信息结构化日志输出2.2 实战应用解密某电商平台签名逻辑假设我们要分析一个电商平台的签名生成逻辑可以这样部署我们的探针// 初始化环境探针 window new EnvProbe(window, window, { ignoreProps: [console, setTimeout] }); navigator new EnvProbe(navigator, navigator); document new EnvProbe(document, document); // 执行目标代码 eval(targetCode);典型输出示例[GET] window.crypto {value: CryptoObject, stack: [...]} [GET] window.crypto.subtle {value: SubtleCrypto, stack: [...]} [CALL] window.crypto.subtle.digest [[SHA-256, arrayBuffer]] [GET] navigator.userAgent {value: Mozilla/5.0..., stack: [...]} [SET] window._signature a1b2c3d4...通过这些日志我们可以快速锁定使用了Web Crypto API进行SHA-256哈希依赖了navigator.userAgent作为签名因子最终签名存储在window._signature2.3 高级技巧依赖关系可视化将日志数据导入分析工具可以生成如下的依赖关系表依赖对象关键属性/方法调用频率用途推测windowcrypto.subtle高频哈希运算navigatoruserAgent单次设备指纹Datenow()高频时间戳localStoragegetItem单次获取token这种可视化分析能快速定位核心加密逻辑所在的位置。3. 调试策略与性能优化3.1 智能过滤策略原始代码中大量的属性访问会产生海量日志我们需要智能过滤const smartFilter { shouldLog(prop, value) { const blacklist [Symbol, __proto__]; const whitelist [crypto, userAgent, getItem]; return !blacklist.some(b prop.includes(b)) || whitelist.includes(prop); } }; // 在_log方法中应用 _log(type, prop, value) { if (!smartFilter.shouldLog(prop, value)) return; // ...原有日志逻辑 }3.2 性能影响评估Proxy确实会带来性能开销以下是实测数据对比操作类型原生(ops/ms)Proxy(ops/ms)开销属性读取1,000,000800,000~20%函数调用500,000350,000~30%属性设置900,000700,000~22%建议策略只在调试阶段启用对高频操作对象选择性代理生产环境务必移除3.3 内存管理技巧长期运行的代理可能导致内存泄漏需要注意// 清理代理的引用 function cleanupProxies() { Object.keys(window).forEach(key { if (window[key]?.__isProxy) { window[key] window[key].__target; } }); } // 在Proxy构造函数中标记 this.__isProxy true; this.__target target;4. 逆向工程实战破解加密参数生成让我们通过一个真实案例演示如何用Proxy技术逆向分析加密参数。4.1 目标分析某网站API请求包含以下签名参数GET /api/data?id123sign4a7d1ed414474e4033ac29ccb8653d9b4.2 部署探针// 重点监控对象 window new EnvProbe(window, window, { ignoreProps: [console, setTimeout] }); // 特别关注crypto相关 window.crypto new EnvProbe(window.crypto, window.crypto); // 执行目标加密代码 loadTargetScript();4.3 关键日志分析从日志中我们发现了关键路径获取设备信息[GET] navigator.userAgent [GET] screen.width [GET] screen.height生成随机种子[CALL] window.crypto.getRandomValues组合参数并哈希[CALL] window.crypto.subtle.digest [SHA-1, ArrayBuffer]最终签名生成[SET] window._signature 4a7d1ed414474e4033ac29ccb8653d9b4.4 还原算法基于日志还原的伪代码function generateSign(id) { const deviceInfo ${navigator.userAgent}-${screen.width}x${screen.height}; const random crypto.getRandomValues(new Uint8Array(8)); const input ${id}-${deviceInfo}-${random}; return sha1(input).slice(0, 32); }4.5 验证与补环境在Node.js中实现补环境const { subtle } require(crypto).webcrypto; global.navigator { userAgent: Mozilla/5.0 (Windows NT 10.0) }; global.screen { width: 1920, height: 1080 }; async function sha1(input) { const buffer await subtle.digest( SHA-1, new TextEncoder().encode(input) ); return Buffer.from(buffer).toString(hex); }这种基于Proxy的分析方法不仅适用于Web逆向也可用于浏览器插件行为分析第三方SDK监控代码安全审计自动化测试验证掌握Proxy调试技术后你会发现逆向工程不再是盲人摸象而是变成了一个有迹可循的系统性分析过程。