用 RP2350 从零搭建一个 DRM 系统

读完本文,你将获得: 理解 DRM 系统的四个核心问题:内容加密、设备绑定、授权下发、密钥保护 看到一个完整的、可运行的硬件 DRM 原型:从内容打包到设备授权到加密播放 理解基于 HMAC-SHA256 的密钥层级设计,以及为什么每个公式是这样的 对照 Widevine L1/L2/L3,理解「密钥是否离开芯片」这件事的实际含义 亲手对自己造的 DRM 运行 8 条攻击,看到每一条防御挡住了什么、挡不住什么 获得一张从教学原型到商业级 DRM 的加固路线图,以及与 Widevine/PlayReady 的差距对比 阅读路线: 目标 推荐章节 可以先跳过 建立 DRM 全局直觉 一~三 具体命令和代码 复现实验 四~五 加固路线和商业对比 做安全评估 六~八 密码学公式细节 评估与商业 DRM 差距 八~九 复现步骤 研究边界:本文的所有实验仅针对自有音频内容和自有硬件设备。不涉及任何商业 DRM 系统的绕过或密钥提取。代码中的根密钥是故意写死的教学值 —— 不要拿这套代码保护任何真实内容。 实验环境 项目 规格 板子 Raspberry Pi Pico 2W(RP2350A,Cortex-M33 双核 @150MHz,520KB SRAM,4MB Flash) 上位机 MacBook Pro M1,macOS Sonoma SDK pico-sdk 2.1.0 + pico-extras(cyw43 WiFi/BLE) 工具链 arm-none-eabi-gcc 13.2.1 Python 3.12 + pyserial(串口通信) 调试 picotool 2.1.0(烧录 / info / reboot) 源码文件 labs/14_drm_dongle/ ├── CMakeLists.txt └── src/ ├── main.c 固件:USB CDC 协议状态机 + licence 校验 + 会话管理 + 分块 keystream └── drm_crypto.c/h HMAC-SHA256(手写 ipad/opad,SHA-256 走 RP2350 硬件加速器) tools/drm/ ├── drm_common.py 协议与密码学的"唯一真相"(与固件逐字对齐) ├── pack_audio.py 内容方:加密 WAV + 生成 manifest + 签发 licence ├── dongle_sim.py 虚拟 dongle(纯 Python,不需要板子也能跑全流程) ├── player.py 播放器:向 dongle 要密钥 → 解密 → 校验 → 播放 ├── attack.py 8 条攻击的自动化实验台 └── parity_check.py 固件与上位机协议一致性自检 一、为什么要自己造一个 DRM Widevine、PlayReady、FairPlay —— 商业 DRM 系统的架构文档可以读上万页,但它们的代码是闭源的,协议是加密的,密钥管理深藏在 TEE 和安全芯片里。站在外面看,你能看到协议握手的流程图;站在里面看,你还是不知道一条 licence 被篡改时到底哪一步会拒绝它、拒绝的原因是什么。 ...

September 30, 2026 · 12 min · 2462 words · +5

把 classes.dex 藏起来就安全了?主流加固方案的真实防线

