告别抓瞎!用这8个Hook代码片段,5分钟定位JS逆向加密关键点
在逆向工程的世界里,JavaScript加密就像一座迷宫,而Hook技术则是照亮迷宫的探照灯。想象一下,当你面对一个复杂的网页应用,需要逆向分析其加密逻辑时,传统的逐行调试就像在黑暗中摸索,而Hook技术能让你直接定位到关键函数,就像给迷宫装上了GPS导航。
1. Hook技术基础:逆向工程师的瑞士军刀
Hook技术本质上是一种"中间人"攻击,它通过拦截和修改程序原有的函数调用流程,让我们能够在关键节点插入调试逻辑。与传统的断点调试相比,Hook具有几个显著优势:
- 主动拦截:不需要等待断点触发,可以主动捕获特定行为
- 精准定位:只关注我们感兴趣的函数调用,过滤无关噪音
- 非侵入式:不需要修改原始代码,保持目标环境完整性
在JavaScript中,最常用的Hook方法是通过Object.defineProperty重写对象属性的getter和setter。下面是一个基础示例:
// 基础Hook示例:拦截对象属性访问 const target = { secret: 'initialValue' }; let tempValue = target.secret; Object.defineProperty(target, 'secret', { get: function() { console.log('有人正在读取secret属性'); return tempValue; }, set: function(newValue) { console.log('有人正在修改secret属性为:', newValue); tempValue = newValue; } });这个简单的Hook已经包含了核心思想:在属性被访问或修改时执行我们的自定义逻辑。在实际逆向中,我们通常会在这些Hook点插入debugger语句,让浏览器自动暂停执行,方便我们检查调用栈。
2. 实战Hook工具箱:8个必杀代码片段
2.1 Cookie监控:追踪身份验证关键点
网站认证信息往往藏在Cookie中,特别是那些以__开头的神秘字段。这个Hook能帮你捕获Cookie设置过程:
(function() { 'use strict'; let cookieCache = document.cookie; Object.defineProperty(document, 'cookie', { set: function(value) { if (value.includes('__auth') || value.includes('token')) { console.log('发现关键Cookie设置:', value); debugger; // 自动断点 } cookieCache = value; return value; }, get: function() { return cookieCache; } }); })();使用场景:当你在分析一个需要登录的网站,发现请求头中有Authorization: Bearer xxxx这类令牌时,可以用这个Hook找出令牌是如何生成并设置的。
2.2 请求头拦截:捕获API通信密钥
现代Web应用常用自定义请求头传输加密参数,这个Hook专门针对这类场景:
(function() { const originalSetHeader = XMLHttpRequest.prototype.setRequestHeader; XMLHttpRequest.prototype.setRequestHeader = function(key, value) { if (key.toLowerCase() === 'x-signature' || key === 'X-Encrypt-Data') { console.log(`拦截到加密请求头 ${key}:`, value); debugger; } return originalSetHeader.apply(this, arguments); }; })();实战技巧:在开发者工具的Console中执行这段代码后,刷新页面,当遇到包含特定关键字的请求头设置时,会自动暂停执行。这时查看调用栈,通常能找到加密参数的生成逻辑。
2.3 URL参数Hook:定位动态参数生成
很多网站会在URL中添加时间戳、签名等动态参数,这个Hook能帮你找到它们的生成位置:
(function() { const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { if (url.includes('&sign=') || url.includes('?timestamp=')) { console.log('发现加密URL:', url); debugger; } return originalOpen.apply(this, arguments); }; })();典型应用:电商网站的商品详情页经常使用动态参数防止爬虫,用这个Hook可以快速定位到参数加密函数。
2.4 JSON数据处理Hook
现代API大量使用JSON传输数据,这两个Hook分别针对JSON的序列化和反序列化过程:
// Hook JSON.stringify (function() { const originalStringify = JSON.stringify; JSON.stringify = function(obj) { if (obj && obj.hasOwnProperty('encryptedData')) { console.log('发现加密数据:', obj); debugger; } return originalStringify(obj); }; })(); // Hook JSON.parse (function() { const originalParse = JSON.parse; JSON.parse = function(text) { try { const result = originalParse(text); if (result && result.encrypted) { console.log('发现加密响应:', result); debugger; } return result; } catch (e) { return originalParse(text); } }; })();组合使用:建议同时注入这两个Hook,可以完整监控API请求和响应的数据处理流程。
2.5 动态代码执行监控
很多加密逻辑会使用eval或Function动态执行代码,这些Hook能揭开它们的神秘面纱:
// Hook eval (function() { const originalEval = window.eval; window.eval = function(code) { console.log('eval执行代码:', code.slice(0, 100) + '...'); debugger; return originalEval(code); }; })(); // Hook Function构造函数 (function() { const originalFunction = window.Function; window.Function = function() { const args = Array.from(arguments); console.log('新建函数:', args.slice(-1)[0]); debugger; return originalFunction.apply(this, args); }; })();安全提示:监控eval执行时要小心,避免在Console中输出过长的代码片段导致浏览器卡顿。
2.6 控制台修复Hook
有些网站会禁用控制台输出,这个Hook能恢复你的调试能力:
(function() { if (window.console && window.console.log) { const iframe = document.createElement('iframe'); iframe.style.display = 'none'; document.body.appendChild(iframe); window.console = iframe.contentWindow.console; } })();使用注意:这个Hook需要在其他Hook之前执行,确保后续的console.log能够正常输出。
3. 高级Hook技巧与调试策略
3.1 条件断点:精准狙击目标
单纯的Hook可能产生太多干扰信息,添加条件判断可以让断点更智能:
// 带条件的Cookie Hook (function() { let cookieCache = document.cookie; let counter = 0; Object.defineProperty(document, 'cookie', { set: function(value) { if (value.includes('token') && ++counter > 3) { console.log('第三次之后的token设置:', value); debugger; } cookieCache = value; return value; }, get: function() { return cookieCache; } }); })();调试技巧:通过添加计数器、时间戳或特定值判断,可以只在关键时机触发断点,避免不必要的暂停。
3.2 调用栈分析:逆向追踪加密逻辑
当Hook触发的断点生效后,正确的调用栈分析能事半功倍:
- 在开发者工具的Sources面板中查看Call Stack
- 从下往上阅读调用链,寻找可疑的函数名
- 点击调用栈中的函数,跳转到对应源码位置
- 重点关注包含encrypt、sign、hash等关键词的函数
常见模式:加密逻辑通常集中在几个关键函数中,找到它们就成功了一半。
3.3 Hook注入时机:确保先发制人
Hook代码必须在目标函数执行前注入,常见策略有:
- 浏览器插件:如Tampermonkey,可以在页面加载前执行脚本
- 代理工具:Fiddler、Charles等可以自动注入脚本
- 开发者工具:在页面加载初期手动粘贴代码
最佳实践:对于复杂的网站,建议使用浏览器插件确保Hook代码最先执行。
4. 实战案例:破解某电商网站加密参数
让我们通过一个真实案例演示Hook技术的威力。假设目标网站在搜索商品时,请求URL包含一个动态的_token参数。
4.1 注入URL Hook
首先注入我们的URL监控Hook:
(function() { const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { if (url.includes('_token=')) { console.log('捕获token参数:', url); debugger; } return originalOpen.apply(this, arguments); }; })();4.2 触发断点并分析
在网站搜索框输入关键词并回车,Hook会捕获到包含_token的请求并暂停执行。查看调用栈,我们发现一个名为generateSearchToken的函数。
4.3 定位加密函数
通过调用栈跳转到generateSearchToken函数,发现它调用了另一个名为cryptoUtils.sign的函数。继续追踪,最终找到了HMAC-SHA256的签名实现。
4.4 验证Hook结果
复制出加密函数,在Console中测试验证:
function generateToken(keyword) { const timestamp = Date.now(); const hmac = CryptoJS.HmacSHA256(keyword + timestamp, 'secret_key'); return hmac.toString(CryptoJS.enc.Hex); } // 测试 generateToken('手机'); // 输出与网站一致的token格式4.5 完整解决方案
最终我们得到了完整的参数生成逻辑,可以在爬虫中复现:
const CryptoJS = require('crypto-js'); function generateSearchParams(keyword) { const timestamp = Date.now(); const token = CryptoJS.HmacSHA256( keyword + timestamp, '0xFAST_ECOMMERCE' ).toString(); return { q: keyword, _token: token, _t: timestamp }; }这个案例展示了如何通过Hook技术快速定位加密逻辑,而不需要逐行阅读数万行的压缩代码。