逆向某在线教育平台AES-ECB加密m3u8 key的完整流程与Python复现

📅 2026/7/15 10:54:49
逆向某在线教育平台AES-ECB加密m3u8 key的完整流程与Python复现
1. 逆向某在线教育平台AES-ECB加密m3u8 key的完整流程最近在研究某在线教育平台的视频流加密机制时发现其采用了AES-ECB模式对m3u8的key进行加密。这种加密方式在保护视频内容的同时也给开发者带来了不小的挑战。下面我将详细分享逆向分析的完整流程。首先我们需要明确几个关键点m3u8是一种基于HTTP Live StreamingHLS协议的播放列表格式而key则是用于解密视频片段的关键。在该平台中key并非明文传输而是经过AES-ECB加密处理。1.1 定位加密key的网络请求打开目标视频页面后使用浏览器开发者工具F12查看网络请求。经过筛选可以找到一个返回encryptedVideoKey的请求。这个响应值看起来像是一串十六进制字符串很可能就是加密后的key。在实际操作中我发现这个请求通常会在视频开始播放时触发响应内容除了加密的key外还包含videoKeyId和playerId等字段。这些字段可能在后续的解密过程中会用到。1.2 分析JavaScript解密逻辑接下来需要在前端JavaScript代码中寻找解密逻辑。这里有个小技巧直接在开发者工具的Sources面板中搜索关键词decrypt。不过这样可能会得到大量结果效率不高。根据我的经验更有效的方法是搜索prototype.decrypt。这是因为AES解密通常会以类的原型方法形式实现。果然在搜索结果中发现了ModeOfOperationECB.prototype.decrypt方法这很可能就是我们要找的解密函数。为了验证这一点我在该方法内部设置断点然后刷新页面重新播放视频。当断点触发时观察调用堆栈和局部变量可以清楚地看到解密过程的输入输出。2. 解密算法的详细分析2.1 解密流程拆解通过调试分析我整理出了完整的解密流程从网络响应中获取encryptedVideoKey使用固定字符串72Fhskjglp8qjpqx作为密钥将十六进制格式的encryptedVideoKey转换为字节数组使用AES-ECB模式进行解密将解密后的字节数组转换为可用的key特别需要注意的是这里的密钥是硬编码在前端代码中的。虽然这种做法不够安全但在很多在线教育平台中却很常见。2.2 关键代码解析让我们看看JavaScript中的核心解密代码var _encryptedVideoKey _response.encryptedVideoKey; var _key _aes2[default].utils.utf8.toBytes(72Fhskjglp8qjpqx); var _aesEcb new _aes2[default].ModeOfOperation.ecb(_key); var _bbb []; for (var i 0; i _encryptedVideoKey.length; i 2) { _bbb.push(parseInt(_encryptedVideoKey[i] _encryptedVideoKey[i 1], 16)); } var _decryptedBytes _aesEcb.decrypt(_bbb); var _decryptedText _aes2[default].utils.utf8.fromBytes(_decryptedBytes);这段代码清晰地展示了从加密key到解密key的完整过程。其中最关键的是ModeOfOperationECB类的实现它负责实际的解密操作。3. Python复现解密算法3.1 实现AES-ECB解密为了在Python中复现这个解密过程我们需要先安装必要的库pip install pycryptodome然后实现解密函数from Crypto.Cipher import AES from Crypto.Util.Padding import unpad def decrypt_m3u8_key(encrypted_key_hex): # 将十六进制字符串转换为字节数组 encrypted_bytes bytes.fromhex(encrypted_key_hex) # 硬编码的密钥 key b72Fhskjglp8qjpqx # 创建AES-ECB解密器 cipher AES.new(key, AES.MODE_ECB) # 执行解密 decrypted cipher.decrypt(encrypted_bytes) # 移除可能的填充 decrypted unpad(decrypted, AES.block_size) return decrypted.hex()3.2 完整示例代码下面是一个完整的Python脚本包含从获取加密key到最终解密的全部流程import requests from Crypto.Cipher import AES from Crypto.Util.Padding import unpad def get_encrypted_key(video_url): # 模拟浏览器请求获取加密key headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } response requests.get(video_url, headersheaders).json() return response[encryptedVideoKey] def decrypt_m3u8_key(encrypted_key_hex): # 将十六进制字符串转换为字节数组 encrypted_bytes bytes.fromhex(encrypted_key_hex) # 硬编码的密钥 key b72Fhskjglp8qjpqx # 创建AES-ECB解密器 cipher AES.new(key, AES.MODE_ECB) # 执行解密 decrypted cipher.decrypt(encrypted_bytes) # 移除可能的填充 try: decrypted unpad(decrypted, AES.block_size) except ValueError: # 如果没有填充直接使用 pass return decrypted.hex() # 使用示例 if __name__ __main__: video_url https://example.com/api/video/123 # 替换为实际视频API地址 encrypted_key get_encrypted_key(video_url) print(f加密key: {encrypted_key}) decrypted_key decrypt_m3u8_key(encrypted_key) print(f解密key: {decrypted_key})3.3 验证解密结果为了确保我们的Python实现正确可以使用以下方法验证从浏览器开发者工具中记录一个真实的encryptedVideoKey和解密后的key用我们的Python脚本解密相同的encryptedVideoKey比较两者结果是否一致例如当encryptedVideoKey为848e11b61279fd861d0b7d4805906ce4时解密后的key应该是716c435948704e73584146706654337a。4. 实际应用与注意事项4.1 批量下载加密视频有了解密key后我们可以配合N_m3u8DL等工具批量下载加密视频。具体步骤包括获取视频的m3u8播放列表提取其中的加密key URI使用我们的解密算法获取真实key将key提供给下载工具4.2 可能遇到的问题与解决方案在实际应用中可能会遇到以下问题密钥变更平台可能会定期更换硬编码的密钥。解决方案是定期检查JavaScript代码是否有更新。请求验证某些平台会对视频API请求进行签名验证。这时需要分析前端代码复现签名算法。反爬机制频繁请求可能会触发反爬。合理的做法是控制请求频率或者使用代理IP。4.3 法律与道德考量需要特别强调的是这种技术只应用于合法授权的场景比如自己购买的课程备份获得内容所有者明确授权的下载安全研究和学习目的未经授权下载受版权保护的内容是违法行为。技术本身是中性的关键在于如何使用。