读完本文,你将获得: 分清 R8、代码混淆、DEX 加壳、函数抽取、DEX2C、VMP、SO 保护与 RASP 到底解决什么问题 看懂一个加固 APK 从 CI 构建、后处理、对齐、重签名,到壳启动、完整性校验和业务代码加载的完整链路 了解 360、阿里 mPaaS、爱加密、梆梆、腾讯乐固,以及 DexGuard、Promon、Appdome、AppSealing、Google Play 方案的公开能力与证据边界 理解为什么加固必须与 APK 签名、Play Integrity、设备注册、账号图谱和服务端风控组合,而不能独自承担“客户端可信” 获得一套可执行的 release 参数、性能基线、兼容性矩阵和加固验收方法 〇、摘要:壳不是保险柜,它是一套成本控制系统 Android APK 对逆向工程天然友好。 classes.dex 不是源码,却保留了大量类、方法、调用和数据流语义;resources.arsc、Manifest、Assets、字符串和 native SO 又把接口、功能开关、协议常量、JNI 边界与第三方 SDK 关系一并交给了终端用户。一个正常用户看到的是登录、支付和播放页面,分析者拿到的却是一份可以离线拆解、反复运行和任意修改的程序副本。 APK 加固由此产生。它要处理的不是一个问题,而是四类问题: 代码理解。 降低 Java/Kotlin、C/C++、Flutter、Unity 或脚本逻辑被快速恢复和复用的概率。 运行时观测。 增加调试、Hook、注入、内存读取和自动化批量控制的成本。 篡改与重打包。 发现签名、代码、资源、调用顺序或运行环境发生了不符合预期的变化。 业务滥用。 把客户端风险信号传给服务端,让登录、领券、支付、游戏结算、内容授权等动作得到分级处置。 但有一条物理事实绕不过去:代码要在用户控制的设备上执行,处理器最终就必须获得明文指令、解码后的类,或与原算法等价的 VM 语义。 加固可以缩短稳定观测窗口、打散结构、改变执行形态、提高自动化规模成本,却无法把白盒客户端变成服务端 HSM。 所以本文的主线不是“哪家的壳最硬”,而是: 1 2 资产分级 -> 构建期变换 -> 包与运行时保护 -> 平台可信证明 -> 设备/安装身份连续 -> 绑定业务动作 -> 风险处置与反馈 这条链也把前两篇文章接了起来:Chrome VMP讨论如何让关键语义难以稳定观测,设备指纹与设备注册讨论如何把端上证据放进服务端身份和业务图谱。APK 加固位于两者之间:它保护”客户端如何执行”,但不能独立回答”服务端为什么应该相信这次请求”。 ...

August 25, 2026 · 9 min · 1723 words · +5

一个 Canvas 当然认不出你:海内外主流 Web / Android 设备指纹与风控体系全景

〇、研究证据与方法声明 本文是一篇横向综述,不是单一目标的逆向工程报告。核心方法是文献综述 + 公开材料交叉验证 + 版本样本观察,辅以少量一手逆向实验作为交叉校准。以下声明帮助读者判断每条结论的可信度和适用边界。 方法论 项目 说明 研究方法 文献综述 + 逆向验证 + 横向对比 覆盖范围 8 个国内平台(抖音/字节系、快手、淘宝、蚂蚁/支付宝、夸克、拼多多、美团、小红书)+ 7 类海外产品(Fingerprint、Cloudflare、Arkose、Stripe Radar、Sift、ThreatMetrix、Play Integrity)+ Netflix MSL 协议专题,共计 16+ 平台/产品 技术维度 5 大方案类别(第一方状态、概率指纹、完整性证明、网络与行为检测、业务图谱)x 7 个工程环节(采集、封装、校验、归一化、召回、匹配、图关联) 证据分级 A(官方公开文档与平台规范)/ B(架构映射与开源代码分析)/ C(版本化逆向样本与社区观察)– 详见 §1.4 证据来源统计 等级 来源数 典型代表 A:公开确认 ~50 Android 官方文档(标识符最佳实践、Play Integrity、Key Attestation)、W3C 指纹缓解规范、各平台隐私政策(淘宝/拼多多/美团/小红书/夸克/快手)、厂商产品文档(阿里云设备风控、Fingerprint API、Cloudflare Bot Management、Stripe Radar、Sift、Arkose)、火山引擎 DataFinder、Netflix MSL 开源规范 B:架构映射 ~10 学术论文(Laperdrix 浏览器指纹综述、Eckersley Panopticlick、Vastel FP-STALKER)、开源项目代码分析(FingerprintJS、CreepJS、RiskEngine、TrustDevice)、顶象算法公开说明、GeaFlow 流式图计算 C:外部观察 ~7 看雪社区版本样本(淘系 SecurityGuard、美团 mtgsig、拼多多 libpdd_secure)、仓库内抖音 v37.5 MetaSec 实验记录、仓库内 Netflix MSL 协议逆向日志 范围限制 本文的"留白"是刻意的设计选择,以下是主要已知限制: ...

August 25, 2026 · 16 min · 3217 words · +5

一段 UTF-16 XML 凭什么管住 4K?PlayReady 的套娃式架构

