
本文教你通过浏览器开发者工具追踪动态插入弹窗的 JS 调用链,并利用 Greasemonkey/Tampermonkey 注入拦截逻辑,从根源屏蔽基于 jQuery insertBefore/removeChild 实现的定时弹窗行为。
本文教你通过浏览器开发者工具追踪动态插入弹窗的 js 调用链,并利用 greasemonkey/tampermonkey 注入拦截逻辑,从根源屏蔽基于 jquery `insertbefore`/`removechild` 实现的定时弹窗行为。
在现代网页中,随机弹窗(尤其是广告类)常通过 jQuery 的 DOM 操作方法(如 before()、after()、remove())动态注入和销毁 <div> 元素,其 ID 随机、无明确事件触发源,导致常规审查难以定位。但这类行为并非“无迹可循”——关键在于<strong>逆向追踪调用栈</strong>与<strong>前置拦截核心原生方法</strong>。<h3>? 第一步:精准定位弹窗源头</h3>
<ol>
<li>
<p><strong>启用调用栈捕获</strong><br>
在 Chrome DevTools 的 <em>Sources</em> 面板中,右键点击任意空白处 → 选择 <em>Breakpoints</em> → 勾选 <strong>"Native Event Listeners"</strong> 和 <strong>"DOM Breakpoints"</strong>;<br>
更有效的是:在弹窗出现瞬间,立即打开 <em>Console</em>,输入:</p>
<pre class="brush:php;toolbar:false;">monitor(setTimeout);
monitor(setInterval);</pre>
<p>这将记录所有定时器注册点,极大缩小可疑函数范围。</p>
</li>
<li><p><strong>捕获 DOM 修改调用栈</strong><br>
在 <em>Elements</em> 面板中,右键目标弹窗 <code><div> → <em>Break on</em> → <strong>"Subtree modifications"</strong>;<br>
当弹窗被 <code>insertBefore 插入时,Debugger 将自动暂停,并在右侧 Call Stack 中清晰显示:jQuery.fn.before → domManip → (anonymous) → yourAnnoyingAdFunction
—— 此处 yourAnnoyingAdFunction 即为罪魁祸首,通常位于内联 <script></script> 或第三方脚本中。
? 第二步:从源头屏蔽(推荐 Greasemonkey 方案)
若确认弹窗由 insertBefore 触发,可直接重写该方法进行条件拦截。以下脚本兼容 jQuery 2.x 及原生 DOM 操作:
// ==UserScript==
// @name Block Annoying Popups
// @namespace https://github.com/user/block-popup
// @version 1.2
// @description 屏蔽基于 insertBefore/removeChild 的随机弹窗
// @match *://*/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 缓存原始方法
const originalInsertBefore = Node.prototype.insertBefore;
const originalRemoveChild = Node.prototype.removeChild;
// 定义弹窗特征(可根据实际调整)
const POPUP_PATTERNS = [
/ad/i,
/popup/i,
/modal/i,
/banner/i,
/^.*[0-9a-f]{8,}/ // 匹配随机ID(如 "ad_7f3a9b2c")
];
// 拦截 insertBefore:阻止含敏感特征的节点插入
Node.prototype.insertBefore = function(newNode, refNode) {
if (newNode && newNode.nodeType === 1) {
const id = newNode.id || '';
const className = newNode.className || '';
const outerHTML = newNode.outerHTML?.substring(0, 200) || '';
if (POPUP_PATTERNS.some(pattern =>
pattern.test(id) ||
pattern.test(className) ||
pattern.test(outerHTML)
)) {
console.warn('[Popup Blocker] Blocked suspicious node insertion:', newNode);
return null; // 阻止插入
}
}
return originalInsertBefore.call(this, newNode, refNode);
};
// 拦截 removeChild:防止弹窗被“清理”后二次触发
Node.prototype.removeChild = function(child) {
if (child && child.nodeType === 1) {
const id = child.id || '';
if (/^popup|ad\d{4,}$/.test(id)) {
console.info('[Popup Blocker] Prevented removal of persistent popup:', child);
return child; // 不真正移除,维持 DOM 稳定性
}
}
return originalRemoveChild.call(this, child);
};
})();
✅ 优势说明:
- 不依赖 jQuery 版本,直击原生 DOM API;
- 使用正则匹配 ID/className/HTML 片段,适应随机命名;
console.warn提供调试线索,便于后续规则优化;- 保留
removeChild返回值避免破坏 jQuery 内部逻辑。
⚠️ 注意事项与进阶建议
-
避免过度拦截:
POPUP_PATTERNS列表需根据实际弹窗特征精简,否则可能误杀正常组件(如含ad的商品 ID); -
jQuery 2.0.3 兼容性:该版本不支持
MutationObserver,故优先使用insertBefore拦截而非监听; -
持久化生效:若弹窗由
eval()或setTimeout("...")字符串执行,需额外重写window.eval和setTimeout(需@grant unsafe-eval,慎用); -
终极方案:结合 uBlock Origin 的
##div:has-text(/广告|弹窗/)CSS 选择器过滤,实现双保险。
通过以上方法,你不仅能彻底屏蔽烦人弹窗,更能深入理解前端动态内容注入机制——这正是前端安全与逆向调试的核心能力。











