您说得对,window.location
是一个特殊的只读对象,直接代理或 Hook 确实会遇到问题。不过我们仍然可以通过一些技巧来检测它的访问和修改。以下是几种可行的解决方案:
1. 通过 Object.getOwnPropertyDescriptor
分析
虽然不能直接修改 location
,但可以检查它的属性描述符:
const locationDesc = Object.getOwnPropertyDescriptor(window, 'location');
console.log('Location descriptor:', locationDesc);
// 输出结果会显示 configurable: false(不可配置)
2. 间接监控跳转行为
(1)监听 beforeunload
事件
任何通过 location.href
或类似属性的跳转都会触发页面卸载:
window.addEventListener('beforeunload', (e) => {
console.trace('Page is unloading, likely due to location change');
// 可以记录当前调用栈
});
(2)拦截 document.write
或动态脚本加载
某些混淆代码可能通过其他方式触发跳转:
const originalWrite = document.write;
document.write = function(...args) {
console.log('Document.write called with:', args);
return originalWrite.apply(this, args);
};
3. AST 静态分析(推荐)
即使代码被混淆,AST 分析也能识别所有访问形式。例如:
window.location.href
window['location']['href']
var a=window; a.location.hash
工具推荐:
- Babel Parser + AST 遍历插件
- eslint-plugin-no-unsafe-redirect(专为检测跳转设计)
4. Chrome DevTools 的「Event Listener Breakpoints」
- 打开 DevTools → Sources → Event Listener Breakpoints
- 勾选
load
/beforeunload
/unload
- 当跳转发生时会自动暂停并显示调用栈。
5. Override JavaScript API(实验性)
通过调试器覆盖内置方法(需在页面加载前执行):
// 在 DevTools Console 中提前执行
debugger;
Object.defineProperty(window, 'open', {
value: function(url) {
console.trace('window.open called with URL:', url);
return null; // 阻止弹窗
},
configurable: true
});
6. Service Worker + Proxy(高级方案)
如果是单页应用(SPA),可通过 Service Worker 拦截所有导航请求:
self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
console.log('Navigation attempt to:', event.request.url);
}
});
注意事项
- CSP限制:某些网站的 Content Security Policy 会阻止调试脚本注入。
- 即时生效:Hook代码需在目标脚本执行前注入(可通过Chrome扩展或Fiddler等工具实现)。
- 反调试陷阱:部分混淆代码会检测DevTools并改变行为。
如果需要进一步分析具体案例,可以提供部分混淆代码片段,我可以给出更有针对性的解决方案。
内容由零声教学AI助手提供,问题来源于学员提问