dp-2026-1
cloak/dp-2026/1
3 个文件
105.3 KB
下载 3 次
dp-2026-1 斗篷脚本 · 分析与优化报告
分析对象:dp-code.js(已补充详细中文注释) 关联文件:
辅助工具/tg.html(落地页样例)、辅助工具/通用注入代码.txt(页面注入模板) 本版本状态:已移除反调试自保护与移动端mousemove触发逻辑;遮罩改为"真正移除"而非置透明
0. 结论速览
- 当前流程为三关卡闸门式判定:参数齐全 → 关键词命中 → 桌面环境,全部通过才切换页面,否则一律保持"空白 + Loading"。结构清晰,无冗余分支。
- 上线前唯一的阻断项是配置:
confArr仍是占位值['Name', 'Link'],整条链路实际处于空转状态(P0-01)。 - 已修复的高危缺陷:遮罩此前只被"置为透明",而
.haoniuwlls覆盖全屏且未设置pointer-events: none,会导致页面看得见却点不动;现在改为真正remove()。 - 仍需业务侧决策的:移动端命中后永久白屏(真实移动用户同样如此)(P1-04)。
1. 文件与依赖清单
| 文件 | 角色 | 关键点 |
|---|---|---|
dp-code.js |
斗篷主逻辑 | 参数校验 + 关键词匹配 + 桌面判定 + 页面替换 + 遮罩移除 |
辅助工具/通用注入代码.txt |
注入到宿主页的片段 | 提供 <ul class='haoniuwlls'> 遮罩占位 + 外部 CSS 引用 |
辅助工具/tg.html |
落地页样例 | iframe 的目标页;其内部把全站 <a> 的 href 统一改写为固定地址 |
外部 custom.css |
遮罩样式(squarespace 域名托管) | 全屏白底遮罩 + Loading 转圈动画,均由此文件定义;未加载则遮罩完全失效 |
依赖关系:dp-code.js 能否命中"空白 + Loading"这一前置状态,完全取决于注入模板的 DOM 结构(.haoniuwlls)与外部 CSS 是否同时生效。
2. 执行流程
2.1 页面初始状态:空白 + Loading(由 CSS 提供,非 JS 生成)
遮罩来自宿主页注入的 HTML 结构(<ul class='haoniuwlls'><li></li></ul>),样式来自外部 custom.css,实际内容如下:
*{padding:0;margin:0}
body{min-height:100vh}
img{width:100%;cursor:pointer}
ul.haoniuwlls{width:100%;height:100%;position:fixed;left:0;top:0;
background:rgba(255,255,255,.99);z-index:1000}
ul.haoniuwlls li{width:5vh;height:5vh;border:4px solid #e3e3e3;
border-top:4px solid #09f;border-radius:50%;
animation:haoniuwllsiwuyh 1s linear infinite;
margin:auto;margin-top:47.5vh;list-style:none}
@keyframes haoniuwllsiwuyh{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
要点:
position: fixed+100% × 100%+z-index: 1000+rgba(255,255,255,.99)→ 全屏近不透明遮罩。li的border-top蓝色 + 无限旋转动画 → 即肉眼看到的 Loading 转圈。- 没有
pointer-events: none→ 只要该元素还在 DOM 里,它就会截获全屏点击(这正是必须remove()的原因)。
2.2 三道关卡
| 关卡 | 判定内容 | 不通过的结果 |
|---|---|---|
| 1 | URL 同时存在 kw、gclid、gad_campaignid |
直接 return,保持空白 + Loading |
| 2 | 归一化后的 kw 命中 confArr 中某条正则 |
直接 return,保持空白 + Loading |
| 3 | isDesktopLike() 返回 true |
直接 return,保持空白 + Loading |
补充说明:
- 关卡 1 只读这 3 个参数(不是"读取全部参数"),其余查询参数一律忽略。
kw归一化:转小写 + 去掉全部空格(含词中间空格),使Air Pods与airpods命中同一规则。- 关卡 2 是"三参数齐全"之外的必要条件——参数齐全 ≠ 一定切换,未命中关键词同样什么都不做。
- 关卡 3 的
screen.height !== screen.availHeight本质是"系统是否存在任务栏/菜单栏",属经验判断。
2.3 通过后的动作
swapBodyToIframe(url):document.title改写为硬编码的'site',再用body.innerHTML把整页替换为「全屏 iframe(100% × 100vh)+ 空的<ul class="haoniuwlls">」。原页面 DOM 被整体丢弃,但已加载的脚本、定时器、监听器仍在后台运行。- 移除遮罩:
document.getElementsByClassName(OVERLAY_CLASS)[0].remove(),真正把全屏遮罩从 DOM 中摘除,恢复页面可点击。
2.4 完整流程
用户进入页面
└─ 外部 custom.css 生效:全屏白底遮罩 + Loading 转圈(空白 + Loading)
脚本加载 → DOMContentLoaded
├─ 关卡 1:kw / gclid / gad_campaignid 齐全?
│ └─ 否 → return(保持空白 + Loading)
├─ kw 归一化(小写 + 去空格)
├─ 关卡 2:命中 confArr 中某条关键词?
│ └─ 否 → return(保持空白 + Loading)
├─ 关卡 3:是桌面环境?
│ └─ 否 → return(保持空白 + Loading,移动端即走此分支)
├─ swapBodyToIframe(命中配置的 URL):整页替换为全屏 iframe
└─ 移除 .haoniuwlls 遮罩
2.5 分支结果矩阵
| 参数齐全 | 命中关键词 | 桌面环境 | 结果 |
|---|---|---|---|
| ✗ | — | — | 保持空白 + Loading |
| ✓ | ✗ | — | 保持空白 + Loading |
| ✓ | ✓ | ✗ | 保持空白 + Loading(移动端不处理) |
| ✓ | ✓ | ✓ | 全屏替换为 iframe,遮罩被移除 |
3. 问题清单
P0 · 阻断上线
| 编号 | 位置 | 问题 | 影响 | 建议 |
|---|---|---|---|---|
| P0-01 | confArr(配置表) |
仍是占位值 ['Name', 'Link'] |
关卡 2 几乎不可能命中;即便命中,iframe src="Link" 也是无效地址 |
填入真实 [关键词, 落地页URL],并确认目标页允许被 iframe 嵌套 |
| P0-02 | 外部依赖 | 遮罩结构与 custom.css 均为外部依赖,脚本内无兜底 |
移除遮罩处直接取 [0];若注入缺失,该值为 undefined(当前有 if (overlay) 保护,但缺失时页面会漏出原始内容而非白页) |
上线前用 辅助工具/tg.html + 注入模板做全链路自测 |
P1 · 高风险
| 编号 | 位置 | 问题 | 影响 | 建议 |
|---|---|---|---|---|
| P1-01 | kw.toLowerCase().replaceAll(' ', '') |
String.prototype.replaceAll 属 ES2021,老 WebView / 旧浏览器不支持 |
抛 TypeError → 整个 DOMContentLoaded 回调中断,任意关卡都不会执行 |
改为 replace(/\s+/g, '') |
| P1-02 | swapBodyToIframe |
无 onerror、无加载超时兜底 |
目标站返回 X-Frame-Options: DENY 或 CSP frame-ancestors 限制时,遮罩已被移除,用户看到纯白屏且无法回退 |
增加加载超时检测,失败时保留遮罩或恢复原页面 |
| P1-03 | 关卡 1 | 只校验参数"存在",不校验取值与来源 | 手工拼接 ?kw=xxx&gclid=1&gad_campaignid=1 即可复现切换效果,斗篷可被人工/竞品轻易验证 |
校验 gclid 长度与字符集,叠加 document.referrer 等辅助判断 |
| P1-04 | 关卡 3 | 非桌面环境(移动端)直接 return,遮罩永不移除 |
移动端真实用户与审查流量一样,永远停在空白 + Loading,若该落地页有移动端投放会 100% 无转化 | 确认这是预期策略;若否,需增加移动端处理分支 |
| P1-05 | 遮罩 CSS | z-index 仅 1000,且为外链加载 |
宿主页若有不低于 1000 的元素(如 bootstrap 的 .navbar-static-top 同样是 1000),白页可能漏出内容;外链 CSS 下载完成前原页面内容可见(内容闪现) |
用 DevTools 逐一核对层叠关系;CSS 可考虑内联关键样式 |
P2 · 健壮性
| 编号 | 位置 | 问题 | 影响 | 建议 |
|---|---|---|---|---|
| P2-01 | new RegExp(confArr[i][0]) |
配置片段直接参与正则构造,未转义;关键词含 + ? ( ) [ 等元字符会异常匹配或抛 SyntaxError,且未包 try/catch |
异常中断整个回调(同 P1-01 的后果) | 转义配置片段后再构造正则,并把匹配包进 try/catch |
| P2-02 | 整体缺少异常兜底 | DOMContentLoaded 回调与两个函数均无错误处理 |
任一环节抛错都会让页面停在空白 + Loading,且(反调试已移除后)报错会直接出现在控制台 | 对外层回调做一次统一 try/catch,失败时保持遮罩不动 |
P3 · 可维护性与性能
| 编号 | 位置 | 问题 | 建议 |
|---|---|---|---|
| P3-01 | confArr 结构 |
用下标表达"关键词 / 落地页",可读性差 | 改为对象数组:{ pattern: 'xxx', url: 'https://...' } |
| P3-02 | 配置分散 | 'site' 标题、OVERLAY_CLASS、confArr 分散在文件各处 |
统一收敛到顶部 CONFIG 区块,并注明修改注意事项 |
| P3-03 | swapBodyToIframe |
先把 body 换成「iframe + 空的遮罩占位」,随后又立刻移除该占位 |
可直接不创建该 <ul>,少一次 DOM 变更 |
| P3-04 | 可观测性 | 无任何命中/异常上报,线上无法评估效果 | 用 navigator.sendBeacon 上报命中事件(需自行评估合规风险) |
| P3-05 | 正则构造 | 循环内重复 new RegExp |
配置量增大时预编译缓存 |
| P3-06 | 原页面残留 | body.innerHTML 整体替换后,原页面的脚本、定时器、监听器仍在后台运行 |
若非必要,替换前先清理页面级定时器/监听 |
4. 修复建议片段
4.1 关键词正则转义(P2-01)
// 把配置中的关键词转义为字面量,避免 + ? ( ) [ ] 等元字符破坏匹配
function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
try {
if (new RegExp(escapeRegExp(confArr[i][0].toLowerCase())).test(kw)) { /* ... */ }
} catch (e) {
// 匹配异常不应影响后续流程
}
4.2 兼容老浏览器(P1-01)
// replaceAll 属 ES2021,老 WebView 不支持
kw = kw.toLowerCase().replace(/\s+/g, '');
4.3 iframe 加载失败兜底(P1-02)
// 加载超时则移除 iframe 并恢复遮罩,避免用户停在纯白屏
var timer = setTimeout(function () {
document.body.innerHTML = '';
document.body.appendChild(overlay);
}, 8000);
4.4 配置结构化(P3-01 / P3-02)
var CONFIG = {
OVERLAY_CLASS: 'haoniuwlls',
PAGE_TITLE: 'site',
RULES: [
{ pattern: 'telegram|tg|飞机', url: 'https://xxx.example.com/lp/index.html' },
],
};
5. 上线前检查清单
- [ ]
confArr已填入真实关键词与落地页地址,并逐条验证命中效果(P0-01) - [ ] 目标落地页允许被 iframe 嵌套(无
X-Frame-Options/ CSPframe-ancestors限制)(P1-02) - [ ] 宿主页已注入
.haoniuwlls结构,外部custom.css可正常加载,白页不漏内容(P0-02、P1-05) - [ ] 桌面端验证:命中后 iframe 显示正常,且页面可以正常点击(遮罩已移除)
- [ ] 移动端验证:确认"永久空白 + Loading"是预期行为(P1-04)
- [ ] 在目标机型的最低版本浏览器中验证脚本无 API 报错(P1-01)
- [ ] 确认手工拼接
kw/gclid/gad_campaignid无法被轻易复现(P1-03)
6. 待确认事项
- 移动端"永久空白 + Loading"是否为最终策略? 该分支目前对所有移动端访问者生效,包括真实用户。
- 关键词配置的维护方式? 人工改代码,还是后续接入接口/配置中心下发。
- 是否需要多落地页分流? 影响
confArr的结构设计(P3-01)。 - iframe 加载失败时的期望表现? 停留白屏,还是回退到遮罩/原页面(P1-02)。
7. 合规提示
本脚本的实现目标是根据 kw、gclid、gad_campaignid 等参数,对不同来源的访问者呈现不同内容(并向非目标环境展示空白页)。此类做法通常与主流广告平台(含 Google Ads)关于落地页一致性和审查规避的政策相冲突,可能引发账户封禁、投放受限等后果。建议在实际投放前完成合规评估,并由业务方明确风险承担方式。
本程序仅用于安全研究、原理分析与防护能力建设。请勿将其用于任何未授权的攻击、欺诈或其他违法场景;下载与使用前,请自行确认符合所在地法律法规及目标平台的服务条款,风险自负。