288 lines
9.5 KiB
JavaScript
288 lines
9.5 KiB
JavaScript
/**
|
||
* 浏览器Hook脚本
|
||
* 在浏览器Console中运行此脚本,可以拦截并分析API请求参数
|
||
*
|
||
* 使用方法:
|
||
* 1. 打开开发者工具 (F12)
|
||
* 2. 切换到 Console 标签
|
||
* 3. 复制粘贴此脚本并回车
|
||
* 4. 进行正常操作,脚本会自动捕获并显示请求信息
|
||
*/
|
||
|
||
(function() {
|
||
console.log('🚀 参数捕获Hook已启动');
|
||
console.log('📍 监听目标: getInstituteDarenData 及相关API');
|
||
console.log('─'.repeat(80));
|
||
|
||
// 配置
|
||
const TARGET_APIS = [
|
||
'getInstituteDarenData',
|
||
'authorTradeData',
|
||
'api/data',
|
||
'ark/api'
|
||
];
|
||
|
||
// 工具函数
|
||
function shouldCapture(url) {
|
||
return TARGET_APIS.some(api => url.includes(api));
|
||
}
|
||
|
||
function extractParams(url) {
|
||
try {
|
||
const urlObj = new URL(url);
|
||
const params = {};
|
||
urlObj.searchParams.forEach((value, key) => {
|
||
params[key] = value;
|
||
});
|
||
return params;
|
||
} catch (e) {
|
||
return {};
|
||
}
|
||
}
|
||
|
||
function formatParams(params) {
|
||
const signParams = ['verifyFp', 'fp', 'msToken', 'a_bogus'];
|
||
const result = { sign: {}, business: {} };
|
||
|
||
Object.entries(params).forEach(([key, value]) => {
|
||
if (signParams.includes(key)) {
|
||
result.sign[key] = value;
|
||
} else {
|
||
result.business[key] = value;
|
||
}
|
||
});
|
||
|
||
return result;
|
||
}
|
||
|
||
function printCapturedRequest(method, url, params, headers) {
|
||
console.log('\n' + '='.repeat(80));
|
||
console.log(`🔍 捕获到 ${method} 请求`);
|
||
console.log('='.repeat(80));
|
||
|
||
// URL
|
||
try {
|
||
const urlObj = new URL(url);
|
||
console.log(`\n📍 URL: ${urlObj.origin}${urlObj.pathname}`);
|
||
} catch (e) {
|
||
console.log(`\n📍 URL: ${url}`);
|
||
}
|
||
|
||
// 参数分组
|
||
const { sign, business } = formatParams(params);
|
||
|
||
if (Object.keys(sign).length > 0) {
|
||
console.log('\n🔑 验签参数:');
|
||
console.table(sign);
|
||
}
|
||
|
||
if (Object.keys(business).length > 0) {
|
||
console.log('\n📋 业务参数:');
|
||
console.table(business);
|
||
}
|
||
|
||
// 关键请求头
|
||
if (headers) {
|
||
const importantHeaders = {};
|
||
['cookie', 'user-agent', 'referer', 'origin'].forEach(key => {
|
||
if (headers[key]) {
|
||
const value = headers[key];
|
||
importantHeaders[key] = value.length > 100
|
||
? value.substring(0, 100) + '...'
|
||
: value;
|
||
}
|
||
});
|
||
|
||
if (Object.keys(importantHeaders).length > 0) {
|
||
console.log('\n📨 关键请求头:');
|
||
console.table(importantHeaders);
|
||
}
|
||
}
|
||
|
||
// 调用栈
|
||
console.log('\n📚 调用栈:');
|
||
console.trace();
|
||
|
||
console.log('='.repeat(80) + '\n');
|
||
}
|
||
|
||
// Hook XMLHttpRequest
|
||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||
const originalXHRSend = XMLHttpRequest.prototype.send;
|
||
const originalXHRSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
||
|
||
XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
|
||
if (!this._requestHeaders) {
|
||
this._requestHeaders = {};
|
||
}
|
||
this._requestHeaders[header.toLowerCase()] = value;
|
||
return originalXHRSetRequestHeader.apply(this, arguments);
|
||
};
|
||
|
||
XMLHttpRequest.prototype.open = function(method, url) {
|
||
this._method = method;
|
||
this._url = url;
|
||
return originalXHROpen.apply(this, arguments);
|
||
};
|
||
|
||
XMLHttpRequest.prototype.send = function(data) {
|
||
if (this._url && shouldCapture(this._url)) {
|
||
const params = extractParams(this._url);
|
||
printCapturedRequest(
|
||
this._method,
|
||
this._url,
|
||
params,
|
||
this._requestHeaders
|
||
);
|
||
|
||
// 保存数据供后续分析
|
||
if (!window._capturedRequests) {
|
||
window._capturedRequests = [];
|
||
}
|
||
window._capturedRequests.push({
|
||
timestamp: Date.now(),
|
||
method: this._method,
|
||
url: this._url,
|
||
params: params,
|
||
headers: this._requestHeaders,
|
||
data: data
|
||
});
|
||
}
|
||
return originalXHRSend.apply(this, arguments);
|
||
};
|
||
|
||
// Hook fetch
|
||
const originalFetch = window.fetch;
|
||
window.fetch = function(...args) {
|
||
const url = typeof args[0] === 'string' ? args[0] : args[0].url;
|
||
|
||
if (shouldCapture(url)) {
|
||
const options = args[1] || {};
|
||
const params = extractParams(url);
|
||
|
||
// 提取headers
|
||
const headers = {};
|
||
if (options.headers) {
|
||
if (options.headers instanceof Headers) {
|
||
options.headers.forEach((value, key) => {
|
||
headers[key.toLowerCase()] = value;
|
||
});
|
||
} else {
|
||
Object.entries(options.headers).forEach(([key, value]) => {
|
||
headers[key.toLowerCase()] = value;
|
||
});
|
||
}
|
||
}
|
||
|
||
printCapturedRequest(
|
||
options.method || 'GET',
|
||
url,
|
||
params,
|
||
headers
|
||
);
|
||
|
||
// 保存数据
|
||
if (!window._capturedRequests) {
|
||
window._capturedRequests = [];
|
||
}
|
||
window._capturedRequests.push({
|
||
timestamp: Date.now(),
|
||
method: options.method || 'GET',
|
||
url: url,
|
||
params: params,
|
||
headers: headers,
|
||
data: options.body
|
||
});
|
||
}
|
||
|
||
return originalFetch.apply(this, arguments);
|
||
};
|
||
|
||
// Hook WebSocket (如果需要)
|
||
const originalWebSocket = window.WebSocket;
|
||
window.WebSocket = function(url, protocols) {
|
||
if (shouldCapture(url)) {
|
||
console.log('🔌 WebSocket连接:', url);
|
||
}
|
||
return new originalWebSocket(url, protocols);
|
||
};
|
||
|
||
// 添加全局辅助函数
|
||
window._showCapturedRequests = function() {
|
||
if (!window._capturedRequests || window._capturedRequests.length === 0) {
|
||
console.log('📭 暂无捕获的请求');
|
||
return;
|
||
}
|
||
|
||
console.log(`\n📊 已捕获 ${window._capturedRequests.length} 个请求:\n`);
|
||
window._capturedRequests.forEach((req, index) => {
|
||
const time = new Date(req.timestamp).toLocaleTimeString();
|
||
console.log(`${index + 1}. [${time}] ${req.method} ${req.url}`);
|
||
});
|
||
|
||
console.log('\n💡 使用 window._capturedRequests[index] 查看详细信息');
|
||
};
|
||
|
||
window._clearCapturedRequests = function() {
|
||
window._capturedRequests = [];
|
||
console.log('🗑️ 已清空捕获的请求');
|
||
};
|
||
|
||
window._exportCapturedRequests = function() {
|
||
if (!window._capturedRequests || window._capturedRequests.length === 0) {
|
||
console.log('📭 暂无可导出的请求');
|
||
return;
|
||
}
|
||
|
||
const dataStr = JSON.stringify(window._capturedRequests, null, 2);
|
||
const blob = new Blob([dataStr], { type: 'application/json' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `captured_requests_${Date.now()}.json`;
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
|
||
console.log('💾 请求数据已导出');
|
||
};
|
||
|
||
// Hook常见的加密函数(如果存在)
|
||
const cryptoFunctions = ['md5', 'sha1', 'sha256', 'hmac', 'sign', 'encrypt'];
|
||
cryptoFunctions.forEach(funcName => {
|
||
if (window[funcName] && typeof window[funcName] === 'function') {
|
||
const original = window[funcName];
|
||
window[funcName] = function(...args) {
|
||
console.log(`🔐 调用加密函数: ${funcName}`, args);
|
||
const result = original.apply(this, args);
|
||
console.log(`🔐 返回结果:`, result);
|
||
return result;
|
||
};
|
||
}
|
||
});
|
||
|
||
// 监听全局变量变化(如果有签名相关的全局变量)
|
||
const watchedGlobals = ['_signature', '_token', '_bogus', 'msToken'];
|
||
watchedGlobals.forEach(varName => {
|
||
let value = window[varName];
|
||
Object.defineProperty(window, varName, {
|
||
get() {
|
||
return value;
|
||
},
|
||
set(newValue) {
|
||
console.log(`📝 全局变量 ${varName} 被设置:`, newValue);
|
||
console.trace('调用栈:');
|
||
value = newValue;
|
||
}
|
||
});
|
||
});
|
||
|
||
console.log('\n✅ Hook安装完成!');
|
||
console.log('\n💡 可用命令:');
|
||
console.log(' - window._showCapturedRequests() 查看所有捕获的请求');
|
||
console.log(' - window._clearCapturedRequests() 清空捕获记录');
|
||
console.log(' - window._exportCapturedRequests() 导出为JSON文件');
|
||
console.log(' - window._capturedRequests[0] 查看第一个请求详情');
|
||
console.log('\n🎯 现在可以进行正常操作,脚本会自动捕获请求!\n');
|
||
})();
|
||
|