作者:星安果 来源:AirPython 大部分网站都会对关键参数进行加密,JS 逆向时,我们首要任务是定位参数具体的加密逻辑 常见方式包含:关键字搜索、堆栈调试、XHR 及事件监听、AST 内存漫游、JS Hook 注入等 本篇文章以 JS Hook 注入定位 Cookie 中某个加密参数为例进行讲解 Cookie 监听 编写一个 Chrome 插件( V3 版本)监听浏览器 Cookie 值的变动,当 Cookie 的 Name 匹配时执行 debugger 命令主动触发调试 具体实现如下: 1-1 编写 manifest.json 配置文件 在配置文件中,指定 background.js、content_script 并通过 permissions、host_permissions 进行权限设置 { 1-2 监听 Cookie 在 background.js 文件中添加一个事件监听,在它的回调函数中再添加一个对 Cookie 的监听事件 当监听到的 Cookie 满足条件时,发送消息给 Content Script 去执行具体的动作 需要指出的是,changeInfo.cause 表示 Cookie 变化的原因,值 explicit 表示 Cookie 变化是由于用户主动操作导致的 # 监听的cookie_name 1-3 触发调试 在 Content Script 中,主动触发一次发起调试的消息给 Background 然后,设置一个监听事件,特定条件下主动进入调试模式 // cookie.js 将编写好的 Chrome 插件安装到浏览器上,打开目标网站及浏览器开发者工具 只要指定的 Cookie 变动,就会自动触发调试操作 Cookie Hook 通过上面的方式仅仅只能发现 Cookie 变动了,但是没法定位到参数设置的具体位置,因此我们需要借助 Hook 进行改造 具体实现如下: 2-1 配置文件中指定 Hook 文件 在 manifest.json 文件中,使用 web_accessible_resources 关键字指定 Hook 脚本及匹配 URL // manifest.json 2-2 Content Script 注入 JS 在 Content Script 中注入 JS Hook 代码 // cookie.js 2-3 JS Hook 具体逻辑 在 cookie_hook.js 文件中,使用 document.__lookupSetter__ 对 Cookie 设置注入脚本,手动触发调试 // cookie_hook.js 当然,我们也可以利用下面的方式进行注入 // cookie_hook.js 2-4 使用 在 Chrome 浏览器中安装扩展后,打开浏览器开发者工具和目前网站,一旦目标 Cookie 被设定一个值后,会自动进入断点模式 在调试模式下,我们就可以在 Source 面板利用 Call Stack 调用栈一步步查询到加密参数生成的具体逻辑
"manifest_version": 3,
...
"background": {
"service_worker": "background.js"
},
"content_scripts":[
{
"matches": [
"<all_urls>"
],
"js": [
"js/cookie.js"
],
"run_at": "document_start"
}],
"permissions": [
"cookies",
"tabs",
"scripting"
],
"host_permissions": [
"https://host/*"
],
...
}
const targetCookieName = "cookie_name";
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "startDebugging") {
chrome.cookies.onChanged.addListener((changeInfo) => {
//console.log("监控到cookie变化")
//console.log(changeInfo.cookie.name)
//console.log(changeInfo.cause)
if (changeInfo.cookie.name === targetCookieName && changeInfo.cause === "explicit") {
console.log("监控到cookie变化-explicit,名称:",changeInfo.cookie.name)
chrome.tabs.sendMessage(sender.tab.id, { action: "debugger" });
}
});
}
});
chrome.runtime.sendMessage({ action: "startDebugging" });
chrome.runtime.onMessage.addListener((request) => {
if (request.action === "debugger") {
debugger;
}
});
{
"manifest_version": 3,
...
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"js/cookie.js"
],
"run_at": "document_end"
}
],
"permissions": [
"cookies",
"tabs",
"scripting"
],
"host_permissions": [
"*://*/*"
],
"web_accessible_resources": [
{
"resources": [
"js/cookie_hook.js"
],
"matches": [
"https://host/*"
]
}
]
}
function import_js(js_path) {
let tmp = document.createElement('script');
tmp.src = chrome.runtime.getURL(js_path);
tmp.setAttribute('type', 'text/javaScript');
document.head.appendChild(tmp);
}
(function () {
let url = window.location.href;
import_js('js/cookie_hook.js')
})()
//待匹配的Cookie-Key
const targetCookieName = "cookie_name";
//Hook Cookie Set
//注意:这种方法可能与某些网站的JavaScript代码不兼容,因为它依赖于废弃的__defineSetter__方法
function hookCookieSetter() {
const originalCookieSetter = document.__lookupSetter__("cookie");
document.__defineSetter__("cookie", function (value) {
const cookieName = value.split("=")[0].trim();
if (cookieName === targetCookieName) {
debugger;
}
//调用
originalCookieSetter.call(document, value);
});
}
hookCookieSetter();
//待匹配的Cookie-Key
const targetCookieName = "cookie_name";
//cookie 钩子:用于定位 cookie 中关键参数生成位置
var code = function(){
var org = document.cookie.__lookupSetter__('cookie');
document.__defineSetter__("cookie",function(cookie){
if(cookie.indexOf(targetCookieName)>-1){
debugger;
}
org = cookie;
});
document.__defineGetter__("cookie",function(){return org;});
}
var script = document.createElement('script');
script.textContent = '(' + code + ')()';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);