以下内容仅交流学习,请勿用于非法用途
如果你现在想模拟登陆知乎,会发现 fromdata 是一串加密的字符串
看了之后是不是很痛苦?你是不是就想使用 selenium 来模拟登陆?不过好像知乎对 selenium 也进行了相应的反爬处理,哈哈。但是我不也想用 selenium,效率太慢了,直接破解 js 才是我最喜欢挑战的。好,我现在教你如何用 js 硬撸破解,废话不多说,直接进入正题。
1. 找出signature加密
加密位置这个相对来说是比较难找的,需要自己对那些混淆过的 js 进行一遍又一遍的搜寻,有时候你看到头皮发麻也不一定找得到,再加上这个加密参数是一堆字符串,连个键都没有,搜索的条件都没有。这怎么办呢?我们可以去百度或者谷歌看看前人是怎么搞的。
你直接搜索知乎模拟登陆的话,会发现以前的知乎的 fromdata 是键值形式的,有以下键值对
顺便也可以看看之前的破解思路,看到了上面的 signature 是通过加密来的,猜测知乎应该也是对之前的键值加密的 fromdata 进行加密的,在控制台搜搜 signature 看看有没有线索
提示:按下 ctrl + shift + f 可出现搜索框
一搜,果然有,看了看,signature 的加密过程和以前的还是一样的,证明我的猜想正确了,说明是通过之前的 fromdata 的键值对进行加密成的一堆字符串,现在就看看 signature 是如何加密的。
如果你对加密有点了解的话,还容易知道通过上面代码知道,很容易知道是通过 hmac 加密,哈希算法是 sha1,密钥为 d1b964811afb40118a12068ff74a12f4,加密数据有四个,为 clientId、grantType、timestamp 和 source,这些值都可以在上面通过调试出来的,就不多说了,如下
2. 找出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 的加密方法。
3. 找出 fromdata 加密位置
如果你是第一次找这个,估计你得不断地翻 js,也不一定能找得到,或者你可以根据下面这个调用函数过程来找
会发现很多,不过你懂套路的话都知道加密一般都用到 encrypt 名字之类的,可以直接根据这个名字搜
一搜果然有这个,通过查看你很容易就找到这个
这个一通过调试,你可以看到,我们的加密字符串出来了,是不是很激动,我当时找到了这个的时候激动不得了。
这个是加密的字符串
这个就是我们需要找的
历尽千辛万苦,终于找出了庐山真面目,激动不?先不要激动先,这只是加密的位置,后面的才是最难的!
4. 找出 fromdata 加密的所有方法
知道位置后,我们可以直接把这个加密的 js 方法都扣出来,放在一个 html 文件内执行就好。
在上面找出位置之后,很容易就可以看到这个完整的一个的加密方法
按这个半括号向上找,你就可以找到一个完整的加密方法,这个就是整个 fromdata 的加密方法,挺容易找的,如果觉得不方便找的,可以先将这个 js 文件里面的代码复制下来,然后到 Sublime Text 软件上找,这个可以折叠,也比较容易找,找出来是这样子
格式化之后有 400 多行,而且全是混淆,难看得一批。
为了看看这个正确不正确,我们可以把函数里面的内容直接拿出来,就是去掉最外层的函数,然后调用下面的函数 Q,把我们的 fromdata 传进去
最后将上面的 JavaScript 给弄成一个 html 文件,放在 script 标签内即可
格式就和上面一样,然后直接用浏览器上打开这个 html 文件,你会看到这个
这个就是我们一直努力在找的 fromdata 加密字符串。
弄完这个之后,我们继续使用 python 来操作了,因为这个 加密的方法格式化之后有 400 多行,实在太多,也全都是混淆,如果想用 python 来实现的话也不是不可能,就是成本太大了,需要的时间太多了,我们还不如直接使用 python 的 execjs 来执行 JavaScript 代码直接获得就可以了,这个简单方便。
(我们除了使用 execjs 来执行,还可以使用 selenium 运行这个html 文件也是可以的,但是我并不想用 selenium 这个工具,还是喜欢折腾,所以忽略了,想用的可以试试。)
但是这里又会有一个问题,我们用浏览器打开的是为它提供了一个浏览器的运行环境,我们在 python 使用的 execjs 提供的是 node 环境,两个环境的不一样,就会产生不同的效果,下面我们可以选择使用 webstorm 编辑器来提供 nodejs 环境来进行尝试以下。
5. 在 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 算是大功告成了,接下来就是登陆验证下我们搞得这个加密对不对了。
6. 模拟登陆知乎
这个知乎的登陆也是坑满满,我也给踩了几个,这个就直接说坑吧,其他的就不多说了。
我只是用手机号来登陆的,也可以用邮箱登陆,过程都差不多的。
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.
你还想要?没有了,坑暂时只有这么多,最后给你们看下登陆成功的结果
7. 写在最后
这个登陆折腾了差不多一周了,实际来说可能是三周,因为从刚开始看不懂 js 代码,就跑去学了两周 js,现在总得来说 js 也可以说上手了,以后或许也会使用 nodejs 搞点爬虫,挺好玩的。
至于代码,暂时不公布了,如果你一步一步按照我方法来弄的话估计也可以,前提的有 js 基础最好,以后会公布的,等我再完善先,因为还需要干别的东西。如果有问题也可以找我,加我微信 june--98 拉你进群讨论即可。
折腾这个,掉了不少头发,但听说分享点赞是生发之道,所以你们懂的!