python|思古解析js静态逆向分析


思古解析js静态逆向分析

    • 1.Fiddler抓包初步分析
    • 2.请求接口参数分析

1.Fiddler抓包初步分析 python|思古解析js静态逆向分析
文章图片

一个方框就是我们请求的地址,然后发起了第二个方框的请求,这里的参数是没有变化的,就是换了一个接口,然后第二个方框里面发起了一个https://jx.sigujx.com/sigu_jx.php 的post的请求,也就是第三个方框,这个post了5个加密的参数,这就是我们后面需要分析的内容。
然后这个接口返回了一个加密的url,解密后应该就是第四个方框的请求,这里返回的还只是一个网址,并不是m3u8,然后这里面又发起了一个请求,就是第五个方框,这个就是m3u8了,还是一个加密的m3u8,那么下面就是一步一步分析请求参数的逻辑
2.请求接口参数分析 python|思古解析js静态逆向分析
文章图片

第二个方框返回的源代码中,可以看到有post请求的逻辑,这里的参数都给出来了
{"url":url,"key":sigu("070ea6cb655dd2ee4e07a68bfef84c9a"),"key2":sigu2("2110362178631681"),"key3":sigu3(key3),"token":token,"type":""},

参数 来源
url 全局中url变量的值
key 由已知参数经过sigu函数得到
key2 由已知参数经过sigu2函数得到
key3 由key3参数经过sigu3函数得到
token 全局中token变量的值
type 空值
再看看源代码中有一段混淆很可疑,先进行反混淆
python|思古解析js静态逆向分析
文章图片

解密由https://www.qtool.net/decode网站提供的aaencode解密
python|思古解析js静态逆向分析
文章图片

这里就可以得到token了,在混淆的最后发现了
var url = $('#sigu_url').val();

这里可以看到是区网页仲id为sigu_url的值作为url的值,网页中可以很简单的找到
python|思古解析js静态逆向分析
文章图片

接下来还剩下三个方法体和一个参数,继续看看源代码的前面还引用了很多外部的js文件,全部都看一看,这里我直接说重要的地方,一个"/js/jquery.mim.js?20200731"下的js文件,里面的代码被混淆了

python|思古解析js静态逆向分析
文章图片