读完本文,你将获得: 分清 cenc:pssh、mspr:pro、PRO、PRH、WRMHEADER 和 License,避免把六个对象叫成同一个“DRM 数据” 看懂 PlayReady 从 KID、内容密钥到客户端证书和许可证绑定的完整控制面 理解 SL150、SL2000、SL3000 的真实边界,以及为什么安全等级不等于分辨率等级 理解 AES-CTR/CBCS、密钥轮换、Root/Leaf License、Secure Stop 和输出保护分别解决什么问题 用 Shaka Packager、Bento4、GPAC、Shaka Player 和 dash.js 搭建只处理自有测试内容的分析环境 从攻击面而不是宣传页评估 PlayReady:哪些边界稳,哪些风险只是被推到了 TEE、OEM 和 License Server 〇、摘要:我最初把那段 Base64 当成了许可证 笔者第一次认真拆 PlayReady,是在 DASH MPD 里盯着这样一个节点: 1 2 3 4 <ContentProtection schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95"> <cenc:pssh>AAA...</cenc:pssh> </ContentProtection> 第一反应很自然:这一大段 Base64 应该就是 License,里面也许还藏着内容密钥。 解开第一层,得到一个 ISO BMFF pssh box;继续取出 Data,得到 PlayReady Object;按小端字段再拆一层,遇到 0x0001 记录;最后用 UTF-16LE 解码,才看见一段 WRMHEADER XML。里面有 KID、算法和 License URL,唯独没有内容密钥。 ...

August 24, 2026 · 12 min · 2451 words · +5

Cromite 源码在手,Widevine 还是过不了

读完本文,你将获得: 看清 Chrome/Chromium、Cromite/Bromite、EME、Widevine CDM 和平台 DRM 到底是谁管谁 按版本、补丁、GN 参数和 Ninja 目标复现 Cromite/Bromite 的构建过程 弄明白为什么 “official build” 与 “Chrome codecs” 都不等于 Widevine 跟着六次碰壁,看网络抓流、MSE 截获、UA 伪装和视频 remux 分别死在哪一层 从 MSL、License、设备能力、CENC、CDM 和安全输出六条链评估 Netflix 的防护 〇、摘要:这条路线死在了编译之前 事情的起点很简单。 Chrome 的 Widevine CDM 是一个黑盒,直接改 Chrome 又太重。Cromite 和 Bromite 恰好站在中间:它们是 Chromium 分叉,源码在手里,补丁在手里,GN 参数也在手里。笔者最初把路线排得很顺:编译浏览器 → 打开 proprietary codecs → 伪装 Chrome 能力 → 截获 Fetch/MSE 分片 → FFmpeg 合成视频。 每一步单独看都很合理,连起来却犯了一个致命错误:🧑‍🔬 笔者把”能改浏览器”误当成了”能控制 DRM 信任链”。 第一盆冷水来得比预想中快。还没等 Chromium 开始吃满 CPU,Cromite FAQ 里一句很短的回答就把路线从中间截断了:Does Cromite support DRM media? No. ...

August 23, 2026 · 12 min · 2524 words · +5

Chrome 里藏了个虚拟机,它到底在保护什么

读完本文,你将获得: 明确区分 Chrome 沙箱、V8 字节码、商业 VMProtect 壳与本文讨论的 VM-based Protection 理解 Chrome 原生媒体模块中 VMP 的核心目标:不是让代码不可执行,而是让关键语义不可稳定观测 掌握一套分析 VMP 保护的工程框架:入口边界、调度器、编码状态、完整性校验、明文输出边界 经历从"grep AES S-box"到"差分边界建模"的认知转变过程——以及中间踩过的每一个坑 看清 VMP 的真实安全边界:它能显著提高密钥提取成本,但无法让合法播放后的明文数据凭空消失 〇、摘要 本文讨论的 VMP 指 VM-based Protection / 虚拟机化保护,不是 Chrome 浏览器自身的沙箱机制,也不特指商业产品 VMProtect。它是一类代码保护方法:将原始算法提升为自定义字节码、解释器调度、编码状态和完整性校验的组合,使攻击者很难从静态反编译、内存扫描或常规断点中恢复关键语义。 Chrome 生态里,最适合观察这类保护的位置不是普通网页 JavaScript,而是高价值原生模块,例如桌面端 Widevine CDM 这类承载 DRM 密钥处理和媒体解密的组件。它们处在 Chrome 的 EME/Mojo/CDM 调用链上,既要在用户可控机器上运行,又要尽可能保护 license、content key、白盒表和解密状态。 本文的核心结论是: VMP 的核心不是“藏代码”,而是“抹除可观测性”:标准 AES 表、key schedule、硬件 AES 指令、稳定函数边界都会被替换成 VM 调度、动态表、编码状态和热路径变换。 Chrome 场景下的 VMP 是多边界协同:浏览器进程模型、Mojo IPC、CDM utility 进程、沙箱、完整性校验和白盒数据路径共同构成防护面。 密钥保护和明文保护不是一回事:VMP 可以让 content key 难以提取,但合法播放路径最终仍会产生解码后的明文帧,这是 DRM 工程无法回避的语义边界。 正确的分析方法不是一上来硬反 VM:更有效的路线是先刻画输入/输出边界,再用 perf、堆快照、IPC 观察、完整性安全的断点和差分实验定位“语义转移点”。 换句话说,现代 VMP 的价值在于把攻击者从”搜一个表、hook 一个函数、dump 一个 key”的线性流程,拖入”恢复 VM 指令集、还原状态编码、绕过完整性校验、证明数据流语义”的系统工程。 ...

