前端逆向JavaScript之获取视频解析接口插图

这么久没写这儿的博客了,刚好今天视频解析接口失效了,那咱们就重新去找一个接口玩玩。Ok,那么经过我的层层挑选,我也是终于找到了一个非常不错的解析接口。话不多说,我们直接开干!注意一下,逆向我不是专业的,所以我依赖了GPT,来帮助我完成对算法的分析。

成果展示

逆向开始

好的,那么我们首先让我们的开发者工具能够弹出,这算一个前提条件。

前端逆向JavaScript之获取视频解析接口插图1

我们更改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

很不幸,没有匹配上,没办法只好断点调试一下。

算法逆向

在请求启动器,查看一下请求调用栈,点进去看看长什么样:

前端逆向JavaScript之获取视频解析接口插图2

还行,没有加密而且有一对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 这一行打上断点,跑一下看看是个什么情况。

前端逆向JavaScript之获取视频解析接口插图3

变量「f」通过第一次运算后得到了整数型的「46」,接着走,又将「f」变为字符串然后作为「It()」的一个参数传入并取前十位赋值给「f」得到 d9d4f495e8 这个字符串。

紧接着在将「f」作为 It() 的一个参数传入,获得新的值:

前端逆向JavaScript之获取视频解析接口插图4

由于我并不是太清楚 f = It()(String(f)) 到底做了什么,但是大概还是能够猜到 It() 是与计算md5值有关。那么我么这次选择「步入」的方式看看到底是什么情况。

单步调试

随着单步进入,真相逐渐浮出水面!

Ok,跑进来,看不懂看不懂,还是看不懂,磨来磨去,看懂了个大概。

将46转为数组然后转为字符串,OK那么这里应该就是String的实现:

前端逆向JavaScript之获取视频解析接口插图5

最后我跳转到了一个 function d(e, t) 这个函数,一看一长串,应该是属于md5实现的一部分,我将这部分丢给了GPT,看看什么情况。

前端逆向JavaScript之获取视频解析接口插图6

很好,那么基本可以断定 (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」是什么。

前端逆向JavaScript之获取视频解析接口插图7

由图不难看出,先获取今天是星期几,然后加上「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])