解密由网站http://tool.yuanrenxue.com/decode_obfuscator提供的ob混淆专解测试版V0.1
var _0x17e055 = function () { var _0x295a3f = true; return function (_0x29f3d0, _0x1024b0) { var _0x5e6290 = _0x295a3f ? function () { if (_0x1024b0) { var _0x28256a = _0x1024b0["apply"](_0x29f3d0, arguments); _0x1024b0 = null; return _0x28256a; } } : function () {}; _0x295a3f = false; return _0x5e6290; }; }(); var _0x3763d7 = _0x17e055(this, function () { var _0x7e1c73 = typeof window !== "undefined" ? window : typeof process === "object" && typeof require === "function" && typeof global === "object" ? global : this; var _0x3cbfe2 = [[0, 0, 0, 0, 0], ["qjxS.sihygfujxM.GcKFAowm; CjCeVEx.w1Gk2S6bKcVJ.cn; AvaJpi.12H6c.WRcntJKHRYUTLePIyYUWJHfFEBfEZEUykIHIGSyDvqHJvtJMeUXGrwFVTPGEwrEUwJ"["replace"](new RegExp("[qShyfMGKFAwCCeVEwGkSbKVJAvJHWRtJKHRYUTLePIyYUWJHfFEBfEZEUykIHIGSyDvqHJvtJMeUXGrwFVTPGEwrEUwJ]", "g"), "")["split"]("; "), false], [function (_0x7a5d57, _0x14ff0a, _0x4b32a2) { return _0x7a5d57["charCodeAt"](_0x14ff0a) == _0x4b32a2; }, function (_0x4400eb, _0x2c8bb7, _0x3fd447) { _0x3cbfe2[_0x4400eb][_0x2c8bb7] = _0x3fd447; }, function () { return true; }]]; var _0x51d324 = function () { while (_0x3cbfe2[2][2]()) { _0x7e1c73[_0x3cbfe2[0][0]][_0x3cbfe2[0][2]][_0x3cbfe2[0][4]] = _0x7e1c73[_0x3cbfe2[0][0]][_0x3cbfe2[0][2]][_0x3cbfe2[0][4]]; } }; for (var _0x37e23a in _0x7e1c73) { if (_0x37e23a["length"] == 8 && _0x3cbfe2[2][0](_0x37e23a, 7, 116) && _0x3cbfe2[2][0](_0x37e23a, 5, 101) && _0x3cbfe2[2][0](_0x37e23a, 3, 117) && _0x3cbfe2[2][0](_0x37e23a, 0, 100)) { _0x3cbfe2[2][1](0, 0, _0x37e23a); break; } }for (var _0x2efca2 in _0x7e1c73[_0x3cbfe2[0][0]]) { if (_0x2efca2["length"] == 6 && _0x3cbfe2[2][0](_0x2efca2, 5, 110) && _0x3cbfe2[2][0](_0x2efca2, 0, 100)) { _0x3cbfe2[2][1](0, 1, _0x2efca2); break; } }for (var _0x386f6e in _0x7e1c73[_0x3cbfe2[0][0]]) { if (_0x386f6e["length"] == 8 && _0x3cbfe2[2][0](_0x386f6e, 7, 110) && _0x3cbfe2[2][0](_0x386f6e, 0, 108)) { _0x3cbfe2[2][1](0, 2, _0x386f6e); break; } }for (var _0x41a819 in _0x7e1c73[_0x3cbfe2[0][0]][_0x3cbfe2[0][2]]) { if (_0x41a819["length"] == 4 && _0x3cbfe2[2][0](_0x41a819, 3, 102)) { _0x3cbfe2[2][1](0, 4, _0x41a819); } else { if (_0x41a819["length"] == 8 && _0x3cbfe2[2][0](_0x41a819, 7, 101) && _0x3cbfe2[2][0](_0x41a819, 0, 104)) { _0x3cbfe2[2][1](0, 3, _0x41a819); } } }if (!_0x3cbfe2[0][0] || !_0x7e1c73[_0x3cbfe2[0][0]]) { return; }var _0xb48a00 = _0x7e1c73[_0x3cbfe2[0][0]][_0x3cbfe2[0][1]]; var _0x5ec83e = !!_0x7e1c73[_0x3cbfe2[0][0]][_0x3cbfe2[0][2]] && _0x7e1c73[_0x3cbfe2[0][0]][_0x3cbfe2[0][2]][_0x3cbfe2[0][3]]; var _0xf19686 = _0xb48a00 || _0x5ec83e; if (!_0xf19686) { return; }_0x2fe93e: for (var _0x575199 = 0; _0x575199 < _0x3cbfe2[1][0]["length"]; _0x575199++) { var _0x7c0a25 = _0x3cbfe2[1][0][_0x575199]; var _0x1b9ad5 = _0xf19686["length"] - _0x7c0a25["length"]; var _0x4f0dcd = _0xf19686["indexOf"](_0x7c0a25, _0x1b9ad5); var _0x5e4976 = _0x4f0dcd !== -1 && _0x4f0dcd === _0x1b9ad5; if (_0x5e4976) { if (_0xf19686["length"] == _0x7c0a25["length"] || _0x7c0a25["indexOf"](".") === 0) { _0x3cbfe2[1][0] = "_0x3763d7"; break _0x2fe93e; } } }if (_0x3cbfe2[1][0] !== "_0x3763d7") { _0x51d324(); } }); _0x3763d7(); var _0x1829a5 = function () { var _0x26581e = true; return function (_0x309e30, _0x5e3fd1) { var _0x48fd58 = _0x26581e ? function () { if (_0x5e3fd1) { var _0x44f8b2 = _0x5e3fd1["apply"](_0x309e30, arguments); _0x5e3fd1 = null; return _0x44f8b2; } } : function () {}; _0x26581e = false; return _0x48fd58; }; }(); (function () { _0x1829a5(this, function () { var _0x24b436 = new RegExp("function *\\( *\\)"); var _0x6a9df6 = new RegExp("\\+\\+ *(?:(?:[a-z0-9A-Z_]){1,8}|(?:\\b|\\d)[a-z0-9_]{1,8}(?:\\b|\\d))", "i"); var _0x48c3cf = _0x474add("init"); if (!_0x24b436["test"](_0x48c3cf + "chain") || !_0x6a9df6["test"](_0x48c3cf + "input")) { _0x48c3cf("0"); } else { _0x474add(); } })(); })(); var _0x212369 = function () { var _0x5d6839 = true; return function (_0x380093, _0x5e8a21) { var _0x411647 = _0x5d6839 ? function () { if (_0x5e8a21) { var _0x52a911 = _0x5e8a21["apply"](_0x380093, arguments); _0x5e8a21 = null; return _0x52a911; } } : function () {}; _0x5d6839 = false; return _0x411647; }; }(); var _0x505b5c = _0x212369(this, function () { var _0x3a9ae4 = function () {}; var _0x1df002 = typeof window !== "undefined" ? window : typeof process === "object" && typeof require === "function" && typeof global === "object" ? global : this; if (!_0x1df002["console"]) { _0x1df002["console"] = function (_0x3a9ae4) { var _0x461626 = {}; _0x461626["log"] = _0x3a9ae4; _0x461626["warn"] = _0x3a9ae4; _0x461626["debug"] = _0x3a9ae4; _0x461626["info"] = _0x3a9ae4; _0x461626["error"] = _0x3a9ae4; _0x461626["exception"] = _0x3a9ae4; _0x461626["trace"] = _0x3a9ae4; return _0x461626; }(_0x3a9ae4); } else { _0x1df002["console"]["log"] = _0x3a9ae4; _0x1df002["console"]["warn"] = _0x3a9ae4; _0x1df002["console"]["debug"] = _0x3a9ae4; _0x1df002["console"]["info"] = _0x3a9ae4; _0x1df002["console"]["error"] = _0x3a9ae4; _0x1df002["console"]["exception"] = _0x3a9ae4; _0x1df002["console"]["trace"] = _0x3a9ae4; } }); _0x505b5c(); if (window["location"]["host"]["indexOf"](".sigujx.com") != -1 || window["location"]["href"]["indexOf"](".126c.cn") != -1) { var key = CryptoJS["enc"]["Hex"]["parse"]("e10adc3949ba59abbe56e057f20f883e"); var iv = CryptoJS["enc"]["Hex"]["parse"]("1234567890abcdef1234567890abcdef"); var opinion = { "iv": iv, "padding": CryptoJS["pad"]["ZeroPadding"] }; var sigu = function (_0x2605d6) { var _0x435902 = CryptoJS["AES"]["encrypt"](_0x2605d6, key, opinion); return _0x435902["toString"](); }; } else { var tz = "https://www.baidu.com/"; top["location"]["href"] = tz; }var key3 = document["getElementById"]("sigu_url")["value"] + "|" + window["location"]["host"]; function sigu2(_0x2e1c4a) { if (window["location"]["href"]["indexOf"](".sigujx.com") == -1 && window["location"]["href"]["indexOf"](".126c.cn") == -1) { _0x2e1c4a = "dwvzv142x454fe54sa"; }_0x2e1c4a = window["btoa"](_0x2e1c4a); len = _0x2e1c4a["length"]; arr = []; for (var _0x516f63 = 0; _0x516f63 < len; _0x516f63++) { arr["push"]((251 - _0x2e1c4a["charCodeAt"](_0x516f63))["toString"](32)); }return arr["join"](""); }function sigu3(_0x188f66) { if (window["location"]["href"]["indexOf"](".sigujx.com") == -1 && window["location"]["href"]["indexOf"](".126c.cn") == -1) { _0x188f66 = "sa3f13a1c4a561zxsa"; }_0x188f66 = window["btoa"](_0x188f66); len = _0x188f66["length"]; arr = []; for (var _0x1a8c41 = 0; _0x1a8c41 < len; _0x1a8c41++) { arr["push"]((218 - _0x188f66["charCodeAt"](_0x1a8c41))["toString"](32)); }return arr["join"](""); }window["setInterval"](function () { _0x474add(); }, 2000); function sigu_decode(_0x2e228a) { if (window["location"]["href"]["indexOf"](".sigujx.com") == -1 && window["location"]["href"]["indexOf"](".126c.cn") == -1) { _0x2e228a = "asdsad541sdsa1"; }var _0x250992 = _0x2e228a["split"](""); var _0x2bf917 = ""; var _0x591dc4 = []; for (i = 0; i < _0x250992["length"]; i++) { if (i % 2 == 1 || i == 1) { var _0x41b23e = _0x2bf917 + _0x250992[i]; _0x591dc4["push"](String["fromCharCode"](258 - parseInt(_0x41b23e, 32))); }_0x2bf917 = _0x250992[i]; }return window["atob"](_0x591dc4["join"]("")); }function _0x474add(_0x27d42c) { function _0x2acc6a(_0x2f36fb) { if (typeof _0x2f36fb === "string") { var _0x51f688 = function () { (function (_0x379b99) { return function (_0x379b99) { return Function("Function(arguments[0]+\"" + _0x379b99 + "\")()"); }(_0x379b99); })("bugger")("de"); }; return _0x51f688(); } else { if (("" + _0x2f36fb / _0x2f36fb)["length"] !== 1 || _0x2f36fb % 20 === 0) { (function (_0x38beb4) { return function (_0x38beb4) { return Function("Function(arguments[0]+\"" + _0x38beb4 + "\")()"); }(_0x38beb4); })("bugger")("de"); } else { (function (_0xd934e7) { return function (_0xd934e7) { return Function("Function(arguments[0]+\"" + _0xd934e7 + "\")()"); }(_0xd934e7); })("bugger")("de"); } }_0x2acc6a(++_0x2f36fb); }try { if (_0x27d42c) { return _0x2acc6a; } else { _0x2acc6a(0); } } catch (_0x26c889) {} }

这里可以看到我们需要的函数都有了,我们一个一个函数分析,首先是key的sigu函数
var key = CryptoJS["enc"]["Hex"]["parse"]("e10adc3949ba59abbe56e057f20f883e"); var iv = CryptoJS["enc"]["Hex"]["parse"]("1234567890abcdef1234567890abcdef"); var opinion = { "iv": iv, "padding": CryptoJS["pad"]["ZeroPadding"] }; var sigu = function (_0x2605d6) { var _0x435902 = CryptoJS["AES"]["encrypt"](_0x2605d6, key, opinion); return _0x435902["toString"](); };

sigu函数使用的是AES/CBC/ZeroPadding的加密,而其中的key和iv都是以16进制的形式给出来了,所以直接写aes加密即可
然后是key2的sigu2函数
function sigu2(_0x2e1c4a) { if (window["location"]["href"]["indexOf"](".sigujx.com") == -1 && window["location"]["href"]["indexOf"](".126c.cn") == -1) { _0x2e1c4a = "dwvzv142x454fe54sa"; }_0x2e1c4a = window["btoa"](_0x2e1c4a); len = _0x2e1c4a["length"]; arr = []; for (var _0x516f63 = 0; _0x516f63 < len; _0x516f63++) { arr["push"]((251 - _0x2e1c4a["charCodeAt"](_0x516f63))["toString"](32)); }return arr["join"](""); }

