吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 15033|回复: 175
收起左侧

[Web逆向] 某视频网站流媒体初次分析全过程

    [复制链接]
ligxi 发表于 2022-4-8 15:10
本帖最后由 我没有失眠啊i 于 2022-4-8 16:37 编辑

开篇

最近呢,学了一点js逆向的知识,一直想找个可以实践一下的平台来试试学习效果。偶然间看到了这个平台,发现很适合拿来练手,不过由于这个网站视频开始播放前都有那种不和谐的广告,所以地址就不能贴了,贴图也做了一些脱敏处理!

需要准备的工具:

  • 一些JavaScript基础知识,能大概看懂就行
  • 浏览器:Chrome浏览器、Edge浏览器等能方便进行调试的,这里我用的是Chrome浏览器
  • 抓包工具:Fiddler,用来替换和保存一些数据
  • 分析工具:Winhex,用来查看内容
  • 下载工具:IDM,用来测试内容是否可以正常下载
  • M3U8下载器:https://www.52pojie.cn/thread-1374045-1-1.html

第一次分析


打开目标网站首页,选择任意一个视频信息点击进入后:img

可以直接看到资源下载地址,不过这次目的是来逆向的,所以看不到!看不到!看不到!😎

1.1 过控制台检测

接下来就到了我们的分析时间,点击【在线播放】后尝试使用快捷键F12打开控制台,然后就弹出了以下提示:img

打不开控制台不要紧,选择浏览器右上角的三个小点,从更多工具中打开控制台:

img

1.2 过无限debug

控制台一打开,立马跳出个无限debuuger,看来还是做了一些反调试措施的:

img

从右边的堆栈中向下查找入口,从上到下依次点击看看:

img

很显然这个并不是,再往下点时,就发现了非常关键的函数调用:

img

其实这个无限debugger卡了挺长时间的,一开始开始尝试删除这个关键位置的调用,删除整个debugger的自调用函数,甚至删除整个外层的debugger函数,但是发现这些操作会导致视频无法正常加载,控制台过段时间就会直接卡死等莫名其妙的问题,说明这些函数中有些关键地方还是有用的,那看不懂这些混淆的代码又该怎么办呢?难道此次实战就此终结!!!

在前思来想去后,突然想到既然debugger关键字会触发断点,那要是我把这个关键字给改了是不是就停不下了?说干就干,把含有无限debugger的js文件在源代码中直接另存为或者从Fiddler另存为一份到本地,方便进行修改。
从上图可以看到前面的内容为“bugger”,后面的内容为“de”,要修改的关键就在这里里,以文本方式打开对应的js,直接搜“de”,发现有5个地方有这个信息:

img

全部替换,这里我替换成“dd”,替换后保存:

img

打开Fiddler工具,右边选择自动响应,勾选启用规则和请求传递,填写js网络地址和本地js地址,并保存:

img

确认Fiddler能获取浏览器请求后,打开浏览器里的设置,选择清空之前的数据,这样才会重新加载本地替换的js文件:

img

重新打开播放页面后,再次打开控制台,发现不仅无限debugger没了,控制台也正常了,视频也能正常加载了,很好!可以愉快的玩耍了。

1.3 寻找m3u8地址

img

打开网络面板,会发现很多的302请求,302表示重定向,这个请求会在响应中返回一个新的地址。开始查找视频文件地址,发现m3u8文件也被重定向了:

img

用IDM工具下载这个m3u8文件看看,可以看到返回的居然是一个张图片???😂

img

打开看看,额,居然是二维码,扫了一下返回是视频网址,那m3u8信息哪去了?

img

用winhex打开看看,看这个头信息好像就是一个图片img

查找一个关键内容看看,winhex直接搜m3u8:

img

发现并不是想要的内容,用winhex前后翻看发现基本都是乱码,那么极有可能m3u8的内容被加密了,存放在这个图片中。尝试在源代码中查找m3u8文件的调用堆栈发现事情并不简单,很多地方的js代码都被混淆了,所以要找到还原方法实属头大,可是没有代码就不能还原出m3u8的内容怎么办?于是想到加载ts文件不是也得从m3u8的内容中读取吗?所以开始尝试查找ts的调用堆栈,这里可以看到ts的请求也是302状态码,先不管:

