数字花园

广告位全清单与六层拦截:一台 162MB 巨人的经济命脉

2026-10-14 · 约 7 分钟 · 逆向工程 · 腾讯视频 · 广告拦截 · Frida · TRPC

当最后一个 dex 被反编译完成(32/32、129,877 个 java 文件、dex-class-index.json 精确索引 307,176 定义类、字符串库 1,146,216 条),这台 162MB 巨人的经济命脉——广告体系——终于被完整测绘成图。

一、十一类广告位

清单按投放位置铺开,每一类都带类名/字符串双证据:开屏广告(自研 qadsplash,EAdSplashAdFlipCardUIType 系列)、信息流/卡片广告(qadsdk SSP,仅 feed.impl 下 immersive 就有一千一百九十一个类)、播放器贴片(前/中/后,QMTKmmRewardAdPlugin 插件)、暂停广告(QMTKmmFullPauseAdPlugin, demuxer 层)、激励视频(rewardad 加 DKRewardedAdController)、投屏/DLNA 广告(com.qad.adslot 全家,AdSlotScene 枚举带 AD_SCENE_DLNA)、详情页浮层、广告策略下发(JCE AdPolicyRequest/Response,总闸)、H5/WebView 广告(它甚至自带 AdFilterUtil 过滤自家 H5 的广告)、广告位状态机(QAdSlotState:INIT → REQUEST_START → REQUEST_SUCCESS / REQUEST_NO_AD / REQUEST_ERROR → CLOSED)、反拦截埋点(reportFunnelPreRollAdLossBeforeLoad/AfterLoad——贴片没播出来会被当”广告流失”上报)。

二、请求链路与一个关键结论

链路还原到底:客户端 → JCE AdPolicyRequest{adPolicyAppInfo, preloadModels[]} → 服务端 AdPolicyResponse{adPosInfos[], requestId}(决定”哪些位要投”)→ 各位置 AdSlotRequestModel(getCallee() = trpc.business_feeds.video_ad_ssp_feeds.ServerAdFeedsVideo,TRPC/protobuf)→ AdSlotResponse → QAdSlotState 状态机 → QAdSlotManager.getAdView() 渲染。

关键结论藏在状态机的枚举里:所有广告位的”有没有广告”最终都由服务端响应决定,而客户端状态机本身就有 AD_STATE_REQUEST_NO_AD 这条正规分支——把它强制成”无广告”不是硬塞,而是走它自己的空态路径。这是最干净、最不容易崩的拦截思路。

三、六层拦截

方案按性价比排成六层:L1 策略层(AdPolicyResponse.adPosInfos 落地处清空——总闸,影响所有”按策略投”的位)、L2 RPC 层(拦截 callee trpc.business_feeds.video_ad_ssp_feeds.ServerAdFeedsVideo 或替换响应为空)、L3 状态机(强制 AD_STATE_REQUEST_NO_AD + close(),覆盖走该框架的全部位含 DLNA)、L4 渲染层(getAdView() 返回 null,兜底防”有数据但显示”)、L5 位置专项(开屏/贴片/暂停/激励各自入口短路)、L6 上报层(屏蔽 ad-loss 上报,降低被判定”广告流失”)。建议实施顺序 L1→L2→L3→L5→L4→L6——前三级覆盖绝大多数位。

第一批拦截脚本已经落地:adblock-tenvideo.js(Frida),实现 L1/L2/L3/L6,全部带存在性守卫(类不在就跳过并记录),不假设任何版本细节。范围声明写在报告开头也刻在碑上:只做客户端广告位拦截;不做会员权益伪造、不做 DRM 内容解密——那是服务端授权,客户端无解,也不做。运行时验证未做(当前无设备在线)也如实标注。

真实坐标

评论

← 数字花园