August 23, 2026 · 11 min · 2148 words · +5

有了 PSSH 还是拿不到 Key,从 L3 到 L1 有多远

读完本文,你将获得: 分清 MPD、PSSH、WidevinePsshData、KID、CK 和 License,不再把一段 Base64 当成内容密钥 看懂 moov/trak/stsd/sinf/tenc 与 moof/traf/saiz/saio/senc/mdat 的完整层级和引用关系 分清 CMAF Header、Segment、Fragment 与 Chunk,理解低延迟发布、ABR 切换和 CENC 元数据如何落到同一条时间轴 看懂客户端为什么不能直接访问 Widevine License Service,以及合作方 License Proxy 真正承担什么职责 对照 Chrome 与 Android 双泳道通信图,理解 EME/Mojo/CDM 与 MediaDrm/AIDL HAL/OEMCrypto 两条接入路径 严格区分 Widevine L1/L2/L3、Android 五级安全枚举、分辨率授权和 HDCP 输出策略 理解 Provisioning、设备身份、License 个性化、续租、离线授权、密钥轮换和撤销之间的关系 对照十类主流 OTT 应用,理解 Widevine 在订阅、租购、离线、直播和 UHD 场景中到底负责哪一段 用固定版本 Shaka Packager 对自有媒体做 CENC 实验,并用 Bento4、GPAC 与 PSSH parser 交叉检查结果 从攻击面而不是产品宣传评估 Widevine:L1 把风险压到了哪里,License Server 又可能怎样把整条链主动放空 阅读路线不必从头走到尾: ...

August 22, 2026 · 27 min · 5667 words · +5

把 Netflix MSL 拆成字节 - 一次协议逆向的路线、踩坑与经验

读完本文,你将获得: 一个常被忽略的问题的答案:既然已经有 HTTPS,Netflix 为什么还要在里面再套一层自研的 MSL 加密信道? MSL 消息的字节级结构:header envelope、encrypted envelope、payload chunk 三层是怎么嵌套的,encrypt-then-MAC 到底对哪段 bytes 签名 CBOR integer key 编码的真实字节,以及为什么 bytes 写成 text、headerdata 内联成 map 会让服务端直接 502 一套不依赖“协议很复杂所以安全”的评估框架:MSL 能保护什么、哪些属性取决于部署配置,以及攻击者会转向哪些边界 〇、摘要 本文记录笔者对 Netflix Message Security Layer (MSL) 的一次协议逆向。 和前几篇 Widevine / FairPlay 文章不同,这次的目标不是攻破某个白盒 AES,而是把一个真实商业客户端的应用层加密协议,拆成能对着字节解释、能复现、能被服务端接受或拒绝的结构。产出是两个最小实现: nfmsl.py:单文件 Python 研究客户端,每一层中间结构都能打印,用来做字段 diff 和错误二分; Android MslClient:用真机 MediaDrm / CryptoSession 复现 Android 侧的 MSL 加密签名链路。 真正的突破点不是拿到某个密钥,而是把下面这些东西对齐到服务端能接受的 wire format: MSL 消息的三层信封结构,以及 encrypt-then-MAC 中「签名签的是密文而非明文」这一点; CBOR integer key 编码里 bytes/text、内联 map/加密 envelope 的字节差异; MasterToken 与 UserIdToken 通过 mtserialnumber 建立的字段级绑定; ASYMMETRIC_WRAPPED 与 WIDEVINE 两类 Key Exchange 的密钥归属差异; licensedManifest 把 Manifest 与 Widevine license challenge 合并进同一个 payload 的结构。 本文同时区分三个容易混淆的对象:Netflix 开源 MSL 框架的能力、本文观测到的 Netflix 客户端协议实例、Netflix 当前生产环境的完整安全策略。前两者可以由公开文档和实验字节支持;第三者还包含服务端风控、密钥托管、撤销策略和设备分级,不能仅凭客户端逆向完整证明。 ...

