js逆向
js逆向就是从网页的js找到加密的参数,实现破解加密,拿到cookie
微博登录案例
手动操作流程
- 访问首页https://weibo.com
- 输入用户名和密码
- 点击登录
- 如果有验证码,就输入验证码验证
- 成功跳转到微博首页面
1.请求分析
请求回的响应是否包含cookie,也即是看首页面的响应头中是否包含set-cookie。如果包含,那么这个请求是登录过程中必须的。经过查看,发现在首页面的响应头中,包含set-cookie,这个请求是登录的第一个请求。
2.寻找请求数据
第一次的请求
第二次的请求
观察data的变化,发现除了最后有个时间戳解决浏览器缓存之外,其他参数都是固定的。
nonce,pwencode,rsakv,以及sp的值都明确指明了参数被js加密了
一个servertime ertime 时间戳不管它,一个su,预测u就是username,一个sp,p应该是sp
3. 寻找加密的js
根据经验,在请求页面的html之后,还会去请求页面中的js,css,图片等信息。css,图片信息我们可以排除,一般情况,不会是登录的必须请求。一种常见的手法是,将后续请求需要用到的参数放到js中,然后通过js异步请求来完成登录。所以,我们在Network中过滤出所有的js请求。排除一些功能性的js,例如jquery之类,找出可能是参数的js。
https://login.sina.com.cn/sso/prelogin.php
这是一条jsonp的请求,其中包含了几个关键参数pubkey,nonce,rsakv,这是rsa加密用的参数
然后分析这个jsonp的请求data
现在要请求该url,拿到部分的加密数据,用session来访问
import re
import time
import json
import requests
session = requests.session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
})
# 1.请求首页面
session.get('https://weibo.com')
# 2.请求pre_login 获取参数
params = {
'entry': 'weibo',
'callback': 'sinaSSOController.preloginCallBack',
'su': '',
'rsakt': 'mod',
'client': 'ssologin.js(v1.4.19)',
'_': int(time.time())
}
res = session.get(url='https://login.sina.com.cn/sso/prelogin.php', params=params)
data = json.loads(re.findall(r'\((.*?)\)', res.text)[0])
print(data)
data就是上面的json数据
4.点击登录后请求的分析
先清空调试工具中的请求历史,然后勾选Preserver log和Disable cache,保证抓包的正确。
点击开发者工具Elements选项卡,点击左上角的选中按钮,然后用鼠标左定位页面中的登录按钮。
再点击开发工具窗口中的右边的子窗口,选中Events Listeners, 找到click事件,从而定位到js代码。
然后再点击,右边的js代码,会打开调试工具的sources窗口,它由3个子窗口组成,从左往右依次为,文件目录窗口,js代码窗口和调试窗口。
点击格式化后,js代码会自动跳到上面click监听时间执行的入口函数处
打好断点后,就可以开始调试了,点击登录按钮,js会暂停到刚才断点处
必须一步一步调试,知道找到关键代码,js调试需要极有耐心。头发就会慢慢掉的。
上面是常规做法。但是,我教你另一种情况,可以换另外一种方法定位。那就是如果你要找某个请求的触发函数,那么可以直接在networking选项窗口直接定位,这样不用一个个跳,因为看js真的让人头疼的事
输入错误密码,然后点击登录,请求的Initiator字段显示了,发送这条请求的发起对象
打上断点,然后进行调试。
然后点击登录
将代码往前,就会发现用户名和密码
在用户名和密码的加密函数在断点
现在就是想看makerequest中发生了啥?所以要一步一步调试
先到了变量e的生成
明显知道a 就是用户名,b 就是密码
这里参数就是在这里生成的,再往下看看
先对a进行了encodeURIComponent(a)
再往下跳回了base64
再跳去了base64生成函数中,
一个encode编码,一个base64
import base64
def encrypt_username(self):
'''
对账号进行base64加密
:return:
'''
return base64.b64encode(self.username.encode())
su 搞定,剩下sp
再往下看找 b 和sp
import rsa
from binascii import b2a_hex
def encrypt_password(self):
'''
对密码进行rsa加密
:return:
'''
result = self.per_login()
my_password = str(result['servertime']) + '\t' + str(result['nonce']) + '\n' + str(self.password)
publicky = rsa.PublicKey(int(result['pubkey'],16),int('10001',16))
return b2a_hex(rsa.encrypt(my_password.encode(),publicky))
总体思路
- su 是base64的编码
- sp 是rsa的公密钥加密 rsa的公密钥来自预请求的json中
- 还有一个时间戳要乘以1000 int(time.time()*1000)
- 用session 先获得预请求,拿到rsa的公密钥,在将su,sp加密,用post请求访问url
回复 【微博】 获取登录代码
来源:CSDN
作者:毛利学python
链接:https://blog.csdn.net/weixin_44510615/article/details/103609826