1.查看接口
通过xhr记录排查找到该数据由此接口返回
2.查看调用
第一个记录点进去可知最终由此方法发送请求
直接打上断点刷新页面
查看调用参数发现并不是热评接口,直接放行本次调用。
经过几次放行,发现热评接口。
查看请求参数发现参数被加密
3.何时加密
查看调用栈,寻找未被加密前是什么参数。
当点击此调用栈发现加密前参数
向上点击查看,当进入此调用栈时参数被加密
可以确定参数在此方法处理后被加密,将i7b这个参数打上断点刷新页面
第一次查看接口并不是热评接口
放行直到热评接口出现
由图可知此时的data没有被加密
点击向下执行,直到发现参数被加密
由图可知这里的bWf7Y变量就是最终加密的参数,同时也能看出它是调用了asrsea
这个方法后被加密了
4.加密过程
由上面可知加密使用的就是window.asrsea
,直接搜索这个方法发现它指向了d
方法
可以看到定义的d
方法接收了4个参数分别是:d, e, f, g
,查看调用所用到的参数
参数d
就是将真实的参数序列化成字符串
参数e
调用bsG0x方法将返回值做为参数
搜索bsG0x方法查看定义
可以看到它返回一个字符串,因为加密调用bsG0x方法传入的是固定参数,此处可以直接在控制台执行这个方法,这个方法不管执行多少次都返回"010001"
。
所以e
参数即"010001"
在看f
它也是使用方法返回值做为参数,直接执行它。
由此可知f
就是"00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
因为它传入也是一个固定值,所以无论执行几次返回都是一样的值
最后一个参数g
不用看直接执行
由上面步骤可得4个参数值
d:序列化真实的参数这个参数不是固定值
e:"010001"
f:"00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g:"0CoJUm6Qyw8W8jud"
现在我们知道了d方法所需参数,现在回过头看d方法
function d(d, e, f, g) {
var h = {}
, i = a(16);
return h.encText = b(d, g),
h.encText = b(h.encText, i),
h.encSecKey = c(i, e, f),
h
}
d方法先定义一个空对象和i变量,i变量使用a方法返回值做为值(传入固定值16),查看a方法的定义
function a(a) {
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
for (d = 0; a > d; d += 1)
e = Math.random() * b.length,
e = Math.floor(e),
c += b.charAt(e);
return c
}
a方法主要做的就是返回16位随机字符串,for循环中的e变量就是生成随机数
Math.random返回介于 0(包含) ~ 1(不包含) 之间的一个随机数
然后对e取最大整数
Math.floor返回小于等于x的最大整数。
c就是拼接每次随机的字符,现在继续看d方法
function d(d, e, f, g) {
var h = {}
, i = a(16);
return h.encText = b(d, g),
h.encText = b(h.encText, i),
h.encSecKey = c(i, e, f),
h
}
可以看到d方法最终返回的就是h变量,先在h对象定义encText属性,第一次encText 使用b方法返回值做为值。
先看c方法,b方法后面说
function c(a, b, c) {
var d, e;
return setMaxDigits(131),
d = new RSAKeyPair(b,"",c),
e = encryptedString(d, a)
}
从d方法的调用就可以知道,c方法的a,b,c参数除了b和c是固定值,只有a每次不一样。
里面的setMaxDigits和encryptedString来自rsa插件,这里内部不做详解
打上断点查看a的返回值
本次随机了16位字符:OzxSbrV3WrPa6Qf7
现在看d方法中的h.encTex它第一次使用b方法传入d和g做为参数
function b(a, b) {
var c = CryptoJS.enc.Utf8.parse(b)
, d = CryptoJS.enc.Utf8.parse("0102030405060708")
, e = CryptoJS.enc.Utf8.parse(a)
, f = CryptoJS.AES.encrypt(e, c, {
iv: d,
mode: CryptoJS.mode.CBC
});
return f.toString()
}
a参数不固定就是序列化请求参数字符串后结果,b参数是固定值,d里面第一次给定的是g也就是
"0CoJUm6Qyw8W8jud"
b方法做的就是使用AES加密最后返回一个字符串,这里关于具体的AES加密算法和CryptoJS不做详解
这里的iv
就是指加密偏移量
mode
指的的是加密模式,这里使用的CBC
第二次还是使用b方法传入第一次加密结果和16位随机字符串
最后在h对象加入encSecKey属性,值来自c方法。
最终加密结果即h对象