August 15, 2026 · 18 min · 3744 words · +5

当 Hook 失效的那一刻:SVC 指令级系统调用保护的攻防

读完本文,你将获得: 理解 ARM64 SVC 指令如何绕过所有 libc 层 hook,以及为什么 Frida 的 Interceptor.attach 对它束手无策 掌握 SVC 在 Android 安全对抗中的五种核心用法:反 ptrace、反 Frida、完整性校验、线程检测、seccomp-BPF 获得一套从"进程莫名崩溃"到"定位 SVC 指令并绕过"的完整排查方法论 对比六种绕过方案(Frida Stalker / seccomp / 内核模块 / eBPF / binary patch / 仿真)的工程权衡 〇、摘要 本文系统分析了 Android 应用中基于 SVC(Supervisor Call)指令的内联系统调用保护技术。笔者在对多个商业级加固方案的逆向分析中,反复遭遇 “hook 了 libc 但保护照样触发” 的困境,最终追溯到 SVC 这个 ARM 指令集的原子操作。 核心发现与贡献: 五种 SVC 对抗模式梳理:从实际样本中提炼出 anti-ptrace、anti-Frida(/proc/self/maps 扫描)、文件完整性校验、线程枚举检测、seccomp-BPF 五种典型用法 🧑‍🔬 六种绕过方案的工程对比:Frida Stalker、seccomp-BPF 拦截、内核模块、eBPF、binary patch、Unicorn 仿真,各有适用场景和代价 🧑‍🔬🔬 完整实战案例:从"Frida attach 就崩溃"到定位 3 处 SVC 指令并逐一绕过的全过程,包含 4 次失败尝试 🔬 SVC 保护的真实边界分析:SVC 不是银弹——它保护的是调用路径而非调用逻辑,一旦攻击者切换到内核视角,保护立即失效 🧑‍🔬 防御建议:从防御者角度给出 SVC 保护与 OLLVM/VMP/服务端验证组合的分层策略 🧑‍🔬 Research Evidence Environment Item Detail Device Pixel 7 (panther), rooted (Magisk 27.0) OS Android 14 (UP1A.231105.001) Target 某商业加固 SO(arm64-v8a, ~2.1 MB),具体应用脱敏处理 Architecture arm64-v8a (AArch64) IDA Pro 9.0 SP1 Ghidra 11.1.2 Frida 16.5.9 (server) + 16.5.2 (client) strace Android NDK r26d bundled seccomp tools libseccomp 2.5.5, seccomp-tools (Ruby gem) Kernel 5.15.148-android14 (custom build with ftrace enabled) Hypothesis H1: 应用检测到调试器是通过 libc 的 ptrace() 调用实现的,hook libc ptrace 即可绕过 H2: Frida attach 后崩溃是因为 /proc/self/maps 中出现了 frida-agent 的映射,应用通过 libc open/read 读取 H3: SVC 指令的 syscall number 硬编码在 .text 段中,可通过模式搜索 D4000001(SVC #0 编码)批量定位 H4: seccomp-BPF 可以拦截所有 SVC 调用,包括从 .text 段直接发出的内联调用 H5: binary patch 将 SVC 指令替换为 NOP 是最简单有效的绕过方式 Experiments ID 实验 验证假设 结果 关键证据 E01 hook libc ptrace 返回 0 H1 ✗ FAIL hook 生效但进程仍然检测到调试器并 exit E02 hook libc openat/read 过滤 maps 读取 H2 ✗ FAIL /proc/self/maps 从未出现在 hook 日志中,但进程仍然崩溃 E03 strace 观察实际 syscall H1, H2 ✓ PASS 发现 ptrace(PTRACE_TRACEME) 和 openat(/proc/self/maps) 直接出现在 strace 输出中,未经 libc E04 IDA 搜索 SVC #0 指令编码 H3 ✓ PASS .text 段找到 17 处 SVC #0(01 00 00 D4),其中 3 处与反调试直接相关 E05 seccomp-BPF 拦截 SVC ptrace H4 ✓ PASS seccomp filter 成功拦截 __NR_ptrace(117),进程不再崩溃 E06 NOP patch SVC 指令 H5 ⚠️ PARTIAL 反 ptrace 绕过成功,但 SO 完整性校验(也是 SVC 实现)检测到 patch 后 abort E07 Frida Stalker 动态替换 SVC 返回值 - ✓ PASS 成功绕过全部 3 处 SVC 保护,进程正常运行 一、路线总览 这一节给出整个分析的宏观路线图。如果你已经熟悉 SVC 的基本概念,可以直接跳到 §四 看实战。 ...

August 8, 2026 · 28 min · 5806 words · +5

拆开 anti-token 以后 - 拼多多历史样本中的环境记录与服务端盲区

〇、摘要 🧑‍🔬 笔者第一次整理拼多多 libpdd_secure.so 资料时,建了一张很长的字段表:系统属性、Build、网络、SIM、时间、随机量,一项项排得很整齐。表格越完整,文章看起来越像已经还原了”设备指纹”。 问题也恰好出在这里。看雪帖子描述的是特定历史样本中的环境记录、缓存和封装;拼多多隐私政策描述的是产品在安全场景下可能处理的数据类别。前者缺少服务端,后者不是抓包。把两份材料合起来仍然得不到稳定设备 ID,更得不到当前画像模型和交易阈值。 最后只保留那些经得住版本变化的观察:历史 Native 代码曾组织环境记录,记录经过结构化封装和保护后形成输出;部分内容有缓存,动态量会随调用变化。字段顺序、前缀、偏移、密钥和生成步骤则全部省略。研究目的不是做一个 anti-token 生成器,而是看清客户端包裹到达网络边界后,还缺哪些证明。 Research Evidence Methodology Item Detail 文章类型 Type B:官方政策与历史逆向材料复核 资料截止 2026-07-06;实质来源均早于 2026-07-23 发布日期 证据标记 A:官方公开;B:通用防守架构判断;C:第三方历史样本观察 一手实验 无;未下载附件、运行 APK/SO、生成 Token 或请求线上接口 公开边界 不提供密钥、IV、前缀、字段顺序、偏移、函数地址和请求模板 Sources & Evidence Grading 来源 等级 使用方式 拼多多隐私政策,2025-07-08 生效 A 安全用途、数据类别、IMEI 历史版本边界 libpdd_secure.so 指纹算法分析(下篇),2025-12-02 C 7.80 历史样本、作者对 7.85 的说明、记录与封装观察 anti-token 纯算法分析,2026-07-06 C Native 记录容器、缓存和动态记录的外部观察 Android 10 隐私变更与 Play Integrity 概览 A 标识符限制、请求绑定和分级处置的通用原则 Scope Limitations 没有可独立核验的 APK 渠道、完整版本、APK/SO SHA-256、ABI、设备构建号和抓取时间。 7.80 与 7.85 的接近程度来自原帖作者陈述,笔者没有做二进制差分。 2026 年帖子未在公开正文中给出可与 7.80/7.85 对齐的 App 版本,笔者不替它补版本号。 网络边界后的画像、图谱和处置流程均为 B 级职责模型,不代表拼多多内部实现。 负责任披露:这次材料复核用于安全评审与隐私核查,不建议把历史材料用于模拟客户端、批量请求、营销作弊或规避平台处置。 ...

July 23, 2026 · 2 min · 365 words · +5
CC BY-NC-SA 4.0 © 2026 +5 · Repost with attribution, non-commercial only
All research is for academic and security purposes only. No functional exploit code or keys provided. For takedown requests contact overkazaf@gmail.com.
本站总访问量 次  ·  访客数 人