img

把鼠标放在其中一个ts请求的启动器上,点击浮窗中展示的js文件进入调式:img

这里会自动跳转到源代码中js的点击位置,先在这里打上一个断点,免得调试过头了。

img从右下角的

堆栈从上往下依次点击看看,在每个堆栈位置前后翻翻,然后发现了一个有关m3u8的信息,在这里下断点:

img

F5重新加载页面,可以看到m3u8的内容此时已经被加载了:

img

尝试把这个m3u8信息保存下来,打开控制台输入了以下代码:

const data = t.data; // 这里填内容的字符串
const blob = new Blob([data], {type: "text/plain"});
const a= document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "demo.m3u8"; // 这里填保存的文件名
a.click();
URL.revokeObjectURL(a.href);
a.remove();

img

成功保存,打开看看,正好是m3u8的内容:

img

1.4 ts解密

尝试用IDM访问前面一两个ts链接看看有没有加密:

img

怎么返回的又是图片?直接打开看看:

img

啥呀这是,一张花屏的图片,用winhex打开看看:

img

上下拖动内容后发现并不是常规的图片内容,果然有猫腻,在图片的下面发现了视频相关的头信息,难道这是图片伪装的视频文件?从其它平台找一个正常的ts文件对比看看:

img

哦豁,原来后面的内容确实是视频文件,只是前面一小部分是BMP文件的头信息,那简单了,直接删了试试:

imgimg

修改后另存为一份,后缀改为ts,避免修改错误导致源文件信息丢失img

打开修改后的ts文件,正常播放:
img

PS:后来发现论坛里,逍遥大佬写的m3u8下载器可以自动去除这种不是ts内容的信息:

img

至此第一阶段分析结束,我以为也就这样了,但是再尝试打开几个视频后,发发发现居然有不一样的加密!!!

OK,既然被发现了,那必须得再分析看看=>

第二次分析

2.1 获取m3u8和key

有了前面那些踩坑,这次分析起来就快多了,再次尝试打开视频页面,通过调试再次拿到m3u8文件,拖入m3u8下载器看看:

img

发现这次需要key,通过不断的调试终于hook到key的位置,这里先把key拿来用一下,填入key,发现又解码失败了:

img

2.2 ts解密

难道这个ts与众不同?打开m3u8文件后发现ts的链接长度明显变短了,下载ts后再次打开文件看看:img

又是熟悉的花屏图片,用winhex打开看看:

img

发现这次怎么也找不到ts头信息了,搜也搜不到了,而且内容非常乱,看起来应该是被加密了,这样只能调试代码看看怎么回事了。这次换个方法找,直接搜,为啥呢,因为调试了半天也跳到解密位置,直接搜碰碰运气:

img

看到有很多结果,前面两个js可以忽略,第3、4个js文件很可疑,打开相应的js再次搜索关键字,发现有很多结果,从上到下依次都大概看一下。然后发现这个位置很可疑,其它地方都没混淆代码,偏偏这里有混淆,此地无银三百两,打上断点试试:

img

再次F5加载页面或者继续播放,点击格式化后再搜关键字,可以看到代码都被混淆了,但是有些关键信息还是可以看到的:

img

统统打上断点看看,F8依次执行,可以看到rsp就是网站加载的原始ts文件,大小一模一样,这里我从Fiddler保存了一份做对比:

img

F8继续执行,发现len变量的值为1243440,应该是确定加密范围的:

img

点击继续下一个断点,发现rsp变了,长度不是1244642,而是1243440了:

img

依葫芦画瓢,这里先保存一下rsp内容,此时的rsp是不能播放的:

img

打开本地保存的后缀为.bmp的ts文件和这个enc.ts进行对比,并搜搜看:

imgimg

原来是通过一定的算法把前面和后面一部分内容给去掉了,那么剩下的应该就是被加密的视频文件了,删除后大小刚好就是enc.ts的大小。下一个断点,来到uText这个变量,发现这个变量的长度刚好和前面的rsp长度是一样的,这里应该就是做了转换,为解密做准备:

