如何搞定知乎模拟登陆的加密难题?

640?wx_fmt=gif

如何搞定知乎模拟登陆的加密难题?_第1张图片

作者 | sergiojune

责编 | 郭芮

声明:以下内容仅交流学习,请勿用于非法用途。

如果你现在想模拟登陆知乎,会发现 fromdata 是一串加密的字符串:


如何搞定知乎模拟登陆的加密难题?_第2张图片


看了之后是不是很痛苦?你是不是就想使用 selenium 来模拟登陆?不过好像知乎对 selenium 也进行了相应的反爬处理,哈哈。但是我不也想用 selenium,效率太慢了,直接破解 js 才是我最喜欢挑战的。


好,我现在教你如何用 js 硬撸破解。废话不多说,直接进入正题。



640?wx_fmt=png

找出signature加密



加密位置这个相对来说是比较难找的,需要自己对那些混淆过的 js 进行一遍又一遍的搜寻,有时候你看到头皮发麻也不一定找得到,再加上这个加密参数是一堆字符串,连个键都没有,搜索的条件都没有。这怎么办呢?我们可以去百度或者谷歌看看前人是怎么搞的。


你直接搜索知乎模拟登陆的话,会发现以前的知乎的 fromdata 是键值形式的,有以下键值对:


如何搞定知乎模拟登陆的加密难题?_第3张图片


顺便也可以看看之前的破解思路,看到了上面的 signature 是通过加密来的,猜测知乎应该也是对之前的键值加密的  fromdata 进行加密的,在控制台搜搜 signature 看看有没有线索:


如何搞定知乎模拟登陆的加密难题?_第4张图片

提示:按下 ctrl + shift + f 可出现搜索框


一搜,果然有,看了看,signature 的加密过程和以前的还是一样的,证明我的猜想正确了,说明是通过之前的 fromdata 的键值对进行加密成的一堆字符串,现在就看看 signature 是如何加密的。


如何搞定知乎模拟登陆的加密难题?_第5张图片


如果你对加密有点了解的话,还容易通过上面代码知道这是通过 hmac 加密,哈希算法是 sha1,密钥为 d1b964811afb40118a12068ff74a12f4,加密数据有四个,为 clientId、grantType、timestamp 和 source,这些值都可以在上面通过调试出来的,就不多说了。如下:


如何搞定知乎模拟登陆的加密难题?_第6张图片



640?wx_fmt=png

找出fromdata的完整键值对



在知道 signature 是如何加密的之后,我们还需要找出完整的 fromdata 先,不过在上面的调试中,你会发现也有几个 fromdata 值,但是不全。


如何搞定知乎模拟登陆的加密难题?_第7张图片


这时候如果我们得继续搜索 signature 的话,找了一整天你都会发现不到什么线索,这时候我们可以通过登陆的 url 进行突破,看看 url 是哪个路径,然后一顿搜。


其登陆url是 https://www.zhihu.com/api/v3/oauth/sign_in。那我们可以直接搜 sign_in 试试。搜了发现和上面的 signature 是在同一个 js 文件上的,感觉应该有戏。


如何搞定知乎模拟登陆的加密难题?_第8张图片


这个和登陆地址完全匹配,应该就是这个了,可以进行调试一波:


如何搞定知乎模拟登陆的加密难题?_第9张图片


这不出来了,经过多次调试,发现大多数值都是固定的,只有 signature 和 timestamp 不是,其他的就是账号密码之类的,还有个验证码 captcha 以及它的类型 lang,signature 上面的已经找出来了,timestamp 很明显就是时间戳,其他的就不多说了。


现在的 fromdata 已经全部找出来了,我们离加密字符串又近了一步,如果你直接用这个表单进行模拟登陆,会给你返回下面错误


 
   

Missing argument grant_type


可见我们还得找出这个 fromdata 的加密方法。



640?wx_fmt=png

找出 fromdata 加密位置



如果你是第一次找这个,估计你得不断地翻 js,也不一定能找得到,或者你可以根据下面这个调用函数过程来找:


如何搞定知乎模拟登陆的加密难题?_第10张图片


会发现很多,不过你懂套路的话都知道加密一般都用到 encrypt 名字之类的,可以直接根据这个名字搜:


640?wx_fmt=png


一搜果然有这个,通过查看你很容易就找到这个:


640?wx_fmt=png


这个一通过调试,你可以看到,我们的加密字符串出来了,是不是很激动,我当时找到了这个的时候激动不得了。


640?wx_fmt=png

这个是加密的字符串


640?wx_fmt=png

这个就是我们需要找的


历尽千辛万苦,终于找出了庐山真面目,激动不?先不要激动先,这只是加密的位置,后面的才是最难的!



