Fiddler+编程猫插件实现JS Hook:5分钟定位网站加密参数生成位置

📅 2026/6/17 7:22:58
Fiddler+编程猫插件实现JS Hook:5分钟定位网站加密参数生成位置
1. 项目概述为什么我们需要JS Hook来定位加密参数如果你做过Web逆向或者爬虫开发肯定遇到过这种场景一个网站的登录请求提交的表单里有一串长得像天书一样的加密参数比如sign、token、_signature。你直接模拟请求服务器永远返回“参数错误”。这时候常规的抓包只能告诉你“它长这样”却无法告诉你“它从哪来”。传统的做法可能是去浩如烟海的JavaScript文件里靠搜索关键字和一点点运气去“人肉”定位加密函数效率极低宛如大海捞针。而JS HookJavaScript钩子技术就是解决这个痛点的“外科手术刀”。它不像暴力搜索更像是在关键路口设置检查站。简单来说Hook允许我们在目标网站执行其原有JavaScript代码的过程中插入我们自己的代码逻辑从而监控、修改甚至拦截特定对象的属性访问或函数调用。比如我们可以Hook住document.cookie的赋值操作或者Hook住window.XMLHttpRequest.prototype.send方法。当网站代码试图设置一个包含“token”的Cookie或者发送一个带有“sign”参数的请求时我们的钩子代码就会被触发通常是通过debugger语句让浏览器开发者工具自动断下。此时我们就能在调用栈Call Stack中清晰地看到是哪一行网站代码最终触发了这个操作从而逆向追踪到加密参数的生成逻辑源头。Fiddler作为老牌且强大的HTTP调试代理工具本身并不直接提供JS Hook功能。而编程猫插件则是一个专为Fiddler设计的脚本管理插件它提供了一个便捷的入口让我们能够将写好的Hook脚本注入到经过Fiddler代理的所有浏览器请求中。这个组合的优势在于无需修改浏览器、无需安装额外扩展、一次配置全局生效特别适合在需要纯净浏览器环境或进行自动化测试的场景下使用。所以这个项目的核心价值在于提供一套标准化、可复现的实战流程利用Fiddler编程猫插件这个“基础设施”在5分钟内搭建起JS Hook环境并精准定位到网站加密参数的生成位置。无论你是安全研究员、爬虫工程师还是前端开发者想了解第三方库的行为这套方法都能极大提升你的分析效率。2. 环境准备与工具部署搭建你的Hook作战平台工欲善其事必先利其器。整个环境的搭建是后续所有操作的基础这一步的稳定性直接决定了Hook的成功率。2.1 Fiddler Classic的安装与基础配置首先我们需要安装Fiddler Classic。请注意务必选择Fiddler Classic而不是Fiddler Everywhere。Classic版本是经典的WinForm应用插件生态丰富而Everywhere是新的跨平台版本目前对这类自定义插件的支持不如Classic完善。下载与安装从Fiddler官网下载安装包。安装过程基本一路“Next”即可注意安装路径最好不要包含中文或空格默认路径C:\Program Files (x86)\Fiddler2\就很好。首次运行与证书安装关键步骤首次以管理员身份运行Fiddler右键单击图标选择“以管理员身份运行”。Fiddler作为代理服务器需要安装自己的根证书到系统受信任的根证书颁发机构才能解密HTTPS流量。启动后点击菜单栏的Tools - Options - HTTPS勾选“Capture HTTPS CONNECTs”和“Decrypt HTTPS traffic”。此时会弹出证书安装提示按照指引一路确认安装即可。注意如果遇到证书安装失败或浏览器仍提示不安全可以尝试手动导出证书。在HTTPS选项卡中点击“Actions - Export Root Certificate to Desktop”然后将桌面生成的FiddlerRoot.cer文件双击安装选择“将所有的证书都放入下列存储”并手动选择“受信任的根证书颁发机构”。基础抓包设置在Tools - Options - Connections中可以设置代理监听的端口默认8888。确保“Allow remote computers to connect”是未勾选状态除非你需要抓取手机或其他设备的包。2.2 编程猫插件的安装与激活编程猫插件本质上是一个Fiddler的脚本扩展它将以标签页的形式集成在Fiddler界面中。获取插件从可靠的来源如提供的网盘链接或开源仓库下载编程猫插件的压缩包。通常是一个包含若干.js、.html和图像资源的文件夹。放置插件文件关闭Fiddler。将解压后的插件文件夹内的所有文件复制到Fiddler的脚本目录。这个目录通常是C:\Program Files (x86)\Fiddler2\Scripts\。如果Scripts文件夹不存在可以手动创建一个。验证安装再次以管理员身份启动Fiddler。启动后你应该能在Fiddler主界面的标签栏中看到一个新的标签页名称可能是“编程猫”、“CodingCat”或类似的字样。点击它如果能看到一个可以输入JavaScript代码的编辑区域以及“启用”、“保存”等按钮说明插件安装成功。实操心得很多同学在这一步失败原因有两个。第一没有用管理员权限运行Fiddler导致插件脚本没有权限加载。第二文件放错了位置一定要放到Fiddler2\Scripts\目录下而不是Fiddler2根目录或者其他地方。一个简单的检查方法是查看Fiddler启动时底部状态栏的日志如果有加载自定义脚本的提示通常就是成功了。2.3 浏览器代理配置与连通性测试要让浏览器的流量经过Fiddler需要设置系统代理。设置系统代理Fiddler启动后默认会自动设置系统代理为127.0.0.1:8888。你可以在Fiddler的File - Capture Traffic菜单中确认抓包开关是否打开快捷键F12。更稳妥的方式是在浏览器中安装类似“SwitchyOmega”这样的代理管理插件手动配置一个指向127.0.0.1:8888的代理情景模式方便随时切换。测试抓包保持Fiddler抓包开启用浏览器访问任意HTTP或HTTPS网站例如http://httpbin.org/ip。在Fiddler左侧的会话列表Web Sessions中你应该能看到刚刚产生的请求记录。点击一条HTTPS请求查看右侧的Inspectors标签页如果能正常看到“TextView”或“WebView”中显示的响应内容而不是TLS解密错误说明HTTPS解密配置成功。至此你的Hook作战平台已经搭建完毕。Fiddler负责流量拦截和转发编程猫插件负责向这些流量中注入我们的Hook脚本。3. JS Hook核心原理与常用代码模板解析在动手之前我们需要理解Hook是如何工作的以及几种常见的Hook方式。这能帮助我们在面对不同场景时选择合适的钩子。3.1 Hook的本质在关键节点插入“监听器”JavaScript在浏览器中运行其核心是对各种对象和函数的操作。Hook的目标就是这些操作点。例如对象属性document.cookie、window.localStorage。函数方法XMLHttpRequest.prototype.send、window.fetch、Object.defineProperty本身。Hook的原理就是利用JavaScript的语言特性替换掉原来的属性或方法。当我们访问这个属性或调用这个方法时实际上执行的是我们替换上去的代码。在我们的代码里我们可以记录信息、触发断点然后再选择是否继续执行原始的逻辑。3.2 三种主流的Hook实现方式3.2.1 直接覆盖属性/方法替换这是最简单粗暴的方式适用于Hook全局函数或对象的方法。// 示例Hook console.log记录所有日志输出 var oldLog console.log; console.log function(...args) { // 1. 执行我们自己的逻辑打印到页面某个元素或发送到服务器 debugger; // 触发断点方便调试 console.warn(有人调用了console.log!, args); // 2. 可选择性地继续执行原始函数 return oldLog.apply(this, args); };应用场景Hook一些常见的工具函数如JSON.stringify、Math.random用于固定随机数种子等。缺点是如果目标网站自己重写了这些方法我们的钩子可能会被覆盖。3.2.2 Object.defineProperty精准监控属性这是Hook对象属性的标准方法也是我们Hookdocument.cookie的核心技术。Object.defineProperty可以精确地定义或修改一个对象的属性并设置其getter和setter。(function() { use strict; var cookieCache ; // 用一个变量缓存cookie值 Object.defineProperty(document, cookie, { set: function(val) { // 当对document.cookie进行赋值时触发 console.log([Cookie Set Hook], val); // 关键判断是否包含我们关心的参数例如sessionid if (val.indexOf(sessionid) -1) { debugger; // 如果包含则在此处断住 // 此时可以在Call Stack中查看是谁设置了它 } cookieCache val; // 更新缓存 // 通常我们需要返回val让设置生效。如果不想生效可以返回其他值。 return val; }, get: function() { // 当读取document.cookie时触发 return cookieCache; } }); })();为什么需要缓存变量cookieCache因为我们在setter里拦截了赋值操作真正的document.cookie属性可能已经被我们“架空”了。我们需要自己维护一个内部状态cookieCache来存储当前的cookie值并在getter中返回它这样才能保证网站其他代码读取cookie时能得到正确的值否则整个网站的cookie机制就崩溃了。3.2.3 Proxy更强大的对象级监听ES6引入的Proxy可以创建一个对象的代理从而拦截并自定义该对象的基本操作如属性读取、赋值、枚举等。它比Object.defineProperty更强大可以监听整个对象的所有属性。// 示例Hook window.localStorage var originalLocalStorage window.localStorage; window.localStorage new Proxy(originalLocalStorage, { set: function(target, property, value) { console.log([LocalStorage Hook] 设置 ${property} ${value}); if (property token) { debugger; } // 调用原始对象的set方法 return target.setItem(property, value); }, get: function(target, property) { console.log([LocalStorage Hook] 读取 ${property}); // 调用原始对象的get方法 return target.getItem(property); } });应用场景当需要监控一个对象如localStorage、sessionStorage甚至自定义的全局数据对象的所有读写操作时使用Proxy比用Object.defineProperty逐个定义属性要方便得多。3.3 针对加密参数定位的Hook模板基于以上原理我们可以总结出几个最常用、最高效的Hook模板用于定位不同位置的加密参数。3.3.1 Cookie参数定位模板这是最经典的场景。很多网站的登录凭证如SESSION、UID或反爬标识如__jsluid_s会放在Cookie中。// 模板Hook Cookie中特定关键字的设置 (function() { use strict; var cookieTemp ; Object.defineProperty(document, cookie, { set: function(val) { // 将你想要监控的关键字放在这个数组里 var watchWords [token, session, sign, buvid3, sid]; for (var i 0; i watchWords.length; i) { if (val.indexOf(watchWords[i]) ! -1) { console.log(!!! 关键Cookie被设置 -, val); debugger; // 触发断点 break; } } cookieTemp val; return val; }, get: function() { return cookieTemp; } }); })();3.3.2 HTTP请求头Header参数定位模板加密参数经常出现在请求头里比如Authorization: Bearer xxx或者自定义的X-Sign: abcdef。// 模板Hook XMLHttpRequest的请求头设置 (function() { var originalSetRequestHeader window.XMLHttpRequest.prototype.setRequestHeader; window.XMLHttpRequest.prototype.setRequestHeader function(key, value) { // 监控特定的请求头键名 if (key.toLowerCase() authorization || key X-Sign) { console.log([Header Hook] 设置请求头: ${key} ${value}); debugger; } // 调用原始方法确保请求正常进行 return originalSetRequestHeader.apply(this, arguments); }; })();3.3.3 请求体Body参数定位模板对于POST请求加密参数通常在请求体Payload中。我们可以HookXMLHttpRequest.prototype.send或window.fetch。// 模板Hook XMLHttpRequest的send方法监控请求体 (function() { var originalSend window.XMLHttpRequest.prototype.send; window.XHR.prototype.send function(body) { // body就是请求体数据可能是字符串、FormData等 if (body typeof body string) { // 检查请求体中是否包含特定关键字 if (body.indexOf(encryptedData) ! -1 || body.indexOf(signature) ! -1) { console.log([Request Body Hook] 发现加密参数:, body); debugger; // 此时可以查看this对象里面包含了请求的URL、方法等信息 console.log(请求URL:, this._url || this.url); } } // 调用原始send方法 return originalSend.apply(this, arguments); }; })();注意事项有些网站会使用window.fetch发起请求所以更全面的做法是同时HookXMLHttpRequest.send和window.fetch。Hookfetch的思路类似但需要注意其Promise-based的API。4. 实战演练5分钟定位加密参数生成位置现在我们将理论付诸实践。假设我们遇到一个网站其登录请求的Payload中有一个名为_sign的加密参数我们需要找到它的生成算法。4.1 目标分析与Hook策略制定目标确认打开目标网站进入登录页打开浏览器开发者工具F12的Network面板。勾选“Preserve log”。输入错误的账号密码尝试登录在Network中找到一个状态码为200或400的登录请求通常是login、submit等接口。参数识别点击这个请求查看其Headers和Payload。假设我们在Request Payload或Form Data中发现了username,password,_sign三个字段。_sign是一长串看似随机的字母数字组合这就是我们的目标。策略制定_sign参数出现在请求体中。因此我们的Hook策略是HookXMLHttpRequest.prototype.send方法监控请求体当发现包含_sign字符串时触发debugger。4.2 在编程猫插件中部署Hook脚本打开Fiddler确保编程猫插件标签页已激活。在插件界面的代码编辑区域清空原有内容粘贴我们准备好的请求体Hook模板4.3.3节中的代码。为了更精准我们可以稍作修改(function() { var originalSend window.XMLHttpRequest.prototype.send; window.XMLHttpRequest.prototype.send function(body) { // 重点这里使用我们目标参数的关键字 _sign if (body typeof body string body.indexOf(_sign) ! -1) { console.log( 捕获到包含 _sign 的请求体); console.log(请求体内容:, body); debugger; // 核心在此处自动断住 } // 调用原始方法 return originalSend.apply(this, arguments); }; console.log([INFO] XHR Send Hook 已安装正在监听 _sign 参数...); })();点击插件界面上的“启用”或“开启Hook”之类的按钮不同版本插件按钮文字可能不同。通常界面会有一个明显的开关或复选框。4.3 触发断点与调用栈分析保持Fiddler抓包开启并确保编程猫插件处于启用状态。回到浏览器刷新目标网站的登录页面这一步很重要确保我们新注入的Hook代码在页面上下文中生效。再次在登录页输入账号密码点击登录按钮。奇迹发生点击登录后浏览器页面会立刻卡住并且开发者工具会自动打开并暂停在Sources面板。代码会停在我们的Hook脚本的debugger;这一行。这就是“断住了”。实操心得如果没断住请检查1. 编程猫插件是否真的启用了有些版本需要手动保存并勾选。2. 是否在注入Hook脚本之后刷新了页面Hook只对之后加载的页面上下文生效。3. 目标请求是否真的使用了XMLHttpRequest可以尝试同时Hookfetch。4. 请求体格式是否是字符串如果是FormData对象需要先用[...body.entries()]等方式转换判断。关键一步查看调用栈Call Stack。在开发者工具的Sources面板右侧找到Call Stack窗口。这里显示了导致程序执行到当前debugger语句的完整函数调用链。在Call Stack中最顶部的一行通常是我们自己的Hook代码通常是(anonymous)或send。我们需要忽略这些向下看。寻找来自网站域名的调用例如www.target-site.com下的文件如login.xxxx.js、vendor.js或是一串哈希值的文件。点击Call Stack中第一个看起来是网站自身的调用例如login.min.js:1。点击后代码视图会跳转到网站压缩过的源代码的那一行。这一行就是最终调用send方法的地方。但这还不够我们想知道_sign是在哪里被计算出来的。4.4 逆向追踪加密逻辑向上追踪从调用send的地方继续在Call Stack中向上点击。每点击一层代码视图就会跳转到调用当前函数的上一层函数。我们就像在倒放一部电影从结局发送请求一步步回溯到起因生成参数。寻找参数组装点在回溯的过程中仔细观察每一层函数的代码。寻找将_sign变量赋值或拼接到请求参数对象的地方。例如你可能会看到类似这样的代码var payload { username: uname, password: pwd, _sign: s // 或者 _sign: generateSign(uname, pwd) }; xhr.send(JSON.stringify(payload));定位加密函数一旦找到_sign被赋值的地方比如它等于一个变量s或者是一个函数generateSign()的返回值。那么你的下一个目标就是找到s的定义或者进入generateSign函数内部。如果s是一个变量可以在当前作用域或上层作用域搜索它的定义。如果是一个函数调用直接在generateSign函数名上右键选择 “Jump to definition”不同浏览器措辞不同可能是“Go to definition”开发者工具会直接带你到该函数的定义处。分析算法现在你就站在了加密参数生成的“车间”门口。在这个函数内部你可以看到_sign是如何被计算出来的。可能是对用户名、密码、时间戳进行MD5可能是进行RSA加密也可能是调用了另一个更复杂的黑盒函数。此时你可以结合Console面板打印中间变量的值或者使用Watch功能监控变量变化来彻底理解算法逻辑。常见问题与排查技巧实录问题1Call Stack里全是匿名函数或压缩后的代码看不清。技巧在开发者工具的Sources面板找到那个压缩的JS文件点击底部花括号{}图标“Pretty print”美化代码可以将压缩代码格式化增加可读性。问题2断点触发了但Call Stack很短没看到有用的业务代码。原因可能网站使用了异步请求Promise, async/await或者加密函数在另一个独立的Web Worker中执行。对策在Hook的debugger语句处不要停下按F10Step Over或F11Step Into单步执行观察程序流。同时可以尝试Hook更早的环节比如Hook参数对象的构造过程例如HookJSON.stringify或特定参数对象的赋值。问题3刷新页面后Hook失效。原因编程猫插件是“一次性”注入。页面刷新后新的页面上下文加载旧的Hook脚本失效。对策确保每次刷新目标页面后Fiddler和编程猫插件都在运行且启用状态。编程猫插件会在每个新的页面请求响应中自动重新注入脚本。如果遇到SPA单页应用页面内跳转不刷新的情况Hook可能会持续有效。5. 高级技巧与实战场景扩展掌握了基础定位方法后我们可以应对更复杂的情况并优化我们的Hook策略。5.1 Hook特定函数或加密算法有时你通过调用栈直接找到了加密函数比如window.encrypt()或CryptoJS.MD5()。你可以直接Hook这个函数本身监控其输入输出。// 示例Hook一个名为window.getSign的全局函数 var oldGetSign window.getSign; window.getSign function(param1, param2) { console.log(getSign 被调用参数:, param1, param2); debugger; // 在这里断住可以查看调用栈和参数 var result oldGetSign.apply(this, arguments); // 执行原函数 console.log(getSign 计算结果:, result); return result; // 返回原结果 };这种方法非常精准但前提是你已经知道了函数名。通常是在初步定位后进行深度分析时使用。5.2 条件断点与日志输出优化无差别的debugger可能会在非目标请求时也频繁断住干扰分析。我们可以结合条件判断和console.trace()来优化。// 优化版只在特定URL的请求时断点并输出追踪信息 (function() { var originalOpen XMLHttpRequest.prototype.open; var originalSend XMLHttpRequest.prototype.send; var targetUrlKeyword /api/login; // 只关心登录接口 XMLHttpRequest.prototype.open function(method, url) { this._requestUrl url; // 将url暂存到对象上供send方法使用 return originalOpen.apply(this, arguments); }; XMLHttpRequest.prototype.send function(body) { if (this._requestUrl this._requestUrl.indexOf(targetUrlKeyword) -1) { if (body body.indexOf(_sign) -1) { console.log( 在请求 ${this._requestUrl} 中发现_sign参数); console.trace(); // 在控制台输出完整的调用栈轨迹无需断点 // debugger; // 可以根据需要保留或注释掉 } } return originalSend.apply(this, arguments); }; })();console.trace()会在控制台打印出调用栈这样你可以在不断住页面操作的情况下清晰地看到触发路径对于分析流程非常有用。5.3 处理WebSocket和Fetch请求现代网站越来越多地使用WebSocket和Fetch API。Hook它们需要不同的方法。Hook Fetch:var originalFetch window.fetch; window.fetch function(...args) { // args[0]是URL, args[1]是配置对象包含body、headers console.log(Fetch被调用:, args[0], args[1]); if (args[1] args[1].body args[1].body.indexOf(sign) -1) { debugger; } // 调用原始fetch return originalFetch.apply(this, args); };Hook WebSocketWebSocket的Hook通常在WebSocket.prototype.send方法上。var originalWebSocketSend WebSocket.prototype.send; WebSocket.prototype.send function(data) { console.log(WebSocket发送数据:, data); if (typeof data string data.indexOf(encrypt) -1) { debugger; } return originalWebSocketSend.apply(this, arguments); };5.4 自动化与脚本管理当需要监控多个站点或多个参数时手动编写和切换脚本很麻烦。编程猫插件通常支持多脚本管理。你可以将不同的Hook脚本保存为不同的文件如hook_cookie.js,hook_xhr_sign.js。在编程猫插件界面中可能会有一个“加载脚本文件”或“管理脚本”的功能允许你选择启用哪个脚本。更进阶的做法是写一个Loader脚本根据当前页面的域名动态注入不同的Hook逻辑。// 示例一个简单的根据域名加载不同Hook的Loader (function() { var hostname window.location.hostname; var hookScript ; if (hostname www.site-a.com) { hookScript (function(){ /* Site A专用的Hook代码 */ })();; } else if (hostname www.site-b.com) { hookScript (function(){ /* Site B专用的Hook代码 */ })();; } if (hookScript) { var script document.createElement(script); script.textContent hookScript; document.documentElement.appendChild(script); script.parentNode.removeChild(script); console.log([Hook Loader] 已为 ${hostname} 注入特定Hook。); } })();将这段Loader代码放在编程猫插件中它就会在每个页面执行并根据域名自动选择策略。这需要你对JavaScript和插件机制有更深的理解。6. 安全、伦理与常见避坑指南在享受JS Hook强大能力的同时我们必须清醒地认识到其边界和风险。6.1 合法合规使用核心原则仅用于授权测试和个人学习。对自己拥有或获得明确授权的网站进行安全测试、性能调试、行为分析是正当的。对公开的、非商业性的API进行研究学习了解其实现原理通常也被视为合理使用。严格禁止用于破解他人网站核心业务逻辑、窃取未公开数据、绕过正常付费墙、进行恶意爬虫等侵犯他人合法权益的行为。这不仅不道德还可能违反《计算机信息系统安全保护条例》等相关法律法规。6.2 可能遇到的问题与解决方案网站反调试有些网站会检测开发者工具是否打开或者检测代码执行时间如果发现被调试可能会触发反爬机制、跳转到错误页面甚至停止运行。应对可以尝试使用“隐身模式”的开发者工具有些浏览器插件可以实现或者寻找并绕过反调试代码。对于时间检测可以尝试HookDate.now或performance.now来返回固定值。这是一场攻防战需要具体问题具体分析。Hook被覆盖或失效如果目标网站代码在很晚的时机比如在另一个脚本中重新定义了XMLHttpRequest.prototype.send你的Hook可能会被覆盖。应对尝试将你的Hook脚本注入时机提前。在编程猫插件中确保脚本在网站任何JS执行之前注入。也可以使用更“底层”的Hook方式比如HookFunction.prototype.call或apply但这更复杂且影响面广。无限Debugger循环如果你的Hook条件设置得太宽泛或者网站代码在循环中频繁操作被Hook的对象可能会导致debugger被反复触发页面卡死。应对在Hook代码中加入频率限制或更精确的条件判断。在开发者工具中可以点击“Deactivate breakpoints”停用断点按钮暂时禁用所有断点然后修改你的Hook脚本。影响网站正常功能不恰当的Hook尤其是getter/setter实现有误可能会破坏网站原有逻辑导致页面功能异常。应对在测试环境或本地副本上进行操作。Hook代码要尽量保持“透明”确保原始属性或方法的功能在Hook后依然能正确执行即正确调用原始方法或返回正确的值。6.3 性能考量注入的Hook脚本会随着页面生命周期一直存在并拦截所有匹配的操作。虽然单个Hook的性能开销很小但如果Hook点非常多、逻辑复杂可能会轻微影响页面性能。在完成分析后应及时在编程猫插件中禁用或清除Hook脚本。最后技术本身是中立的Fiddler和JS Hook是极其强大的分析和调试工具。将它们用于正当的学习和研究能帮你洞悉Web应用的运行机理提升解决复杂问题的能力。记住每一次成功的参数定位不仅是一次技术上的胜利更是对你耐心、逻辑思维和解决问题能力的一次锤炼。在实际操作中从简单的站点开始练手逐步积累经验你会发现自己面对加密参数时从最初的茫然无措变得愈发从容和有把握。