这么久没写这儿的博客了,刚好今天视频解析接口失效了,那咱们就重新去找一个接口玩玩。Ok,那么经过我的层层挑选,我也是终于找到了一个非常不错的解析接口。话不多说,我们直接开干!注意一下,逆向我不是专业的,所以我依赖了GPT,来帮助我完成对算法的分析。
成果展示
逆向开始
好的,那么我们首先让我们的开发者工具能够弹出,这算一个前提条件。
我们更改VM中的debugger断点为false即可过掉。
那么接下来,我们对能够看到的XHR进行分析:
载荷
- z: 27a9e6d51c8cbc2e461c2bc5eef2481f
- jx: https://www.iqiyi.com/v_19rsfjbafk.html
- s1ig: 11399
- g:
好的,那么我们成功拿到了载荷,其中「z」和「s1ig」这两个参数无法使用肉眼观察法获得,所以就只有看看到底什么算法了。
参数猜测
对于「z」参数,看了下位数为32位,那么我首先想到的就是md5值,毕竟这个前端嘛好多都是用这个加密的,「s1ig」这个参数倒是猜不出来。有了基础的思路,我们来试试看。
首先我认为「z」参数是由「jx」参数直接md5加密而来,结果内容如下:
明文密码: https://www.iqiyi.com/v_19rsfjbafk.html
----------加密结果----------
base64_encode($pass):aHR0cHM6Ly93d3cuaXFpeWkuY29tL3ZfMTlyc2ZqYmFmay5odG1s
md5($pass):8e59461a71432c1752a861f4f5a56a82
md5(md5($pass)):93f52d6666486e7a2d3443297c0df984
md5(md5(md5($pass))):e4dd0366768c23d1a6b5c089aa05b695
md5(MD5($pass))a8cbd7535a2be9092a2f0b26d9ded38c
md5(MD5(MD5($pass)))3db103f7913c32b64df92a762cfdb0b5
md5(base64($pass)):2abae1764347b8208bc7855302d75f20
md5(sha1($pass)):7b7e3cc62e8f541ceef40df4344fccdb
sha1($pass):6b7b5da9f9104a137ba5a239f47dc01370765713
sha1(md5($pass)):888fa932ec908fe9bf928524e5778561525d58f6
sha256($pass):945344e8d2dddcee12c333c47aa680a7d8cbffd0309d0aa5d978ea6400c2a23e
sha256(md5($pass)):3e47cd6d9d164b46d13f444fbaae769eb32d507640fcc39eb28f17a952962ae5
mysql($pass):03e5b7a03803fd4f
mysql5($pass):093147d179a18bedcc9801c092d8849f82afab5d
NTLM($pass):cdcda3adffb4b969dfc6db969facfbc6
很不幸,没有匹配上,没办法只好断点调试一下。
算法逆向
在请求启动器,查看一下请求调用栈,点进去看看长什么样:
还行,没有加密而且有一对case情况,还算能够看懂代码的大概逻辑,往上翻一下,看到了URL字段,并且是在e.prev=35
的情况下的,我这里把部分源码贴出来:
u = new Date,
c = u.getTime(),
s = 6e4 * u.getTimezoneOffset(),
8,
d = new Date(c + s + 288e5),
f = (f = d).getDate() + 9 + 9 ^ 10,
f = (f = It()(String(f))).substring(0, 10),
f = It()(f),
p = d.getDay() + 11397,
h = "".concat(m = "//m1-a1.cloud.nnpp.vip:2223/", "api/v/?z=").concat(f, "&jx=").concat(o),
h += "&s1ig=".concat(p),
(v = we.getAll()) && (h += "&g=".concat(v.join(","))),
o || (h = "".concat(m, "api/v/")),
y = function () {
var e = b(g().mark((function e() {
var t;
return g().wrap((function (e) {
for (; ;)
switch (e.prev = e.next) {
case 0:
return h = "//a2.m1907.top:404/api/v/",
e.next = 3,
fetch(h, {
credentials: "include",
headers: {}
});
case 3:
return t = e.sent,
e.t0 = console,
e.next = 7,
t.json();
case 7:
e.t1 = e.sent,
e.t0.log.call(e.t0, e.t1);
case 9:
case "end":
return e.stop()
}
}
), e)
}
)));
return function () {
return e.apply(this, arguments)
}
}()
不难看出,从第十行开始请求的网址就开始拼接了(其实都算一行),那么之前的某一行一定就是「z」参数,那么我们直接在 f = (f = d).getDate() + 9 + 9 ^ 10
这一行打上断点,跑一下看看是个什么情况。
变量「f」通过第一次运算后得到了整数型的「46」,接着走,又将「f」变为字符串然后作为「It()」的一个参数传入并取前十位赋值给「f」得到 d9d4f495e8
这个字符串。
紧接着在将「f」作为 It()
的一个参数传入,获得新的值:
由于我并不是太清楚 f = It()(String(f))
到底做了什么,但是大概还是能够猜到 It()
是与计算md5值有关。那么我么这次选择「步入」的方式看看到底是什么情况。
单步调试
随着单步进入,真相逐渐浮出水面!
Ok,跑进来,看不懂看不懂,还是看不懂,磨来磨去,看懂了个大概。
将46转为数组然后转为字符串,OK那么这里应该就是String的实现:
最后我跳转到了一个 function d(e, t)
这个函数,一看一长串,应该是属于md5实现的一部分,我将这部分丢给了GPT,看看什么情况。
很好,那么基本可以断定 (f = It()(String(f))).substring(0, 10)
这行代码的 It()
实际上代表了md5计算。那么我们来到测试步骤
验证猜想
我对46这个字符串进行了md5加密,得到了以下结果:
md5($pass):d9d4f495e875a2e075a1a4a6e1b9770f
判断一下他的前十位是否与f相同:
'd9d4f495e875a2e075a1a4a6e1b9770f'.substring(0,10) === f
很好,结果输出为true
,那么接下来再对 d9d4f495e8
进行md5加密测试比较:
md5($pass):27a9e6d51c8cbc2e461c2bc5eef2481f
如法炮制,结果输出为true
,那么接下来只需要将「f」的初值计算出来就行,我直接把前面部分丢给GPT,让他帮忙分析结果:
function calculateDate() {
// 获取当前时间和时区信息
var currentDate = new Date();
var currentTime = currentDate.getTime();
var timezoneOffset = 6e4 * currentDate.getTimezoneOffset();
// 计算新日期
var updatedDateTime = new Date(currentTime + timezoneOffset + 288e5);
var updatedDate = updatedDateTime.getDate() + 9 + 9 ^ 10;
return updatedDate;
}
// 调用函数并打印结果
console.log(calculateDate());
请注意,函数calculateDate()不接收任何参数,并返回更新后的日期。在示例中,我们将函数体放入了calculateDate函数中,并在末尾调用该函数并打印结果。
很好,直接给出了函数,那么我们再看看参数:「s1ig」是什么。
由图不难看出,先获取今天是星期几,然后加上「11397」即可,最后完成拼接并发送请求。
逆向完毕,那么我们直接上程序代码,我使用Python,便于直接调用JavaScript代码,避免我再去转。
完整代码
JavaScript
function calculateDate() {
// 获取当前时间和时区信息
var currentDate = new Date();
var currentTime = currentDate.getTime();
var timezoneOffset = 6e4 * currentDate.getTimezoneOffset();
// 计算新日期
var updatedDateTime = new Date(currentTime + timezoneOffset + 288e5);
var updatedDate = updatedDateTime.getDate() + 9 + 9 ^ 10;
return updatedDate;
}
function calculate_md5(){
var timeString = String(calculateDate());
return hex_md5(hex_md5(timeString).substring(0, 10));
}
function get_time_difference(){
var s = new Date();
return s.getDay() + 11397
}
这里的md5自己去找找实现就行,非常容易并且内容较多,这里我就不贴那部分了。
Python
import execjs
import requests
def load_js(file_name):
"""
读取js文件
:return:
"""
with open(file_name, 'r', encoding='UTF-8') as file:
result = file.read()
return result
def get_video_json(date_md5, add_url, date_difference):
params = {
'z': date_md5,
'jx': add_url,
's1ig': date_difference
}
result = requests.get(url="https://m1-a1.cloud.nnpp.vip:2223/api/v/", params=params)
return result.json()
if __name__ == '__main__':
js_code = load_js('reverse_js/nnpp_cloud_api_video.js')
ctx = execjs.compile(js_code)
calculateDate = ctx.call('calculate_md5')
date = ctx.call('get_time_difference')
# https://im1907.top/
result_json = get_video_json(date_md5=calculateDate, add_url='https://www.iqiyi.com/v_19rsfjbafk.html',
date_difference=date)
print(result_json['data'][0])
m3u8 切片播放切片播放即可