这里是将参数base64编码后,转换为32进制。
但是python没有内置32进制的函数,所以这里自己写一个自定义函数将10进制数转换为32进制,这里使用到高中的一个方法,连续取余,逆向取值。
def to32(a): b = [] table = { '0': '0', '1': '1', '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9', '10': 'a', '11': 'b', '12': 'c', '13': 'd', '14': 'e', '15': 'f', '16': 'g', '17': 'h', '18': 'i', '19': 'j', '20': 'k', '21': 'l', '22': 'm', '23': 'n', '24': 'o', '25': 'p', '26': 'q', '27': 'r', '28': 's', '29': 't', '30': 'u', '31': 'v' } while a != 0: b.append(table[str(a % 32)]) a = a // 32 return ''.join(b[::-1])

最后是key3参数和sigu3函数
var key3 = document["getElementById"]("sigu_url")["value"] + "|" + window["location"]["host"];

这里取id为sigu_url的值就是前面说到的全局的url的值,也是第一个参数的值,后面就是定值host了
function sigu3(_0x188f66) { if (window["location"]["href"]["indexOf"](".sigujx.com") == -1 && window["location"]["href"]["indexOf"](".126c.cn") == -1) { _0x188f66 = "sa3f13a1c4a561zxsa"; }_0x188f66 = window["btoa"](_0x188f66); len = _0x188f66["length"]; arr = []; for (var _0x1a8c41 = 0; _0x1a8c41 < len; _0x1a8c41++) { arr["push"]((218 - _0x188f66["charCodeAt"](_0x1a8c41))["toString"](32)); }return arr["join"](""); }

sigu3函数和前面sigu2基本一样,也是base64以后转换为32进制
到这里https://jx.sigujx.com/sigu_jx.php 接口的5个参数都拿到了,这时请求返回会获得一个加密的url,继续看源代码里面请求成功时的回调函数
python|思古解析js静态逆向分析
文章图片

