- import requests
- import ExecJS
- """
- 考虑思路:
- 1. 要模仿页面向后台请求数据, 首先要看点击按钮之后发生了什么, 他是怎么请求数据的, 咱就怎么模仿
- 抓包发现: 按钮绑定点击事件, 通过点击触发 ajax 以 post 的方式访问下面的 url, 参数为: data={d: xxx}, 参数, 响应均为 js 加密过的密文, 且参数是动态变化的
- 但是这种结果不是我们想要的, 因为一我们不会制作加密请求, 二我们没法解密人家的加密响应, 这没法搞了, 所及就解决这个问题
- 2. 既然它是通过 ajax 请求数据的, 那他的参数加密, 响应解密等过程肯定会跟他的点击事件存在一些联系, 我们只要找到他的点击事件, 然后顺藤摸瓜就可以了
- 通过 chrome 浏览器: 右键提交按钮来到开发者界面 --> Elements 标签栏页面 --> 下方右侧板块的 Event Listeners 标签栏中可以找到 click, 然后点击进去就可以查看到按钮绑定的点击事件了, 发现点击事件中执行了 getData()方法, 但这方法中没发现 ajax --> 却发现了 getAQIData(),getWeatherData()方法 --> 顺藤摸瓜 --> getServerData()
- 这方法在这个页面搜不到, 去全局抓包: 开发者界面切换到 Network 标签栏 --> 刷新一下页面, 重新获取包 --> 然后随便单击一个包, CTRL + F --> 左侧会弹出全局搜索框, 查找 getServerData()方法
- 结果发现找不到方法, 但是找到一堆含 getServerData 的加密乱码, 这就是 js 混淆, 复制这行数据, 去 http://www.bm8.com.cn/jsConfusion / 进行反混淆, 然后就能得到原始函数, 将其复制到本地 jsCode.js 文件
- 3. https://www.cnblogs.com/bobo-zhang/p/11243138.html 分析函数结构
- getParam(method, object): 加密参数的方法
- decodeData(data): 响应解密的方法
- 好了, 有了这两个函数, 我们就可以干活了, 私以为不用像老师一样在 jsCode.js 文件中创建一个函数再调用 getParam 方法,
- 因为他那个函数里啥都没干, 就是把数据加进 dict 中, 作为 getParam 的参数进行调用了, 感觉十分鸡肋, 这个工作 py 也可以干呀.
- 涉及知识点:
- js 加密: 服务端客户端之间传输的是密文(非 https 加密, 因为我们抓包是拿到客户端已经收到的数据, 此时已经解密了)
- js 解密: 还是通过加密的方法进行反解密
- js 混淆: 对前端 js 代码逻辑进行加密保护, 防止不法分子直接获取我们定义的重要数据及用来跟后端进行数据交互的函数等
- 要区分 js 加密和 js 混淆, 一个是保护数据的传输, 一个是保护前端页面的代码逻辑
- js 反混淆: 目前只提到了暴力破解 js 混淆: http://www.bm8.com.cn/jsConfusion/
- js 逆向: 在 py 文件中执行 js 代码
- 使用 PyExecJS 模块 (环境依赖: nodejs) 来实现自动逆向
- """
- node = ExecJS.get()
- url = '某空气质量分析平台'
- headers = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ApplewebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
- 'Cookie': 'UM_distinctid=1710631a776670-015f735f9b0e96-f313f6d-144000-1710631a777cb1; CNZZDATA1254317176=1080600571-1584942473-|1585191130'
- }
- # data
- method = 'GETCITYWEATHER'
- # city = '北京'
- # wea_type = 'HOUR'
- # start_time = '2018-01-25 00:00:00'
- # end_time = '2018-01-25 23:00:00'
- data_dic = {
- 'city': '北京',
- 'wea_type': 'HOUR',
- 'start_time': '2018-01-25 00:00:00',
- 'end_time': '2018-01-25 23:00:00',
- }
- # Compile JavaScript
- file = 'jsCode.js'
- ctx = node.compile(open(file, encoding='utf-8').read()) # 操作模式默认为'r'
- # Get locked data
- # JS = f"getPostParamCode('{method}','{city}','{wea_type}','{start_time}','{end_time}')" # 老师的方法, 私以为没必要
- JS = f"getParam('{method}', {data_dic})"
- # 上面的格式化必须用引号包起来, 你想想如果不包起来的话, 数据替换进去之后是不是:"getPostParamCode(北京, HOUR, ...)"
- # 不管你是什么类型, 放进去就是整个字符串的一部分, 那执行完 eval 方法之后呢? 是不是北京就飘红报错了, 哪有这么写 str 的. 所以逻辑要捋清楚
- data = ctx.eval(JS)
- # print(data)
- # 发起 post 请求
- session = requests.Session()
- response_text = session.post(url=url, headers=headers, data={'d': data}).text
- # print('>>>', response_text)
- JS = f'decodeData("{response_text}")'
- unlocked_data = ctx.eval(JS)
- print(unlocked_data)
来源: http://www.bubuko.com/infodetail-3478762.html