img

下一个断点,来到解密函数,这里可以清楚看到加密的内容uTxt、key、iv,虽然看不太懂混淆的代码,但这显然是一个标准的AES-CBC解密操作:

img
而最后的newRresponse=new Uint8Array(arr);就是解密好的视频流,当然这里可以用代码来实现,这里的key和iv都是同一个值,控制台输出一下:

img

这里用Python代码实现解密:

from Crypto.Cipher import AES
import base64

fr = open(r'enc.ts', 'rb')
content = fr.read()
key = iv = base64.b64decode("9Kq58j61Jx42io3e37Qomg==")
cipher = AES.new(key, AES.MODE_CBC, iv)
data = cipher.decrypt(content)
with open(r'dec.ts', 'wb') as fw:
  fw.write(data)

成果展示

img

总结


通过这次实战见识到了很多花里胡哨的操作,还是相当有收获的。也明白还是需要不断学习才能走的更远,再接再厉!当某种逆向思路不行就得尝试换种思路,还有一点就是逆向一定要有耐心!
不足
由于还没学会如何使用AST解这些混淆代码,导致看不懂核心逻辑,所以以下问题暂时没有得到解决

  1. m3u8地址下载的文件如何从图片提取并还原成正常的m3u8内容?
  2. 第二种加密的每个ts似乎都对应着一个key,那么这些hexkey应该如何计算出来?
  3. 第二种ts文件从什么地方开始到结束才是真正需要解密的内容?
  4. 嗯,就先这样吧!

免费评分

参与人数 51吾爱币 +51 热心值 +47 收起 理由
zhengsg5 + 1 + 1 谢谢@Thanks!
wuyanzu001 + 1 + 1 我很赞同!
并非如此 + 1 + 1 我很赞同!
htwl1023 + 1 + 1 热心回复!
wangjinlong721 + 1 + 1 我很赞同!
jacksu + 1 + 1 我很赞同!
11122039 + 1 + 1 我很赞同!
kakavspaoche + 1 + 1 热心回复!
lxgroot + 1 鼓励转贴优秀软件安全工具和文档!
r061225 + 1 + 1 谢谢@Thanks!
eoo + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
lzj1314 + 1 + 1 热心回复!
lzsmldg + 1 + 1 用心讨论,共获提升!
BarryAllen829 + 1 热心回复!
babyx + 1 + 1 谢谢@Thanks!
jiajiea + 1 + 1 用心讨论,共获提升!
MyModHeaven + 1 + 1 我很赞同!
fengruohantian + 1 + 1 我很赞同!
AnNimUJ + 1 + 1 用心讨论,共获提升!
kkavifo + 1 + 1 谢谢@Thanks!
努力加载中 + 1 + 1 谢谢@Thanks!
46114 + 1 谢谢@Thanks!
poisonbcat + 1 + 1 谢谢@Thanks!
Luminouss + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
chenjingyes + 1 + 1 谢谢@Thanks!
sanbaijin2021 + 1 用心讨论,共获提升!
Jack + 1 用心讨论,共获提升!
5omggx + 1 + 1 用心讨论,共获提升!
人家故里 + 1 + 1 用心讨论,共获提升!
sakura0 + 1 我很赞同!
chinajxw + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
jnez112358 + 1 + 1 谢谢@Thanks!
zjun777 + 1 + 1 用心讨论,共获提升!
Windy159 + 1 + 1 我很赞同!
gaosld + 1 + 1 热心回复!
1MajorTom1 + 1 我很赞同!
KylinYang + 1 + 1 谢谢@Thanks!
chumi + 1 + 1 写的很用心
唐小样儿 + 1 + 1 我很赞同!
tail88 + 1 + 1 谢谢@Thanks!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
yixi + 1 + 1 我很赞同!
mmnnbbvvcc2022 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
fufuok + 1 我很赞同!
独行风云 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
laoxiaodiao + 1 + 1 用心讨论,共获提升!
tigerxiao + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
jinzhu160 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
我是不会改名的 + 2 + 1 热心回复!
李玉风我爱你 + 2 + 1 我很赞同!
我没有失眠啊i + 4 + 1 热心回复!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

漁滒 发表于 2022-4-9 18:25
  • m3u8地址下载的文件如何从图片提取并还原成正常的m3u8内容?
  • 第二种加密的每个ts似乎都对应着一个key,那么这些hexkey应该如何计算出来?
  • 第二种ts文件从什么地方开始到结束才是真正需要解密的内容?

第一个问题,代码来自于play.new.js,反混淆后核心代码如下
[JavaScript] 纯文本查看 复制代码
  _0x109702["onload"] = function (e) {
    var buffer = _0x109702["response"];
    var t = new Uint8Array(buffer);
    t = t["slice"](3354);

    var _0x424177 = pako["inflate"](t);

    var res = "";
    var _0x3295a8 = 16384;

    var _0x6ef1a3;

    for (_0x6ef1a3 = 0; _0x6ef1a3 < _0x424177["length"] / _0x3295a8; _0x6ef1a3++) {
      res += String["fromCharCode"]["apply"](null, _0x424177["slice"](_0x6ef1a3 * _0x3295a8, (_0x6ef1a3 + 1) * _0x3295a8));
    }

    res += String["fromCharCode"]["apply"](null, _0x424177["slice"](_0x6ef1a3 * _0x3295a8));
    res = res["replace"](/.*?\.ts/g, "https://vod.bdys.me/$&");
    lines["push"]("data:application/vnd.apple.mpegurl;base64," + btoa(res));

    if (next) {
      next();
    }
  };


这是请求成功的回调函数,可以看到先截取3354字节后面的内容,然后使用pako进行解压,python代码如下

[Python] 纯文本查看 复制代码
    response = requests.get(m3u8_1, headers=headers).content
    m3u8 = gzip.decompress(response[3354:]).decode()


第二个问题和第三个问题,代码来自于hls.min.js,反混淆后核心代码如下

[JavaScript] 纯文本查看 复制代码
                if (t["url"]["indexOf"](".ts") > 0 && "arraybuffer" === t["responseType"]) {
                  try {
                    var buffer = e["response"];
                    var rsp = new Uint8Array(buffer);

                    if (rsp[10] == 138) {
                      let len = arrayToInt(new Uint8Array([rsp[141], rsp[140], rsp[139], rsp[138]]));
                      let hexKey = Array["from"](rsp["slice"](142, 158), _0x144ed7 => _0x144ed7["toString"](16)["padStart"](2, "0"))["join"]("");
                      rsp = rsp["slice"](158, 158 + len);
                      const key = CryptoJS["enc"]["Hex"]["parse"](hexKey, "uft-8");
                      let uTxt = CryptoJS["lib"]["WordArray"]["create"](rsp);
                      let decrypted = CryptoJS["AES"]["decrypt"]({
                        "ciphertext": uTxt
                      }, key, {
                        "iv": key,
                        "mode": CryptoJS["mode"]["CBC"],
                        "padding": CryptoJS["pad"]["Pkcs7"]
                      });
                      let arr = wordToByteArray(decrypted["words"]);

                      if (arr["length"] > 0 && arr[0] == 71 && arr[1] == 64) {
                        newResponse = new Uint8Array(arr);
                      }
                    }
                  } catch (e) {}
                }


第二个问题就很明显了,key取的是142字节到158字节
第三个问题这里首先计算了ts的长度,在138字节处取了一个小端序的int类型,然后从158字节开始截取出真实的ts
然后就可以使用标准aes解密出ts视频,python代码如下

[Python] 纯文本查看 复制代码
    ts = requests.get(tsurl, headers=headers).content
    if ts[10] == 138:
        key = ts[142:142+16]
        ts = ts[158:158 + struct.unpack("<i", ts[138:138+4])[0]]
        crypto = AES.new(key=key, mode=AES.MODE_CBC, iv=key)
        ts = unpad(crypto.decrypt(ts), AES.block_size)
        with open('1.ts', 'wb') as f:
            f.write(ts)

免费评分