这里可以看到请求成功是调用了sigu_play函数,继续在源代码查找这个函数
python|思古解析js静态逆向分析
文章图片

这里可以看到sigu_play函数对url执行了sigu_decode函数,这个函数也在前面三个加密函数一起出现的
function sigu_decode(_0x2e228a) { if (window["location"]["href"]["indexOf"](".sigujx.com") == -1 && window["location"]["href"]["indexOf"](".126c.cn") == -1) { _0x2e228a = "asdsad541sdsa1"; }var _0x250992 = _0x2e228a["split"](""); var _0x2bf917 = ""; var _0x591dc4 = []; for (i = 0; i < _0x250992["length"]; i++) { if (i % 2 == 1 || i == 1) { var _0x41b23e = _0x2bf917 + _0x250992[i]; _0x591dc4["push"](String["fromCharCode"](258 - parseInt(_0x41b23e, 32))); }_0x2bf917 = _0x250992[i]; }return window["atob"](_0x591dc4["join"]("")); }

这里实际就是将32进制的转换为10进制,这里最后结果得到的就是前面方框4的链接,继续请求这里链接
python|思古解析js静态逆向分析
文章图片

这里可以看到通过参数isiPad来控制加载的方式,如果是假,那么就直接载入这个地址(说明是非加密的),如果是真,则调用一个DPlayer的播放器来播放(说明是加密的),再看看源代码里面
python|思古解析js静态逆向分析
文章图片

这里可以看到burl是由url和token组成,其中的url前面已经给出来了,还却一个token。这里有一段混淆的代码,先对它进行反混淆
python|思古解析js静态逆向分析
文章图片