640?wx_fmt=png

找出 fromdata 加密的所有方法



知道位置后,我们可以直接把这个加密的 js 方法都扣出来,放在一个 html 文件内执行就好。


在上面找出位置之后,很容易就可以看到这个完整的一个的加密方法:


如何搞定知乎模拟登陆的加密难题?_第11张图片


按这个半括号向上找,你就可以找到一个完整的加密方法,这个就是整个 fromdata 的加密方法。挺容易找的,如果觉得不方便找的,可以先将这个 js 文件里面的代码复制下来,然后到 Sublime Text 软件上找,这个可以折叠,也比较容易找,找出来是这样子:


640?wx_fmt=png


格式化之后有 400 多行,而且全是混淆,难看得一批。


为了看看这个正确不正确,我们可以把函数里面的内容直接拿出来,就是去掉最外层的函数,然后调用下面的函数 Q,把我们的 fromdata 传进去:


如何搞定知乎模拟登陆的加密难题?_第12张图片


最后将上面的 JavaScript 给弄成一个 html 文件,放在 script 标签内即可:


如何搞定知乎模拟登陆的加密难题?_第13张图片


格式就和上面一样,然后直接用浏览器上打开这个 html 文件,你会看到这个:


如何搞定知乎模拟登陆的加密难题?_第14张图片

这个就是我们一直努力在找的 fromdata 加密字符串。


弄完这个之后,我们继续使用 Python 来操作了,因为这个加密的方法格式化之后有 400 多行,实在太多,也全都是混淆,如果想用 Python 来实现的话也不是不可能,就是成本太大了,需要的时间太多了,我们还不如直接使用 Python 的 execjs 来执行 JavaScript 代码直接获得就可以了,这个简单方便。

我们除了使用 execjs 来执行,还可以使用 selenium 运行这个html 文件也是可以的,但是我并不想用 selenium 这个工具,还是喜欢折腾,所以忽略了,想用的可以试试。

但是这里又会有一个问题,我们用浏览器打开的是为它提供了一个浏览器的运行环境,我们在 Python 使用的 execjs 提供的是 node 环境,两个环境的不一样,就会产生不同的效果,下面我们可以选择使用 webstorm 编辑器来提供 nodejs 环境来进行尝试以下。


 

640?wx_fmt=png

在 node 环境调试加密代码



你可以拿上面的 JavaScript 代码在 webstorm 运行,你就会看到:


 
   

TypeError: __g._encrypt is not a function


如何搞定知乎模拟登陆的加密难题?_第15张图片


所以我们需要调试,需要把那些在浏览器上只有的对象,比如 window、navigator 之类的对象给弄掉,从而在 node 上用不用的代码代替相同的效果即可。


要调试我们先要找到代码运行的开端,可以很容易找到:


如何搞定知乎模拟登陆的加密难题?_第16张图片


可以看到,这里它会先去判断有没有 window 这个对象来判断是不是在浏览器上面运行的,所以我们可以直接把它修改成 true 或者其他表示成 true 的值都可以。


如何搞定知乎模拟登陆的加密难题?_第17张图片


再次运行,可以看到这个错误:


 
   

ReferenceError: atob is not defined


如何搞定知乎模拟登陆的加密难题?_第18张图片


这个 atob 是将 base64 加密的字符串给解密,在 node 环境下是没有这个方法的,我们需要使用 Buffer.toString()替代即可。


如何搞定知乎模拟登陆的加密难题?_第19张图片


运行之后,还是报这个错误:


 
   

TypeError: __g._encrypt is not a function


注意:这个是大坑,估计一般人每个一两天还搞不定,这个是因为上面的解密的,但是上面的并不一样,你可以在上面的两个函数加断点,分别在浏览器和 node 环境下运行,可以看到解密的数据是不一样的,是因为在浏览器上的 base64 加密的是 binary 编码,解密之后也就同样需要使用 binary 编码。这个是我在知乎的资源文件上搜索 atob 这个方法,然后慢慢查找看到的,当时也差不多心态崩了,还好坚持下来了。而我在 node 环境下解密之后使用了默认的编码,所以解密的数据出错了。当我们加上 binary 编码之后,再运行:


如何搞定知乎模拟登陆的加密难题?_第20张图片


这时,错误不再是上面那个了,变成了另一个,证明解密正确了,再来看看下面这个错误:


 
   

execption at 11: ReferenceError: window is not defined


原来是 window 对象惹的祸,这个时候就需要我们伪造 window 对象了,至于怎样伪造呢,我们可以调试出错的地方,看看它使用了什么方法,就直接使用适合 node 运行的相同效果的代码代替就可以了,经过多次调试,需要我们伪造 window 和 navigator 这两个对象,下面就是伪造之后的代码:


