网站链接
aHR0cHM6Ly9oNS53YWltYWkubWVpdHVhbi5jb20vd2FpbWFpL21pbmRleC9ob21l
网站分析
紧跟上一篇文章,这次是x-for-with的参数加密逻辑,比起上一篇的token,难度要大一些。
首先搜索是搜索不出来这个x-for-with的,但因为是ajax加载的,所以我们可以在xhr里找逻辑,然后去下断点,发现是eval出来的js
经过分析最终定位到x-for-with加密的入口函数是这里
而参数e就是经过这两个函数处理后的值
因为是eval出来的js,而且e参数的值是变化的,那我们就需要找这个js是怎么eval出来的。
ps:其实这里还有个_()函数,控制台打印下就是字符串x-for-with,这就是为什么搜不到这个关键词的原因,因为他混淆了(不过不重要,这里知不知道都无所谓)
这里节省时间,就不踩着坑去走了,直接说最终的eval逻辑。
首先是源码中的一大串看不懂的东西,这个其实就是x-for-with参数加密的js源码加密后的密文(这句话是有点绕哈,说白了就是把js源码给加密了)
对应的解密函数也在源码中,紧跟着这个mieta标签的后面的script标签就是,太长了,截不全,凑合看看知道在那就行了
多刷新几遍会发现,这串js只有最后的这里的三个参数在变化
ps:这三个参数分别为上面mieta标签里的id,aes加密的key和iv,这个我们后面再说
把这个script标签下的所有内容都复制下来,格式化后放在本地,开始js代码的分析
js代码分析
补上window环境后,代码就可以运行了
把格式化后的代码拉到最下面,这里就是入口函数,参数分别有三个,mieta标签里的id,aes加密的key和iv(也就是上面说的那三个)
这里要注意下releasex这个方法前面要加window。还有,红框里的这一行,去获取了mieta标签里的content值,所以我们要先获取到这个值,然后再传进来,不能使用代码原有的写法。
修改后的代码如下:
window.meituan = function _r(metaId, key, iv, content) {
var keyb = window.releasex.util.convertStringToBytes(key);
var ivb = window.releasex.util.convertStringToBytes(iv);
var encryptedHex = content;
window.metaIdx = getKeys(encryptedHex);
encryptedHex = getRealSource(encryptedHex);
var encryptedBytes = window.releasex.util.convertStringToBytes(encryptedHex, "hex");
var aesCbc = new window.releasex.ModeOfOperation.cbc(keyb, ivb);
var decryptedBytes = aesCbc.decrypt(encryptedBytes);
var decryptedText = window.releasex.util.convertBytesToString(decryptedBytes);
var i;
for (i = decryptedText.length - 1; i > 0; i--) {
if (decryptedText.charCodeAt(i) > 31) {
break
}
}
return decryptedText.slice(0, i + 1)
}
直接调用window.meituan传入源码中获取到的metaId, key, iv, content,就能成功解密出我们想要的js源码
接着我们复制这段打印出来的js,格式化后发现就是上面eval出来的js
ps:这段js需要补上window,document,XMLHttpRequest,navigator环境,才能在本地运行
因为只有v函数里面的值是变化的,而且这几个if的结果都是true。
所以我们就需要按原逻辑去取出里面的值,拼接好这个code
最后修改后的加密入口函数如下
var p = window.XX = function(e, code) {
e.code = code;
e.cts = (new Date).getTime();
var r = JSON.stringify(e);
var t = 'jvzempodf8f9anyt';
var n = window.releasex.util.convertStringToBytes(t);
var i = window.releasex.util.convertStringToBytes(t);
var o = window.releasex.util.convertStringToBytes(r);
var a = window.releasex.padding.pkcs7.pad(o);
var u = new window.releasex.ModeOfOperation.cbc(n,i);
var c = u.encrypt(a);
var f = s(c);
return f
};
var w = window.EE = function (){return {
ts: (new Date).getTime(),
cts: (new Date).getTime(),
brVD: d(),
brR: l(),
aM: h(),
code: ""}
};
这里要注意的是releasex这个方法前面要加window,变量t是固定值
最后这样调用就能得到x-for-with的值了
console.log(window.XX(e=window.EE, code='刚才自己拼接的code'))
小结
这篇文章的难点在于js是eval出来的,而且eval出来的js里的某个方法里面的值还是动态的