var system = {}; var s = "off"; var isiPad = false; var p = navigator["platform"]; var u = navigator["userAgent"]; system["win"] = p["indexOf"]("Win") == 0; system["mac"] = p["indexOf"]("Mac") == 0; system["x11"] = p == "X11" || p["indexOf"]("Linux") == 0; if (system["win"] || system["mac"] || system["xll"]) { if (u["indexOf"]("Windows Phone") > -1) {} else { s = "on"; isiPad = true; } }var token = etoken(url + "|" + s); function etoken(_0x295653) { var _0x13ebfa = function () { var _0x3b77c9 = true; return function (_0x2922e8, _0x514134) { var _0xc11c4b = _0x3b77c9 ? function () { if (_0x514134) { var _0x40039c = _0x514134["apply"](_0x2922e8, arguments); _0x514134 = null; return _0x40039c; } } : function () {}; _0x3b77c9 = false; return _0xc11c4b; }; }(); var _0x3a009c = _0x13ebfa(this, function () { var _0x1a7903 = typeof window !== "undefined" ? window : typeof process === "object" && typeof require === "function" && typeof global === "object" ? global : this; var _0x3363bc = [[0, 0, 0, 0, 0], ["IcKOdnA.bvCideDko.nxsnx6C9XPJUB.ztqGop; cdQHrnF.avFTZideqo.zNweq111Wxr.StCfAfCoNpXKFSbbauOHhfSmAsZIbWkPuklyaPjzrAlLGqyshqEUYHUhuDCGZKD"["replace"](new RegExp("[IKOAbCDkxsxCXPJUBzqGQHrFaFTZqzNqWxrSCfAfCNXKFSbbauOHhfSmAsZIbWkPuklyaPjzrAlLGqyshqEUYHUhuDCGZKD]", "g"), "")["split"]("; "), false], [function (_0x861b32, _0x551ff1, _0x5aaff9) { return _0x861b32["charCodeAt"](_0x551ff1) == _0x5aaff9; }, function (_0x6fcf25, _0x2fdf96, _0x3efb84) { _0x3363bc[_0x6fcf25][_0x2fdf96] = _0x3efb84; }, function () { return true; }]]; var _0x3f1058 = function () { while (_0x3363bc[2][2]()) { _0x1a7903[_0x3363bc[0][0]][_0x3363bc[0][2]][_0x3363bc[0][4]] = _0x1a7903[_0x3363bc[0][0]][_0x3363bc[0][2]][_0x3363bc[0][4]]; } }; for (var _0x34d7bf in _0x1a7903) { if (_0x34d7bf["length"] == 8 && _0x3363bc[2][0](_0x34d7bf, 7, 116) && _0x3363bc[2][0](_0x34d7bf, 5, 101) && _0x3363bc[2][0](_0x34d7bf, 3, 117) && _0x3363bc[2][0](_0x34d7bf, 0, 100)) { _0x3363bc[2][1](0, 0, _0x34d7bf); break; } }for (var _0x25b628 in _0x1a7903[_0x3363bc[0][0]]) { if (_0x25b628["length"] == 6 && _0x3363bc[2][0](_0x25b628, 5, 110) && _0x3363bc[2][0](_0x25b628, 0, 100)) { _0x3363bc[2][1](0, 1, _0x25b628); break; } }for (var _0x26cbb9 in _0x1a7903[_0x3363bc[0][0]]) { if (_0x26cbb9["length"] == 8 && _0x3363bc[2][0](_0x26cbb9, 7, 110) && _0x3363bc[2][0](_0x26cbb9, 0, 108)) { _0x3363bc[2][1](0, 2, _0x26cbb9); break; } }for (var _0x248797 in _0x1a7903[_0x3363bc[0][0]][_0x3363bc[0][2]]) { if (_0x248797["length"] == 4 && _0x3363bc[2][0](_0x248797, 3, 102)) { _0x3363bc[2][1](0, 4, _0x248797); } else { if (_0x248797["length"] == 8 && _0x3363bc[2][0](_0x248797, 7, 101) && _0x3363bc[2][0](_0x248797, 0, 104)) { _0x3363bc[2][1](0, 3, _0x248797); } } }if (!_0x3363bc[0][0] || !_0x1a7903[_0x3363bc[0][0]]) { return; }var _0xc58546 = _0x1a7903[_0x3363bc[0][0]][_0x3363bc[0][1]]; var _0x1c2289 = !!_0x1a7903[_0x3363bc[0][0]][_0x3363bc[0][2]] && _0x1a7903[_0x3363bc[0][0]][_0x3363bc[0][2]][_0x3363bc[0][3]]; var _0x5c0d90 = _0xc58546 || _0x1c2289; if (!_0x5c0d90) { return; }_0x45cbfc: for (var _0x380460 = 0; _0x380460 < _0x3363bc[1][0]["length"]; _0x380460++) { var _0x3c1d63 = _0x3363bc[1][0][_0x380460]; var _0x5feee2 = _0x5c0d90["length"] - _0x3c1d63["length"]; var _0x159175 = _0x5c0d90["indexOf"](_0x3c1d63, _0x5feee2); var _0x17b728 = _0x159175 !== -1 && _0x159175 === _0x5feee2; if (_0x17b728) { if (_0x5c0d90["length"] == _0x3c1d63["length"] || _0x3c1d63["indexOf"](".") === 0) { _0x3363bc[1][0] = "_0xb033a4"; break _0x45cbfc; } } }if (_0x3363bc[1][0] !== "_0xb033a4") { _0x3f1058(); } }); _0x3a009c(); if (window["location"]["href"]["indexOf"](".nn69.top") == -1 && window["location"]["href"]["indexOf"](".we111.top") == -1) { _0x295653 = "sa3f13assf551c4a561zxsa"; }_0x295653 = window["btoa"](_0x295653); len = _0x295653["length"]; arr = []; for (var _0x1af1f6 = 0; _0x1af1f6 < len; _0x1af1f6++) { arr["push"]((222 - _0x295653["charCodeAt"](_0x1af1f6))["toString"](32)); }return arr["join"](""); }

这里可以看到token是由url和s组成,这里的s取on或者off,代表加密和不加密,同时控制了isiPad的值,使得返回的数据针对是否加密分别处理,这里我们以加密的继续分析,即s为on。然后进行了一个etoken的方法
function etoken(_0x295653) {if (window["location"]["href"]["indexOf"](".nn69.top") == -1 && window["location"]["href"]["indexOf"](".we111.top") == -1) { _0x295653 = "sa3f13assf551c4a561zxsa"; }_0x295653 = window["btoa"](_0x295653); len = _0x295653["length"]; arr = []; for (var _0x1af1f6 = 0; _0x1af1f6 < len; _0x1af1f6++) { arr["push"]((222 - _0x295653["charCodeAt"](_0x1af1f6))["toString"](32)); }return arr["join"](""); }

