web逆向实操-5
无痕浏览器打开 https://match.yuanrenxue.com/match/5
打开network查看,第一个请求就有cookie了,说明是自己生成的。接下来查找cookie生成的地方
全局搜RM4hZBv0dDon443M没搜到,可能是是拼接的,或临时生成的
cookie钩子:用于定位cookie中关键参数生成位置
var org = document.cookie.__lookupSetter__('cookie');
document.__defineSetter__("cookie",function(cookie){
if(cookie.indexOf('RM4hZBv0dDon443M')>-1){
debugger;
}
org = cookie;
});
document.__defineGetter__("cookie",function(){return org;});
_0x3d0f3f[_$Fe] = 'R' + 'M' + '4' + 'h' + 'Z' + 'B' + 'v' + '0' + 'd' + 'D' + 'o' + 'n' + '4' + '4' + '3' + 'M=' + _0x4e96b4['_$ss'] + ';\x20path=/';
// 转换后是
_0x3d0f3f[_$Fe] = 'RM4hZBv0dDon443M' + _0x4e96b4['_$ss'] + ';\x20path=/';
document["cookie"] = 'RM4hZBv0dDon443M' + window['_$ss'] + ';\x20path=/';
搜索_0x3d0f3f[_$Fe] =
有6处,2处RM,4处m
1、找RM参数
全局搜_$ss
只搜到一处,没搜到。搜索_0x4e96b4或者给widow的_$ss
属性下hook
搜索_0x4e96b4
_$Ww = _$Tk[_$UH[0x2db]][_$UH[0x2dc]][_$UH[0xff]](_0x4e96b4['_$pr'][_$UH[0x1f]]()),
_0x29dd83 = _$Tk['A' + _$UH[0x32d]][_$UH[0x337] + _$UH[0x336]](_$Ww, _0x4e96b4[_0xc77418('0x6', 'OCbs')], {
'mode': _$Tk[_$UH[0x339] + _$UH[0x33a]][_$UH[0x2e5]],
'padding': _$Tk[_$UH[0x33b]][_$UH[0x33c] + _$UH[0x33d]]
}),
_0x4e96b4['_$' + _$UH[0x348][0x1] + _$UH[0x353][0x1]] = _0x29dd83[_$UH[0x1f]]();
// 转换后是
_$Ww = _$Tk["enc"]["Utf8"]["parse"](_0x4e96b4['_$pr']["toString"]()),
_0x29dd83 = _$Tk["AES"]["encrypt"](_$Ww,_0x4e96b4["_$qF"],{
'mode': _$Tk["mode"]["ECB"],
'padding': _$Tk["pad"]["Pkcs7"]
}),
_0x4e96b4["_$ss"] = _0x29dd83["toString"]();
// 还原后是。也可以直接用ob混淆解密帮忙查找
_$Ww = CryptoJS.enc.Utf8.parse(window._$pr.toString())
_0x29dd83 = CryptoJS.AES.encrypt(_$Ww,window._$qF,{...})
window._$ss = _0x29dd83.toString()
CryptoJS.enc.Utf8.parse:从UTF8编码解析出原始字符串
控制台打印CryptoJS.AES.encrypt可查看函数结构是 f (message, key, cfg)
RM参数需要两个值:_$pr
和_$qF
1、找_$pr
直接搜索。在第一处发现是个数组。
_0x4e96b4['_$pr'] = new _0x4d2d2c();
// 转换后
_0x4d2d2c = Array
然后在所有的push的地方打上断点,在控制台,分别输入实参和结果(亦可以hook push方法)
观察发现:它前四次的加密在同一个地方,但是第五次换到了另外一处
让程序跑完:
加密参数 m 的值,就是最后一次加密的时间戳
cookie字段m的值,就是最后一次函数调用的结果
2、找_$qF
_0x4e96b4['_$qF'] = CryptoJS['enc']['Utf8'][_$UH[0xff]](_0x4e96b4['btoa'](_0x4e96b4['_$is'])['slice'](0x0, 0x10));
// 转换后
_0x4e96b4['_$qF'] = CryptoJS['enc']['Utf8']['parse'](_0x4e96b4['btoa'](_0x4e96b4['_$is'])['slice'](0, 16));
全局搜索_$is
_$yw = _0x2d5f5b()[_$UH[0x1f]]();
_0x4e96b4['_$is'] = _$yw;
// 转换后
_0x4e96b4['_$is'] = _0x2d5f5b()['toString']();
全局搜索_0x2d5f5b
function _0x2d5f5b() {
return new _0x35bb1d()['valueOf']();
}
_0x35bb1d = Date
// 可得
_0x4e96b4['_$is'] = new Date().valueOf();
_$qF
的值是最后一个时间戳进行base64编码,取前16位作为AES的key值
2、找f参数
找到url,点击Initiator这一列,数据接口的这一行(有个 anonymous)
var list = {
"page": window.page,
"m": window._$is,
"f": window.$_zw[23]
};
看看 $_zw
在哪些地方进行了赋值,搜索找到第24行位置
$_aiding.$_zw.push($_t1);
打印 $_t1
,是这个值,搜 $_t1
let $_t1 = Date.parse(new Date());
至此,所有的参数都已知晓,剩下的就是抠代码了。
注意:加密函数里面有三个变量,需注意。
总结
1、找位置:全局搜或下钩子。拼接的参数名搜不到。可以hook cookie的set方法、Array的push方法、函数b等。
2、AES加密的函数结构是 f (message, key, cfg)
3、Initiator的使用
参考:第五题详解