郑重声明
- 郑重声明:本项目的所有代码和相关文章, 仅用于经验技术交流分享,禁止将相关技术应用到不正当途径,因为滥用技术产生的风险与本人无关。
1、首先通过抓包定位数据接口
-
url: aHR0cHM6Ly93d3cuemhpcGluLmNvbS93YXBpL3pwZ2Vlay9zZWFyY2gvam9ibGlzdC5qc29u
-
请求方式:get
-
查询参数:
{ 'scene': '1', 'query': 'Java', // 搜索关键字 'city': '100010000', // 城市id 'experience': '', 'degree': '', 'industry': '', 'scale': '', 'stage': '', 'position': '', 'salary': '', 'multiBusinessDistrict': '', 'page': '3', // 页码 'pageSize': '30' // 数据条数 }
-
请求头:
{ 'accept': 'application/json, text/plain, */*', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9', 'cache-control': 'no-cache', 'pragma': 'no-cache', 'referer': '......', 'cookie':'__zp_stoken__=c688eYS8QeXUiHj8Yf2Rabz9bXGglWUhQNj......', 'sec-ch-ua': '"Chromium";v="104", ......', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)......', 'x-requested-with': 'XMLHttpRequest', }
2、通过多次抓包观察,发现cookie: zp_stoken是动态的,在本地用python脚本请求测试,在携带zp_stoken请求时可以成功返回数据,当不携带时返回如下。可以确定某聘后端通过zp_stoken鉴权
{"code":37,"message":"您的访问行为异常.","zpData":{"name":"2330c665","seed":"yeROdSg9sLCvTjzFFPDXCN0reVByGx8sZwDJO1fD0E1Qut6cAZVP8iAst3Ed60eeTyd8AhJv869BpeO3xNZ7ug==","ts":1662174250665}}
3、在浏览器搜索zp_stoken定位到zp_stoken的生成位置,并打断点调试,注意观察 n是第2步返回的ts,t是第2步返回的seed。
单步调试进入一个混淆js文件,这个文件的文件名则是第2步返回的name。
4、将2330c665.js复制到本地,该文件有20000多行,使用了大量的流程平坦化混淆,数值常量混淆,unicode混淆,十六进制混淆,ASCll码混淆,代码膨胀混淆,使用AST简单解一下混淆,方便调试。
5、使用Proxy代理自吐一部分环境,因为boos要检测this等于window,而window被代理后window就不等于this了,就会走错误分支,所以只能选择硬刚调试。
function proxy(obj, name) {
return new Proxy(obj, {
get(target, propKey, receiver) {
let result = Reflect.get(target, propKey, receiver)
let resultType = typeof result;
resultType === 'undefined' ?
console.error('GET', name, propKey,
'return', resultType) :
console.debug('GET', name, propKey,
'return', resultType)
return result;
},
set(target, propKey, value, receiver) {
target[propKey] = value
console.trace('SET', name, propKey, value,
'return', true)
return true
},
});
}
windww = global;
window = proxy(window,'window')
6、通过调试发现 2330c665.js使用了大量的
- typeof 类型检测
- hasOwnProperty 属性检测
- 检测 top,self,this
- Buffer ,module node环境检测
- 检测代码是否格式化和源码是否被更改
- 检测navigator,document,window对象上的属性数量
- 检测 canvas webgl 指纹
- 我们调试时一般会打开异常捕获断点,某聘故意在代码中投放很多异常,增加耗时,利用时间模块检测耗时,如果被检测到耗时过久,就会触发内存爆破
- …
7、把各种环境补齐后,测试依旧不能100%成功,一定是哪里被检测到了,直接定位到cookie的最后生成位置,return Gjk(1517 - 1121, j);
发现 j 是一个数组,复制浏览器此处生成的 j 数组在本地i调用Gjk函数生成cookie是可用的,明显是这个数组有问题。
8、hook浏览器和本地的随机数模块和时间模块,使浏览器生成的zp_stoken固定( j 数组也会固定)
Math.random = function () {
return 0.5
};
Date.prototype.getTime = function () {
return 1662177494440
};
Date.prototype.now = function () {
return 1662177494440
};
对比本地生成的 j 数组的不同,一步一步逆向 j 数组的生成过程,配合浏览器不断对比,成功找到检测点,补齐环境后,携带生成的zp_stoken请求就能100%成功。