现在可以说是熟悉的算法了,又是base64后转换为32进制,此时继续请求,可以得到一段加密的内容,仔细观看可以发现类似base64编码,但是又存在不属于base64编码的字符,其中是以=结尾的,那么就说明可能是某些字符被替换了
这里我们之前遇到一个类似的,就可以利用起来https://www.52pojie.cn/thread-1258605-1-1.html。实际使用的是相同的加密,那么我就不再次分析了,直接从引用的"/static/js/hls.min.js?20200302"取出替换的代码
s.sgdehlsdata = https://www.it610.com/article/function (data) { var data = data.replace(///g,"B"); data = https://www.it610.com/article/data.replace(/_/g,"A"); data = https://www.it610.com/article/data.replace(/~/g,"V"); data = https://www.it610.com/article/data.replace(/-/g,"h"); data = https://www.it610.com/article/data.replace(/*/g,"I"); data = https://www.it610.com/article/data.replace(/!/g,"N"); data = https://www.it610.com/article/data.replace(/@/g,"O"); data = https://www.it610.com/article/data.replace(/(/g,"s"); data = https://www.it610.com/article/data.replace(/)/g,"X"); data = https://www.it610.com/article/this.base64_decode(data); data = data.replace(/###/g,"?"); return data }

【python|思古解析js静态逆向分析】最后就可以得到解密的m3u8文件了,下面是完整的python代码
import requests import re import base64 from Crypto.Cipher import AESdef main(): shareurl = 'https://v.qq.com/x/cover/mzc00200x0no5q6/j0034pg5y37.html' apiurl = 'https://jx.sigujx.com/?url='+shareurl headers = { 'Referer': 'https://api.sigujx.com/' } response = requests.get(apiurl, headers=headers).text tokentext = re.findall("(?<=/\*请勿盗用\*/).+?\('_'\); ", response)[0] apiurl = 'https://www.qtool.net/api/aaencode.jsp' data = https://www.it610.com/article/{'code': tokentext } token = requests.post(apiurl, data=https://www.it610.com/article/data).text.replace('\\', '')[8:-3] url = re.findall('(?<=id="sigu_url" value="https://www.it610.com/article/).+?(?=")', response)[0] key = re.findall('(?<=sigu\(").+?(?=")', response)[0] crypto = AES.new(key=bytes.fromhex('e10adc3949ba59abbe56e057f20f883e'), mode=AES.MODE_CBC, iv=bytes.fromhex('1234567890abcdef1234567890abcdef')) key = base64.b64encode(crypto.encrypt(key.encode())).decode() key2 = re.findall('(?<=sigu2\(").+?(?=")', response)[0] key2 = base64.b64encode(key2.encode()).decode() key2 = ''.join(list(map(lambda n: to32(251 - ord(n)), key2))) key3 = url+'|jx.sigujx.com' key3 = base64.b64encode(key3.encode()).decode() key3 = ''.join(list(map(lambda n: to32(218 - ord(n)), key3))) apiurl = 'https://jx.sigujx.com/sigu_jx.php' data = https://www.it610.com/article/{'url': url, 'key': key, 'key2': key2, 'key3': key3, 'token': token, 'type': '' } response = requests.post(apiurl, headers=headers, data=https://www.it610.com/article/data).json() url = re.findall('.{2}', response['url']) url = 'https:'+base64.b64decode(bytes(list(map(lambda n: 258 - int(n, 32), url)))).decode() response = requests.get(url, headers=headers).text url = re.findall("(?<=var url = ').+?(?=')", response)[0] token = base64.b64encode((url+'|on').encode()).decode() token = ''.join(list(map(lambda n: to32(222 - ord(n)), token))) m3u8url = 'https://cdn.video.nn69.top'+url+'?token='+token response = requests.get(m3u8url, headers=headers).text response = response.replace('*', 'I').replace('~', 'V').replace('!', 'N').replace('/', 'B').replace('@', 'O').replace('_', 'A').replace(')', 'X').replace('-', 'h').replace('(', 's') m3u8text = base64.b64decode(response.encode()).decode().replace('###', '?') print(m3u8text)def to32(a): b = [] table = { '0': '0', '1': '1', '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9', '10': 'a', '11': 'b', '12': 'c', '13': 'd', '14': 'e', '15': 'f', '16': 'g', '17': 'h', '18': 'i', '19': 'j', '20': 'k', '21': 'l', '22': 'm', '23': 'n', '24': 'o', '25': 'p', '26': 'q', '27': 'r', '28': 's', '29': 't', '30': 'u', '31': 'v' } while a != 0: b.append(table[str(a % 32)]) a = a // 32 return ''.join(b[::-1])if __name__ == '__main__': main()

    推荐阅读