参与人数 13吾爱币 +14 热心值 +12 收起 理由
杀猪用牛刀 + 1 + 1 热心回复!
wg198300 + 1 牛掰!
2b菜鸟 + 1 + 1 热心回复!
哇卡s + 1 + 1 我很赞同!
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
sss55 + 1 + 1 渔歌yyds
学习爱好者qaq + 1 + 1 谢谢@Thanks!
李玉风我爱你 + 2 + 1 我很赞同!
衬衫白 + 2 + 1 感谢大佬解答!
kds0221 + 1 大佬就是大佬。厉害
我是不会改名的 + 1 + 1 太厉害了
OVVO + 1 漁滒偶像YYDS
ligxi + 1 + 1 大佬出手,就是nb!

查看全部评分

jinzhu160 发表于 2022-4-9 09:09
var AAA = Function;
Function = function (x) {
  if (x != 'debugger') {
    return AAA(x);
  }
  return function () {};
};
执行这个函数以后,断点会自动消失哦。

免费评分

参与人数 3吾爱币 +4 热心值 +3 收起 理由
李玉风我爱你 + 2 + 1 我很赞同!
罗通晓 + 1 + 1 我很赞同!
ligxi + 1 + 1 用心讨论,共获提升!

查看全部评分

 楼主| ligxi 发表于 2022-8-18 16:20
gamma 发表于 2022-8-18 16:07
小白提问时间:
m3u8软件如何设定参数才能使其从某一位置开始读取呢?

其实没有一个软件可以满足各种需求的,设定参数读取某一个位置的,这种要么软件的作者修改后支持,要么就只能自己写了。
根据网页的逻辑代码,自己编写出对应的处理代码。逍遥的m3u8软件也是这样处理的,判断流媒体是否是正常的头信息,如果是正常的就不进行处理,如果不是就按网页的逻辑代码来处理。
如果感兴趣的话可以看看常见的文件头信息,就会懂如何判断了。
laobj 发表于 2022-5-25 14:07
感谢楼主分享原创
 楼主| ligxi 发表于 2022-4-8 15:58
OVVO 发表于 2022-4-8 15:39
大佬您好,希望能分析下这篇
【震惊】发现一种极其罕见的m3u8魔改加密
https://www.52pojie.cn/thread-16 ...

这个ts加密位置好像和那个阿里是一样的,有一篇阿里的帖子就有提到,不过能不能看懂就得看你自己了。
chucklee 发表于 2022-4-8 15:33
学习一下,谢谢分享
gblw 发表于 2022-4-8 15:38
看得我热血沸腾!
OVVO 发表于 2022-4-8 15:39
大佬您好,希望能分析下这篇
【震惊】发现一种极其罕见的m3u8魔改加密
https://www.52pojie.cn/thread-1613157-1-1.html
(出处: 吾爱破解论坛)
李玉风我爱你 发表于 2022-4-8 15:41
本帖最后由 李玉风我爱你 于 2022-4-8 15:49 编辑

图片类型的可以在hex模式下搜索 49 45 4e 44(IEND)
49 45 4e 44是png的end标识符 之后的数据就是加密的m3u8地址
clipboard.png

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
ligxi + 1 + 1 666666

查看全部评分

yang5355 发表于 2022-4-8 17:00
良心教程,非常好的逆向思路,授人以渔
 楼主| ligxi 发表于 2022-4-8 17:11
李玉风我爱你 发表于 2022-4-8 15:41
图片类型的可以在hex模式下搜索 49 45 4e 44(IEND)
49 45 4e 44是png的end标识符 之后的数据就是加密的m ...

我搜了一下似乎并没有这串代码,这应该是来自其他网站的类似代码吧?不过可以做参考
李玉风我爱你 发表于 2022-4-8 17:18
ligxi 发表于 2022-4-8 17:11
我搜了一下似乎并没有这串代码,这应该是来自其他网站的类似代码吧?不过可以做参考

是其他网站的  我之前逆向的 你可以参考下
头像被屏蔽
又要取名字 发表于 2022-4-8 17:21
这是哔嘀影视吧
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-3-28 17:57

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表