一个方框就是我们请求的地址,然后发起了第二个方框的请求,这里的参数是没有变化的,就是换了一个接口,然后第二个方框里面发起了一个https://jx.sigujx.com/sigu_jx.php 的post的请求,也就是第三个方框,这个post了5个加密的参数,这就是我们后面需要分析的内容。
然后这个接口返回了一个加密的url,解密后应该就是第四个方框的请求,这里返回的还只是一个网址,并不是m3u8,然后这里面又发起了一个请求,就是第五个方框,这个就是m3u8了,还是一个加密的m3u8,那么下面就是一步一步分析请求参数的逻辑
第二个方框返回的源代码中,可以看到有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 | 空值 |
再看看源代码中有一段混淆很可疑,先进行反混淆
解密由https://www.qtool.net/decode网站提供的aaencode解密
这里就可以得到token了,在混淆的最后发现了
var url = $('#sigu_url').val();
这里可以看到是区网页仲id为sigu_url的值作为url的值,网页中可以很简单的找到
接下来还剩下三个方法体和一个参数,继续看看源代码的前面还引用了很多外部的js文件,全部都看一看,这里我直接说重要的地方,一个"/js/jquery.mim.js?20200731"下的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,继续看源代码里面请求成功时的回调函数
这里可以看到请求成功是调用了sigu_play函数,继续在源代码查找这个函数
这里可以看到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的链接,继续请求这里链接
这里可以看到通过参数isiPad来控制加载的方式,如果是假,那么就直接载入这个地址(说明是非加密的),如果是真,则调用一个DPlayer的播放器来播放(说明是加密的),再看看源代码里面
这里可以看到burl是由url和token组成,其中的url前面已经给出来了,还却一个token。这里有一段混淆的代码,先对它进行反混淆
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 = function (data) {
var data = data.replace(/\//g, "B");
data = data.replace(/_/g, "A");
data = data.replace(/~/g, "V");
data = data.replace(/-/g, "h");
data = data.replace(/\*/g, "I");
data = data.replace(/!/g, "N");
data = data.replace(/@/g, "O");
data = data.replace(/\(/g, "s");
data = data.replace(/\)/g, "X");
data = this.base64_decode(data);
data = data.replace(/###/g, "?");
return data
}
最后就可以得到解密的m3u8文件了,下面是完整的python代码
import requests
import re
import base64
from Crypto.Cipher import AES
def 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 = {
'code': tokentext
}
token = requests.post(apiurl, data=data).text.replace('\\', '')[8:-3]
url = re.findall('(?<=id="sigu_url" value=").+?(?=")', 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 = {
'url': url,
'key': key,
'key2': key2,
'key3': key3,
'token': token,
'type': ''
}
response = requests.post(apiurl, headers=headers, data=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()