油猴脚本:Hook Function构造器实现前端反调试绕过

油猴脚本:Hook Function构造器实现前端反调试绕过
1. 为什么需要Hook Function构造器当你打开Chrome开发者工具调试某些网站时经常会遇到无限debugger暂停的问题导致无法正常调试代码。这是因为目标网站的前端代码中植入了大量反调试代码最常见的就是使用debugger语句。传统的解决方案是直接禁用所有断点但这会导致我们失去正常的调试能力。更优雅的方式是通过Hook Function.prototype.constructor来精准拦截并净化包含debugger的恶意代码就像外科手术一样精确。我在实际爬虫项目中遇到过这样一个案例某电商网站使用了动态生成debugger语句的混淆代码每隔几秒就会触发一次debugger。通过分析发现他们是通过Function构造器动态生成包含debugger的代码。这时候就需要用到我们今天要介绍的Hook技术。2. debugger反调试原理剖析2.1 常见的debugger实现方式网站开发者通常会用以下几种方式实现反调试直接插入debugger语句setInterval(function(){ debugger; }, 1000);通过Function构造器动态生成new Function(debugger)();使用eval执行包含debugger的字符串eval(deb ugger);更隐蔽的拼接方式var a deb; var b ugger; setInterval(function(){ eval(a b); }, 100);2.2 为什么Hook Function构造器有效JavaScript中所有函数都是Function构造器的实例包括通过function关键字定义的函数。当我们Hook Function.prototype.constructor时实际上拦截了所有函数的创建过程。这让我们有机会在函数被创建时检查其内容如果发现包含debugger就进行净化处理。这种方法的优势在于精准拦截不影响其他正常代码无需禁用所有断点保留调试能力可以处理动态生成的debugger代码兼容大多数现代浏览器3. 油猴脚本实现详解3.1 完整脚本代码下面是一个完整的油猴脚本实现可以直接安装使用// UserScript // name Anti Anti-debugger // namespace http://tampermonkey.net/ // version 1.0 // description 通过Hook Function构造器绕过前端反调试 // author YourName // match *://*/* // grant unsafeWindow // run-at document-start // /UserScript (function() { use strict; // 保存原始Function构造器 var originalConstructor unsafeWindow.Function.prototype.constructor; // Hook Function构造器 unsafeWindow.Function.prototype.constructor function() { // 获取函数体内容 var fnBody arguments[0]; if (fnBody typeof fnBody string) { // 检查是否包含debugger if (fnBody.includes(debugger)) { // 获取调用者信息非标准实现部分浏览器支持 var caller Function.prototype.constructor.caller; if (caller) { var callerStr caller.toString(); if (callerStr.includes(debugger)) { // 移除调用者中的所有debugger语句 callerStr callerStr.replace(/\bdebugger\b/gi, ); try { // 重新定义调用者函数 eval(caller callerStr); } catch(e) { console.warn(Failed to redefine caller:, e); } } } // 返回一个空函数替代原函数 return function(){}; } } // 正常情况使用原始构造器 return originalConstructor.apply(this, arguments); }; })();3.2 关键代码解析run-at document-start确保脚本在页面加载前执行尽早HookunsafeWindow访问页面的原始window对象保存原始构造器先备份原始Function.prototype.constructor以便后续正常调用检查函数体分析传入的代码字符串是否包含debugger关键字处理调用链尝试找到并净化调用链上的debugger语句返回空函数对于包含debugger的函数返回一个无害的空函数4. 高级应用与优化4.1 处理混淆代码对于经过混淆的代码简单的字符串匹配可能不够。我们可以增强检测逻辑// 增强版的debugger检测 function containsDebugger(code) { // 处理简单debugger if (code.includes(debugger)) return true; // 处理拆分的debugger var debuggerParts [de, bug, ger]; var combined debuggerParts.join(); if (code.includes(combined)) return true; // 处理通过字符编码表示的debugger var charCodes [100, 101, 98, 117, 103, 103, 101, 114]; var fromCharCode String.fromCharCode(...charCodes); if (code.includes(fromCharCode)) return true; return false; }4.2 性能优化Hook Function构造器可能影响页面性能特别是对于大量使用动态函数的网站。我们可以添加白名单机制// 域名白名单 var whitelist [ trusted-site.com, cdn.google.com ]; // 检查当前域名是否在白名单 function isWhitelisted() { return whitelist.some(function(domain) { return window.location.hostname.endsWith(domain); }); } // 修改Hook逻辑 if (!isWhitelisted()) { unsafeWindow.Function.prototype.constructor function() { // Hook逻辑... }; }4.3 错误处理增强添加更健壮的错误处理避免脚本自身导致页面崩溃try { var originalConstructor unsafeWindow.Function.prototype.constructor; unsafeWindow.Function.prototype.constructor function() { try { // Hook逻辑... } catch (e) { console.error(Hook error:, e); return originalConstructor.apply(this, arguments); } }; } catch (e) { console.error(Initialization failed:, e); }5. 实际案例分析5.1 电商网站反调试破解某电商网站使用了如下反调试代码function createDebugger() { return new Function( var adeb;var bugger; if(window.console){ eval(ab); } ); } setInterval(createDebugger(), 3000);我们的Hook脚本成功拦截了这种动态生成的debugger因为检测到new Function调用分析出拼接的debugger字符串返回了空函数替代原函数5.2 金融网站保护机制绕过某金融网站使用了更复杂的保护var _0xad3b [\x64\x65\x62\x75\x67\x67\x65\x72]; (function(_0x12cf8a, _0xad3b82) { var _0x5e4f4a function(_0x1a8f00) { while (--_0x1a8f00) { _0x12cf8a[push](_0x12cf8a[shift]()); } }; _0x5e4f4a(_0xad3b82); })(_0xad3b, 0x1a3); var _0x5e4f function(_0x12cf8a, _0xad3b82) { _0x12cf8a _0x12cf8a - 0x0; var _0x5e4f4a _0xad3b[_0x12cf8a]; return _0x5e4f4a; }; setInterval(function() { var _0x1a8f00 _0x5e4f(0x0); new Function(_0x1a8f00)(); }, 0x7d0);即使在这种复杂混淆下我们的Hook仍然有效因为它最终还是要通过Function构造器执行。6. 常见问题与解决方案6.1 Hook后功能异常有时Hook可能导致网站功能异常解决方案检查是否是白名单网站添加更精确的匹配条件在特定条件下恢复原始构造器var isDebugging false; unsafeWindow.Function.prototype.constructor function() { if (!isDebugging) { return originalConstructor.apply(this, arguments); } // 正常的Hook逻辑... };6.2 无法拦截eval执行的debugger对于直接使用eval的情况可以额外Hook evalvar originalEval unsafeWindow.eval; unsafeWindow.eval function(code) { if (containsDebugger(code)) { console.log(Blocked debugger in eval); return; } return originalEval.apply(this, arguments); };6.3 性能开销问题对于性能敏感的场景限制Hook的作用范围使用更高效的正则匹配避免不必要的调用栈分析// 简化的性能优化版 unsafeWindow.Function.prototype.constructor function() { var fnBody arguments[0]; if (typeof fnBody string /d\s*e\s*b\s*u\s*g\s*g\s*e\s*r/i.test(fnBody)) { return function(){}; } return originalConstructor.apply(this, arguments); };7. 安全与伦理考量在使用这类技术时需要注意仅用于合法授权的测试尊重网站的robots.txt协议不要绕过合理的访问限制遵守相关法律法规技术本身是中立的关键在于使用者的意图。作为开发者我们应当把这类技术用于提升Web安全性而不是滥用它。