知乎的首页加密就这一个,流程比较简单,带大家全流程逆向x-zse-96这个参数
重新发一遍,之前那个流程我只补了一个window,然后我就去试了一下首页,结果是能拿数据,还以为自己补对了,其实是服务器根本没验,前几天有粉丝找上来让我爬评论,结果一试发现不行,然后我马上就把这篇文章下了.
现在有空重新梳理一下流程,前面几部都大差不差,关键是后面函数的补环境.
网址:aHR0cHM6Ly93d3cuemhpaHUuY29tLw==
目录
篇幅较长,坐稳发车咯!
声明
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!
x-zse-96参数分析
总结
1打开知乎首页,往下滑,先抓一个包
2载荷里没有加密, _token应该是一个token令牌,维持登陆的
3再来看头部,多翻几页可以发现x_zse_81是不变的,可以先固定,另一个参数x_ab_pb也可固定
4先全局搜索x-zse-96,不行的话可以hook头部或者下xhr
5可以发现能搜索到两个,全部打上断点后往下滑,断住后把另一个取消掉
6控制台输出一下,发现就是这个结果,此时只需要分析E,可以往上找
7控制台输出一下可以发现E就是这个加密的结果
8从内到外一次输出结果,可以发现是f()这个函数加密s成32位的密文再经Z(r).encrypt加密成最终结果的,32位可以先尝试一下是不是md5,验证一下发现是标准的md5
9 c4c是经典的md5加密字符串1,这样就可以省去扣算法的时间了
10接下来分析s,全部补上后发现少了V这个方法
var o = "101_3_3.0"
, i = "AGDYBfhvGBaPTn-gL72IY3suWqNIoKC34tE=|1672377086"
, a = "3_2.0aR_sn77yn6O92wOB8hPZnQr0EMYxc4f18wNBUgpTQ6nxERFZBXY0-4Lm-h3_tufIwJS8gcxTgJS_AuPZNcXCTwxI78YxEM20s4PGDwN8gGcYAupMWufIeQuK7AFpS6O1vukyQ_R0rRnsyukMGvxBEqeCiRnxEL2ZZrxmDucmqhPXnXFMTAoTF6RhRuLPF03CYCo8bUr8JCxKIGoBpJL_0qCqoTcOhDVY2Cwf2AHmrT29nwwf_vNGODoTvMSL_JL_yhp9bLH1riwLgDoCurXOXhH9EhSskggLfXL82UHqXD3OtDe_RBN0SALLkUxLAcH_8_oM0gVCICt8-upfg9w0LJSCP9cKTwN1s0N_QiU_LJSxCqfz10XL0JOykGHLeiO06DNBogo10BgMfBLmTuFMHbeMuwO_0GY_BRo_0cpCNqtpSXCGKDxmquOm2B3KYCwYKC2m-hOGLUpY9Gg_Twe919LqF9LYwheLuBCC"
, u = "/api/v4/commercial/ecommerce"
, c = '{"urls":["https://xg.zhihu.com/plugin/c8aa5b5253475b97fd4c8696ae6d3cd8?BIZ=ECOMMERCE","https://xg.zhihu.com/plugin/c8aa5b5253475b97fd4c8696ae6d3cd8?BIZ=ECOMMERCE"],"type":"answer","os":"other","url_token":"2721767583"}'
, s = [o, u, i, V(c) && c, a].filter(Boolean).join("+");
11把V补上后可以发现s可以生成
V = function(t, e) {
return void 0 === e && (e = 4096),
!!t && function(t) {
return new Blob([t]).size
}(t) <= e
}
12接下来就是扣Z(r).encrypt这个方法了
13进去这个方法发现它是属于一个模块内部的方法
14往上找把整个模块扣下来在node里调试
16运行一下应该会报一个__g._encrypt不是一个方法,其实是缺少了浏览器环境导致js走错了
这里我用的是jsdom补环境,需要安装jsdom这个库,直接调用npm命令就行了
npm install jsdom
17再补上以下环境,不要直接粘贴,把地址换了
const dom = new JSDOM(`Hello world
`,{url:"https://www.脱敏.com/"});
window = dom.window
location = window.location
navigator = window.navigator
document = window.document;
history = window.history;
screen = window.screen;
18补完发现可以生成结果,但是带上这个参数的请求是拿不了数据的,还缺了环境
19回到浏览器里,可以发现多次加密同一组数据竟然结果不同,可能是时间戳,也可能是随机数,试着hook了一下随机数,发现结果不变了,证明是随机数的问题,可以在node里hook随机数再调试,直到出现和浏览器一样的结果
20直接运行结果不一样,也没有任何提示,可以加上proxy代理再调试,代理我补瑞数的时候有讲
21这里断在了document.toString这个方法,浏览器里返回的是'[object HTMLDocument]',node里返回的是[object Object]
22可以在原型里修改这个方法
let xxx = Object.prototype.toString
Object.prototype.toString = function () {
if(this.constructor.name === 'Document') {
return '[object HTMLDocument]'
}
return xxx.call(this, arguments)
}
23可以发现这个错误解决了,但结果还是不对
24请提前安装canvas这个包,不然会报少包的错误,尽量使用这个命令,普通的npm命令可能装不上
npm install canvas --canvas_binary_host_mirror=https://registry.npmmirror.com/-/binary/canvas
25装好后把以下代码加到上面的if的后面
else if(this.constructor.name === 'CanvasRenderingContext2D') {
return '[object CanvasRenderingContext2D]'
}
26再次运行断在了window._resourceLoader,浏览器里是undefined,把这个补上后再次运行
27刚才那处已经过了,这次断在window._sessionHistory,浏览器也是undefined,接着补上
28断在了global这里,node的全局变量是global,浏览器里面没有global,参考了一下其他大佬的文章,应该是缺了一个alert = window.alert
29旧版本的有这个报错提示,新版本的好像没有
再次运行,断在了__proto__
30这里其实是再次对tostring进行了了检测,打印一下发现是大Window的问题
let aaa = Function.prototype.toString
Function.prototype.toString = function () {
console.log(this)
console.log(aaa.call(this,arguments))
return aaa.call(this, arguments)
}
32补上最后的环境
let aaa = Function.prototype.toString
Function.prototype.toString = function () {
console.log(this)
console.log(aaa.call(this,arguments))
if(this.name === 'Window') {
return 'function Window() { [native code] }'
}
return aaa.call(this, arguments)
}
1出于安全考虑,本章未提供完整流程,调试环节省略较多,只提供大致思路,具体细节要你自己还原,相信你也能调试出来.
2本人写作水平有限,如有讲解不到位或者讲解错误的地方,还请各位大佬在评论区多多指教,共同进步.技术探讨加v lyaoyao__i(两个_,本人)
3本篇分享到这里就结束了,欢迎大家关注下期,我们不见不散☀️☀️