爬虫的两大难点: 1. 如何处理反爬 2. 如何处理巨大数据量
首先 js逆向 是反反爬的一种, 反爬还有图文,特征识别,验证码等问题。
js逆向 大多是处理 登录的信息验证,ajax 的 Fromdata数据提交 。
高级爬虫的效果就是,尽量去模拟真实用户去请求网站并获取数据,
js逆向也是,尽量仿真。
登录的信息验证为例,我们的练手网站有什么,所有的登录网站其实都可以拿来练手 https://zhuanlan.zhihu.com/p/90464269
需要模拟js逆向我们就需要一个能运行js代码的文件,我用的是乐意助手
然后还需要一个notepad++ 这个的功能有(帮我们快速定位函数的头尾,对于数据比较大的js可以快速查找)
那么进入今天的主题 (不想看实例的话可以直接到最下面看总结技巧)
- 抓包步骤
随便填写后按 f12 再点登录(这个步骤很重要可以过滤多余的包找login也快准) 我们就能抓到 login 的包,所有的登录网站都可以这样,我们仍在测试阶段,所以并不需要真的填写正确的账号密码信息,只是纯粹拿来抓包。
简单的网站可以一下子就找到了login的包,但反爬能力比较强一点或者页面比较大型的可能就不容易找到了,所以 养成习惯,直接筛选。
在这个包里面 jsonKey 就是我们要的 数据,接下来就是模拟了。
介绍如何破解前,建议大家还是去网上了解下比较主流的几种加密技术,这里简单介绍以下。
(入门的话我们能一看到 js 加密的数据,我们一看就知道是用了哪种加密,方便之后的全局搜索断点位置和直接网站解码定位真正的login包有巨大的帮助)
0.ASCII 七位二进制来表示
1.MD5加密算法(不可逆,压缩没大写)
import hashlib
print(hashlib.md5(b'nihao').hexdigest))
194ce5d0b89c47ff6b30bfb491f9dc26
2. DES加密算法
3. RSA加密算法(最有影响力的)
import rsa
# rsa加密
def rsaEncrypt(str):
# 生成公钥、私钥
(pubkey, privkey) = rsa.newkeys(123)
print("公钥:\n%s\n私钥:\n:%s" % (pubkey, privkey))
# 明文编码格式
content = str.encode("utf-8")
# 公钥加密
crypto = rsa.encrypt(content, pubkey)
return (crypto, privkey)
# rsa解密
def rsaDecrypt(str, pk):
# 私钥解密
content = rsa.decrypt(str, pk)
con = content.decode("utf-8")
return con
if __name__ == "__main__":
str, pk = rsaEncrypt("hello")
print("加密后密文:\n%s" % str)
content = rsaDecrypt(str, pk)
print("解密后明文:\n%s" % content)
4.IDEA加密算法
5. DSA加密算法
6.AES加密算法
7. Elgamal
8. Base64加密算法 (P343) (a-z A-Z 0-9)
import base64
key = b'nihao'
jiami = base64.b64encode(key)
# b'ZfR&?Zv' 85 (会多一些符号 > ~)
# b'bmloYW8=' 64 (太短的话会有=号)
# b'NZUWQYLP' 32 (太短的话会有=号)
# b'6E6968616F' 16
print(jiami)
jiemi = base64.b64decode(jiami).decode('utf-8')
print(jiemi)
9. SHA1加密算法
import hashlib
print(hashlib.sha1(b'This is a sha1 test!').hexdigest())
# 63d8242da8214b3028624397be3ee20f3f8e3372
10. PKCS加密算法
接上 好了接下来就是必走过程了。( 全局搜索,定位,断点,刷新调试,最后得到结果 )
按 Ctrl+Shift+f 就能找到这个界面然后填入 jsonKey
这里有个小技巧,适合全局搜索到很多 js文件 的情况下使用,我们下面会介绍到
点击 js 文件 格式化然后 Ctrl+f 再次搜索 jsonKey
这里只有这两处位置,这种就比较好找断点位置了
jsonKey:d 直接找到 d的声明 ( 不敢说所有编程,大多编程应该都是这样的吧,将对象赋值给另一个对象,首先得声明第一个对象 这里的 var d )
打断电后我们回到页面再次点击登录**( 登录页面的话千万不要按f5刷新,有时没有触发按钮就没有触发js文件,可能就断点不到了 )**
页面卡住然后出现了这种就证明成功断点了
断点后,我们将鼠标移到我们想知道信息的参数那里,我们就能知道了,如果是undefined的话 可能是僵尸参数,拿来迷惑我们的,又可能是程序没有运行到那个位置,所以还没有值,但我们要记住 undefined 在js中是一种类型,所以如果赋值参数需要的话我们还是要加进去的。这个后面会讲
b是我们的用户信息,然后调用了 JSON.stringify()这个方法将他整个json化 然后 再调用 crypto.Encrypt() 这个方法将他加密,( this大多情况下代表的是同一个 function 内部的定义调用 )
我们点击加密函数进入到了另一个位置
这里就很明显了,这个 Encrypt 就是我们要的加密函数过程了
我们将他复制到 能运行的 js 文件里,具体就是
然后我们就要分析我们 需要的东西是什么, getpwd这个函数里的 Encrypt我们有了 然后 Encrypt这个函数里我们就要找我们没有声明的几个函数
乐意助手里面包含了各种的加密js文档,我们可以直接调用
最后我们只要把c的函数名改一下就可以了
最后一步就是我们需要知道 b这个东西是什么了 我们在控制台中检测一下
这是原函数
控制台中检测
最后放入到函数中运行就得到了我们想要的东西了
最后验证对不对
至于为什么选择这种加载而不是在源代码里 不断断点测试呢,因为这个网站的加密js文档太大了,如果加密函数里参杂了其他东西的话我们不一定能运行出来。
这里的整个过程每一步其实都是测试,不断的测试得出结果,并不能一开始就知道他是哪个函数,怎么运行的。
第二个网站
同样的步骤,来到登录页面,然后抓包
我们需要知道 pwd geetest_challenge geetest_validate
这三个数据的获取过程
类似这种,后面两个其实都是在登录的时候,网页自动加载的
在上图中,最后那个ajax包里面就有了
另一个则在reset这个包里
后面直接复制 post就好了
我们讲讲这个pwd
也是一样 全局搜索 这次我们发现有很多个
这里就要用到我们的技巧1 js 逆向 永恒的定律 encrypt 我们直接搜索这个
发现第一个就是我们想要的
断点然后刷新运行
然后发现断在了这里 就代表我们没错了
修改后的模样
这里就有个小技巧了
(我们发现这些函数都是直接调用,而不像上面那个天安那样,引用再引用的,我们从这里就可以知道,这个加密的函数,大多都是独立的)
那么就是看看我们需要什么函数了
首先是 setMax这个 其实做多了就会发现,这个没什么用的
我们也可以直接删除 ,但这里为了模拟更像一点就不那么做了
然后就是 RSA
我们会发现 这个RSA函数 的js文件就是 RSA 所以这种我们可以将整个js文件复制下来
同样的 encrypt那个函数也在rsa里面
就像上面说的 加上这两个js文件的总代码函数也不超过3000行,所以这种我们大可以全部直接复制
然后回到乐意助手,我们加载函数发现缺少了个函数对象
我们找到这个函数
然后进入也是全部复制
最后得到了我们想要的 同样也是验证
这里只介绍了两个例子,后续文章会继续介绍
那么总结一下技巧
1.断点位置技巧(全局搜索 Encrypt 或者下面的)
'''
new JSEncrypt();
setPublicKey(pubKey)
return encrypt(pwd)
'''
2.抓包技巧,直接搜 login
3. 对于小代码量的 js 文档 且 函数不是引用再引用(函数都是独立一个的)可以将整个js文档复制下载运行
4. 在Console 控制台中检测我们的答案 看看是否一致
5. undifind 是一个类型 如果存在的话也需要复制进去