一、预处理代码
利用ast将代码还原,还原后可以看到这里用有一些eval
检测点,这里先进行手动删除,
替换到网页中的代码后发现陷入到了死循环,这里仍然进行手动删除
二、分析请求
通过定位堆栈请求,可以看到先调用了sp函数,然后进行在请求的页面,那么下面分析sp函数
这里可以看到是先设置了一个mz,然后又发了一个请求,并将请求到的内容执行了一下,那么这里先看一下得到的代码是什么。
这里可以看到是一个混淆过的代码,那么继续利用ast尝试还原看一下,还原后经过分析无效代码,然后手动删除,最终得到了下面的结果,那么实际上这里就是请求一下,然后获取v14
和v142
这两个参数并赋值给了window。
继续分析sp函数,这里可以看到经过一系列的计算最终赋值给了设置了cookie中的’m’参数,至此sp函数结束,然后这里看了一下请求中并没有什么别的参数了。
三、获取v14与v142
在上面分析sp函数中得到,需要先设置cookie 中的mz参数,然后再去请求。这里看到应该是取了浏览器环境中的一系列指纹,然后得到了z这个指纹数组,然后base64编码了一下,就设置给了mz。
手动将z从浏览器里面取出来,然后设置给编码一下设置给cookie,如下所示:
得到了混淆代码后,发现无法直接用正则将需要的值取出来。
因为刚才还原了这个代码,简单看了一下没有用到什么别的环境,所以这里直接简单补了一下,顺利得到需要的参数。补的环境如下:
window = global;
setInterval=function(){};
function get_config(){
return {
'v14':window.v14,
'v142':window.v142,
}
}
四、获取cookie中的m
继续扣取cookie中m参数。将a,b这种赋值的代码直接拿下来。同时这有获取z的toString()顺手直接从浏览器中取下来然后修改代码。
遇到E函数的调用,这里就讲这个函数扣下来,同时跟进去,可以看到关键字jsencrypt
这里就可以合理怀疑RSA加密算法,这里先从浏览器里面取一下,仍然先尝试一下标准算法,如果不对后面回过头来在处理这个。
function E(K) {
function d(h, b) {
var D = b;
var I = _n("jsencrypt");
var u = new I();
var Q = u["encode"](h, D);
return Q;
}
result = d(K, K);
return result;
}
=====》》》
window = global;
const JSEncrypt = require('jsencrypt')
rsa_key ="-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDq04c6My441Gj0UFKgrqUhAUg+kQZeUeWSPlAU9fr4HBPDldAeqzx1UR92KJHuQh/zs1HOamE2dgX9z/2oXcJaqoRIA/FXysx+z2YlJkSk8XQLcQ8EBOkp//MZrixam7lCYpNOjadQBb2Ot0U/Ky+jF2p+Ie8gSZ7/u+Wnr5grywIDAQAB-----END PUBLIC KEY-----"
function Encrypt(Z, a){
rsa = new JSEncrypt()
rsa["setPublicKey"](rsa_key)
var X = a ? a + "|" + Z : Z;
return encodeURIComponent(rsa["encrypt"](X));
}
function E(K) {
result = Encrypt(K, K);
return result;
}
console.log(E(1751089504000))
下面继续分析,调用m5函数得到的了32位的值,合理怀疑md5,然而经过对比标准算法,发现不一样,应该是魔改了,那么这里将m5函数取拿下来。下面一步步的跟然后是调用了gee函数。在抠这个函数的时候,encrypt1函数没有返回值,这里发现疑似一个对称算法,于是,这里尝试与本地的标准算法做对比。(其实encrypt
应该是rsa的算法)
可以看到这里是一样的。那么这里将这部分代码修改为已知的算法。
于是这个函数就成了:
cu["encrypt1"] = function (ci, cP, cm) {
var srcs = CryptoJS.enc.Utf8.parse(ci);
var key = CryptoJS.enc.Utf8.parse(cP);
var iv = CryptoJS.enc.Utf8.parse("0000000000000000");
var cn = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var cR = cn["ciphertext"]["words"];
var cg = cn["ciphertext"]["sigBytes"];
var cN = [];
for (var cX = 0; cX < cg; cX++) {
var cB = cR[cX >>> 2] >>> 24 - cX % 4 * 8 & 255;
cN["push"](cB);
}
return cN;
};
经过比较得到和浏览器一样的结果。
五、构建请求
经过上面的分析得到:
这里首先怀疑那个构没有比较的rsa部分。将那部分代码替换回原本的网页中的webpack打包的代码,并补上navigator部分的环境后,再次请求。可以得到请求了
当时当请求后面页数的时候可以看到是被拦截到的,这里凭借经验判断,应该是有调用次数的限制。于是这里尝试起一个node api接口测试一下。
当起了一个接口后再起发请求是可以获取剩下的数据的。
六、结束语
通过node api 的方式确实可以调用这个,但是超过5次,我想再次调用的时候就要重启服务,所以这里补充一种调用方式,这里经过测试后得到实际上这里要的也是E函数的调用次数,也是每次执行就循环到响应的次数即可。