ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

XHR Hook如何伪造APP端取流:Bilibili-Old网络模拟实现全解析

XHR Hook如何伪造APP端取流:Bilibili-Old网络模拟实现全解析 XHR Hook如何伪造APP端取流Bilibili-Old网络模拟实现全解析【免费下载链接】Bilibili-Old恢复旧版Bilibili页面为了那些念旧的人。项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-OldBilibili-Old 是一款恢复 B 站旧版页面的开源用户脚本与浏览器扩展其最硬核的能力之一就是通过网络模拟Network Mock技术让网页播放器以APP/TV 端身份请求视频流从而解锁更高画质的视频源。本文将带新手读者彻底看懂XHR Hook 拦截机制如何工作、网络模拟在哪里生效、以及浏览器扩展版如何用声明式规则实现同样的伪装效果。为什么需要伪造APP端取流要理解网络模拟先要明白 B 站播放器的取流过程播放器先请求/playurl接口拿到一段视频流地址通常是.m4s或.flv结尾随后用XMLHttpRequestXHR发起真实的流媒体请求下载音视频数据。而服务端会对第 2 步的请求做身份校验User-Agent、referer、origin等请求头必须匹配。网页端默认的身份只能拿到网页源若想拿到TV/APP 源更高画质、无水印请求头就必须长得像官方客户端。项目默认使用的就是 TV 端身份标志见 userstatus.tsUser-Agent: Bilibili Freedoooooom/MarkII同时TV/APP 源要求referer必须为空——网页端天然携带referer直接请求必然 403。网络模拟要解决的就是把网页发的请求改成客户端发的请求。网络模拟的总入口networkMock() ⚙️核心逻辑集中在 network-mock.ts 的networkMock()函数中它根据运行环境走两条完全不同的路线运行环境伪造手段本质用户脚本TampermonkeyxhrHook.ultraGM.xmlHttpRequestJS 层劫持页面 XHR重新发起带 APP 请求头的跨域请求浏览器扩展Manifest V3GM.modifyRequestheader declarativeNetRequest 规则声明式网络规则在网络层直接改写请求/响应头两条路线殊途同归让最终的.m4s/.flv请求带上 APP 端 User-Agent、去掉referer并让响应通过跨域校验。XHR Hook网页请求拦截的基石 用户脚本路线依赖自研的 XHR 拦截工具 hook/xhr.ts。它的原理非常巧妙劫持入口覆写XMLHttpRequest.prototype.open。浏览器里所有 XHR 都必须先调用open(method, url, ...)这是天经地义的必经之路规则表匹配所有注册的拦截规则存放在rules数组中每次open被调用时遍历规则、检查 URL 是否同时包含所有匹配关键词命中则执行回调三级拦截能力由浅入深xhrHook(url, modifyOpen, modifyResponse)修改请求参数或改写响应内容适合接口换数据xhrHook.async(url, condition, modifyResponse)阻断真实请求由脚本异步取到数据后伪造readyState、load、loadend等事件喂回 XHR 实例还能周期性派发progress事件模拟加载进度让上层代码完全察觉不到异常xhrHook.ultra(url, modify)完全接管XHR 实例——你可以随意重定义它的任何属性和方法。网络模拟用的正是这个终极形态。此外拦截默认是一次性的once true命中即注销避免长期挂全局钩子带来的性能开销这个细节在 xhrHook 的源码注释 中有明确说明。ultra 接管一步步伪造取流请求 networkMock() 的取流劫持流程 可以分为四步① 精准定位目标请求只对 URL 中包含.m4s的 XHR 动手——这正是 dash 播放器拉取音视频流的路径其他接口一律不碰。② 用影子对象重定义整个 XHR 实例通过Object.defineProperties把原 XHR 实例的send、setRequestHeader、onload、onprogress、onerror、responseType、timeout等属性全部替换成 getter/setter 代理。所有属性读写都被透明转发到一个内部对象obj——它正是GM.xmlHttpRequest所需的标准参数结构。③ 换头重发被替换的send方法不再走浏览器原生网络栈而是调用脚本环境提供的跨域请求接口GM.xmlHttpRequest(obj)重新发起请求并注入 APP 端 User-Agent见 headers 设置。原实例的abort也被绑定到代理请求上取消行为保持一致。④ 把响应写回原实例defineRes()源码是关键收尾动作它把代理请求返回的status、statusText、response、responseText、responseURL等属性逐一defineProperty回原始 XHR 对象然后才触发播放器注册的onload回调。最终效果是播放器代码以为自己在正常地收流实际上数据来自一次换了身份的请求。onprogress回调里还会重建ProgressEvent源码保证播放器的加载进度条、缓存显示等行为完全正常。扩展版路线不改 JS只改网络 浏览器扩展版没有 Tampermonkey 的跨域 XHR 特权改用了更底层的方案declarativeNetRequest 声明式网络规则在请求真正发出前于网络层改头。规则由GM.modifyRequestheaderchrome/utils/gm.ts动态注入与静态规则文件 network-mock.json 的结构完全对应。以.m4s规则为例{ action: { type: modifyHeaders, requestHeaders: [ { header: user-agent, operation: set, value: Bilibili Freedoooooom/MarkII }, { header: referer, operation: remove }, { header: origin, operation: remove } ], responseHeaders: [ { header: Access-Control-Allow-Origin, operation: set, value: * } ] }, condition: { urlFilter: .m4s?, resourceTypes: [xmlhttprequest] } }三个细节值得注意只拦 XHRresourceTypes限定为xmlhttprequest不影响video标签直接播放等其他资源类型改写请求头设置 APP User-Agent、删除referer和origin与用户脚本路线完全等价补上跨域放行响应头注入Access-Control-Allow-Origin: *和Access-Control-Expose-Headers否则跨域响应头拿不到播放器仍会报错。网络模拟在哪里被触发networkMock()采用首次调用生效、永久驻留的策略networkMocked标志位主要由两个场景触发区域限制视频代理videolimit.ts 处理泰区/港澳台限制视频时先通过networkMock()确保取流通道可用再走代理接口拿到access_key参数换取高画质流地址东南亚泰区番剧bangumi.ts 的 initGlobal() 在尝试东南亚接口前同样会启用网络模拟。也就是说当你打开一部受限制的番剧、脚本成功解锁 APP 源的那一刻这套 XHR Hook 声明式规则的伪装系统就已经在后台默默工作了。总结一次身份伪装的工程教科书 回顾 Bilibili-Old 的网络模拟实现它给出了网页端伪装客户端取流的两种标准解法脚本环境xhrHook.ultra全面接管 XHR 实例 →GM.xmlHttpRequest带 APP 身份重发 →defineRes把响应无缝写回播放器全程无感知扩展环境declarativeNetRequest 规则在网络层改写请求头、补跨域响应头一行 JS 都不用改。这套设计对任何想在网页里越级获取资源的项目都有很强的参考价值先劫持必经之路open/send再透明重写行为最后保证事件序列与原生完全一致——伪装的最高境界就是让对方系统完全看不出来。项目源码均为 TypeScript 编写相关核心文件网络模拟 network-mock.ts、XHR 拦截器 xhr.ts、扩展网络规则 network-mock.json欢迎深入阅读。【免费下载链接】Bilibili-Old恢复旧版Bilibili页面为了那些念旧的人。项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Old创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表