如何搞定知乎模拟登陆的加密难题?_第21张图片


这个时候再运行看看:


640?wx_fmt=png


可以看到成功了,上面的红色字是一个提示,关于 Buffer 的,这个我们忽略就行,接下来就可以使用 Python 环境进行测试了。


如何搞定知乎模拟登陆的加密难题?_第22张图片

640?wx_fmt=png


果然,都出来了,哈哈,注意需要先安装 PyExecJS 库,自行安装,然后在测试的时候记得导入 execjs 即可。现在这个 fromdata 算是大功告成了,接下来就是登陆验证下我们搞得这个加密对不对了。



640?wx_fmt=png

模拟登陆知乎



这个知乎的登陆也是坑满满,我也给踩了几个,这个就直接说坑吧,其他的就不多说了。


我只是用手机号来登陆的,也可以用邮箱登陆,过程都差不多的。


1. 网址的请求头


请求登陆的网址的请求头需要带上这几个:


如何搞定知乎模拟登陆的加密难题?_第23张图片


不带 content-type 的话,会给你返回这个错误:


 
   

Missing argument grant_type


不带 x-zse-83 的话,会给你返回这个错误:


 
   

请求参数异常,请升级客户端后重试


至于 agent-user 那就更不需要说了。


2. 请求顺序


知乎这个登陆是首先请求验证码地址,看需要不需要填写验证码,如果需要填就再请求一次,而且还需要再再请求一次查看是否输入验证码正确,不正确就重复上面步骤,当不需要填写验证码的时候就可以直接请求登陆网址了。


还有上面的三次请求的验证码地址的请求方法都是不一样的,哪种方法自行调试即可。


3. 验证验证码


在验证验证码的时候请求头的 content-type 不要填写值为 multipart/form-data,如果填了请求验证码的时候会给你返回这个错误:


 
   

{"error":{"message":"Missing argument input_text","code":400}}


它的意思是说没有带上验证码验证,当我们去掉的这个字段的时候,就可以验证了。


验证验证码的时候请求头只需要有一个 user-agent 就可以了。


4. 请求的所有阶段带上 cookie


知乎这个有个 cookie 值是验证码票据,是从第一次请求验证码地址来的,就是下面这个:


如何搞定知乎模拟登陆的加密难题?_第24张图片


如果不带 cookie请求或者请求顺序不一样都有可能给你返回这个错误:


 
   

{"error":{"message":"缺少验证码票据","code":120002,"name":"ERR_CAPSION_TICKET_NOT_FOUND"}}


5.XXX


你还想要?没有了,坑暂时只有这么多,最后给你们看下登陆成功的结果:


如何搞定知乎模拟登陆的加密难题?_第25张图片



640?wx_fmt=png

写在最后



这个登陆折腾了差不多一周了,实际来说可能是三周,因为从刚开始看不懂 js 代码,就跑去学了两周 js,现在总得来说 js 也可以说上手了,以后或许也会使用 nodejs 搞点爬虫,挺好玩的。


如果你上面看不懂不要紧,可以先去学习下 js,推荐大家去廖雪峰的官网看 JavaScript 教程,写得蛮不错的。


至于代码,暂时不公布了,如果你一步一步按照我方法来弄的话估计也可以,前提的有 js 基础最好。


折腾这个,掉了不少头发,但听说转发是生发之道,所以你们懂的!

作者:sergiojune,一个热爱折腾Python的学者。本文为作者投稿,首发于作者个人公众号日常学python,版权归对方所有。



 热 文 推 荐 

☞ 华为 5G 硬实力

☞ Java 开发者希望未来使用 Python 和 Go

“边缘计算将吞掉云计算!”

☞ 18 岁少年盗取价值 90 万元的萌乃币, 交易所被迫关停!

李笑来登顶 GitHub TOP 榜!币圈大佬要教程序员如何自学编程

☞ 马云:蚂蚁金服这样做区块链!

女生适合做程序员吗?

Google首页玩起小游戏,AI作曲让你变身巴赫

曝光!月薪 5 万的程序员面试题:73% 人都做错,你敢试吗?

 
   

System.out.println("点个在看吧!");
console.log("点个在看吧!");
print("点个在看吧!");
printf("点个在看吧!\n");
cout << "点个在看吧!" << endl;
Console.WriteLine("点个在看吧!");
Response.Write("点个在看吧!");
alert("点个在看吧!")
echo "点个在看吧!"

640?wx_fmt=png 喜欢就点击“在看”吧!

你可能感兴趣的:(如何搞定知乎模拟登陆的加密难题?)