live-forum/server/crawler/commerce/tools/browser_hook.js
2026-03-24 11:27:37 +08:00

288 lines
9.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 浏览器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');
})();