本帖最后由 ling02123 于 2023-2-23 14:47 编辑
demo 'aHR0cHM6Ly9zdHVkZW50LWFwaS5peWluY2Fpc2hpamlhby5jb20vZXAvcGMvbG9naW4='
1. m3u8包分析
还是经典的 m3u8文件格式,对比上个版本没有太大出入,key_url 一样没有用上。既然没有抓到key链接,直接转去分析ts 解密逻辑。
2. ts 包分析随便断住一个ts 包,跟进解密函数。
如图
参数说明 : j : ts 字节流 q : 30 位数组 $ : 16位数组毫无疑问这里就是解密操作了,接下重点分析 参数如何生成以及后续的解密操作。
准备工作:
如图 ,网页上浪浪已经提前把 console hook 了,我们需要在网页加载的时候保存一份console方便后续分析。
仔细观察这个解密函数,你会毫无头绪,往下拉来观察一下这个函数如何初始化,发现是一个类似于JSVMP的东西,先传入大个很长的字符串还有一些乱七八糟的东西。多次调试发现里面的明文很少很少,挑出几个有明文的地方插桩分析。
例如这个地方的 oe.apply() 其实是函数调用,能看到一些明文,可以在这里下断,可以多下几个日志断点,信息越多越容易分析。
OK,日志嘎嘎输出。第一步:开局我们拿到了一个30位的数组,在第一步的时候他把数组拿到了。然后进行了一下 fromCharCode() 经过尝试 '1-yuYeqlPlHMU85XD+UOdM+QHmG8/P' 字符串就是30位数组 ,顺便一提 yuYeqlPlHMU85XD+UOdM+QHmG8/P 是由 'play_licenses' 接口返回
数组如下,下面还会一直分析数组:[49, 45, 121, 117, 89, 101, 113, 108, 80, 108, 72, 77, 85, 56, 53, 88, 68, 43, 85, 79, 100, 77, 43, 81, 72, 109, 71, 56, 47, 80]
第二 三步:关键词test,那必须是正则的test,可以看到他把一开始加上的 '1-' 去掉了,变成 'yuYeqlPlHMU85XD+UOdM+QHmG8/P' 就是接口直接返回的明文
很显然 他直接 atob 这个明文,atob 就是浏览器原生的base64解密函数。base64解密完的就是下面第二步的字符串。'Êæ\x1EªSå\x1CÅ<åpþPçLù\x01æ\x1BÏÏ'这个样子很奇怪,把它弄成 Uint8Array 试试。[202, 230, 30, 170, 83, 229, 28, 197, 60, 229, 112, 254, 80, 231, 76, 249, 1, 230, 27, 207, 207] len:21
这里他又把21位变成了18位的数组 ,嗨哟你干嘛真的是,对比一下18位跟21位的区别[230, 30, 170, 83, 229, 28, 197, 60, 229, 112, 254, 80, 231, 76, 249, 1, 230, 27] len:18发现他把前面一个和最后俩个分割掉了。
[230, 30, 170, 83, 229, 28, 197, 60, 229, 112, 254, 80, 231, 76, 249, 1, 230, 27] <- 18位数组从18位数组钟取出第一位,然后神秘数字 250 出现了 跟230干了一些事情,然后28出现了;28跟多次出现的21干了点事情,49就出现了;然后 String.fromCharCode(49) 就变成了 '1'; okok,我按照这个分析一波,大胆推测一下 250 ^ 230 = 28 28 + 21 = 49230 -> '1'同理 能得到第二个神秘数字就是 85
[230, 30, 170, 83, 229, 28, 197, 60, 229, 112, 254, 80, 231, 76, 249, 1, 230, 27] <- 18位数组图5 为 处理数组第7位的流程。第一步神秘数字变成了299,你会发现卧槽,原来神秘数字竟在我身边 ,299 是 197 在数组的前俩位。okok,上面分析的 229 ^ 197 = 32 依旧成立,但 32 + 21 != 55你干嘛~,后面咋对不上了很明显 32 + 21 + 2 = 55接下来分析一下这个 '2' 怎么来
我们可以根据图5分析中前面正确的步骤解密出来的值跟最后浏览器生成的值对比得出中间差值我们按照思路重新分析一下:[230, 30, 170, 83, 229, 28, 197, 60, 229, 112, 254, 80, 231, 76, 249, 1, 230, 27] <- 18位数组先把18位填充两位神秘数字成[250,85,230, 30, 170, 83, 229, 28, 197, 60, 229, 112, 254, 80, 231, 76, 249, 1, 230, 27] <- 20位然后[Python] 纯文本查看 复制代码 qq = [250,85,230, 30, 170, 83, 229, 28, 197, 60, 229, 112, 254, 80, 231, 76, 249, 1, 230, 27]
pp = []
for index,i in enumerate(qq):
if index>=2:
a = (qq[index - 2] ^ i) +21
pp.append(a)
print(pp) #此时的18位数组 [49, 96, 97, 98, 100, 100, 53, 53, 53, 97, 48, 53, 46, 49, 51, 98, 52, 47] <- 此时的18位数组[49, 97, 98, 100, 101, 102, 55, 56, 54, 99, 50, 56, 48, 52, 54, 102, 53, 27] <- 浏览器生成最后的18位
[97, 98, 100, 101, 102, 55, 56, 54, 99, 50, 56, 48, 52, 54, 102, 53] <- AES解密16位数组 abdef786c28046f5 <- 16位数组String.fromCharCode()成的字符串你会发现它把18位数组最后还原成了16位。其实是还原后再次分割了。把前面一位和后面一位分割掉了。
所以说有用的只有中间的 16 位对比中间16 位可以得到 中间的 差值 [1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1]对这些数字敏感 可以发现:
[Python] 纯文本查看 复制代码 str(bin(index)).count('1')
可以生成这些数字。分析到现在,完整算法意境分析完了,经过多次测试这个算法能解密其他play_licenses,这次分析也算成功了。
还原算法后也和网页一样能正常解密视频。 这次浪浪更新的难度适中,很适合分析,过程很详细,也可以动手分析一下,细节也讲解到位了,把各个分析部分组装一下就能用。 |