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

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

作者 | sergiojune

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

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

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

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

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

找出signature加密

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

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

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

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

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

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

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

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

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

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

找出fromdata的完整键值对

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

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

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

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

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

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

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

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

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

Missing argument grant_type

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

找出 fromdata 加密位置

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

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

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

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

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

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

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

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

这个是加密的字符串

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

这个就是我们需要找的

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

找出 fromdata 加密的所有方法

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

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

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

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

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

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

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

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

最后将上面的 JavaScript 给弄成一个 html 文件,放在>

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

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

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

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

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

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

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

在 node 环境调试加密代码

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

TypeError: __g._encrypt is not a function
如何搞定知乎模拟登陆的加密难题?

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

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

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

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

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

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

ReferenceError: atob is not defined
如何搞定知乎模拟登陆的加密难题?

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

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

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

TypeError: __g._encrypt is not a function

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

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

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

execption at 11: ReferenceError: window is not defined

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

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

这个时候再运行看看:

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

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

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

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

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

模拟登陆知乎

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

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

1. 网址的请求头

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

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

不带 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 值是验证码票据,是从第一次请求验证码地址来的,就是下面这个:

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

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

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

5.XXX

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

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

写在最后

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

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

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

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


分享到:


相關文章: