之前我在写galgame中的逆向系列教程,最近突然想来点新鲜的,试试分析一下网络相关的逆向,想着可以把学习与折腾的心得和体会分享给大家。
网络逆向相比来说比较特殊,虽然js逆向上手后比起x64,arm64等机器码逆向要容易很多,但是依赖于服务器api,有着时效性与不可重复的特点,测试环境和相关的部署对于新手来说也很麻烦,网络协议相关的更是非常繁杂。因此,网络逆向对于新手来说门槛很高。本系列教程将结合几个例子,来谈谈我的理解与想法。同样,此系列教程也在隔壁同步更新,内容完全一样。
大家都熟悉油猴脚本了, 但是可能对于怎么编写可能感觉不太容易上手,本节将以显示b站楼层编号为例,结合简单的抓包,来谈谈如何上手油猴脚本。
需要的工具:
Chrome
调试脚本与网页抓包
Tempormonky
加载js脚本
fiddler
抓包
jQuery
查询dom元素与插入界面
firefox RESTClient
, python requests
测试发包
TrustForMe
解决安卓SSL Pinning无法抓HTTPS包问题
本例油猴脚本成品:b站显示楼层编号
动机:非常讨厌欢b站取消楼层号,就和写代码没有行号一样,不好定位,看起来非常不爽。
自从b站改版以来,我们发现网页版取消了评论楼层数的显示,但是旧版客户端却还能看到楼层数。因此我们推测有两种可能:
(1)返回的数据里还有楼层编号信息,但是在网页界面隐藏了
(2)采用新的api不再返回楼层编号信息
在评论处ctrl+shift+i
跳转到对应html元素,检查后发现没有楼层(floor)相关的信息,因此推测十有八九是新api本身就没有楼层了。
我们用chrome抓包来看看调用了什么api,F12->Network
可以抓包,点击initialor
可以查看调用关系(callback)。
我们看到获取评论用了GET方法,运用jsonp来进行跨域,我们调用的时候可一把jsonp和callback去掉。简单分析得到如下分析:
url: https://api.bilibili.com/x/v2/reply/
"oid": av号
"pn": 页码
"sort": 0 时间倒序;2 热度倒序
"type": 1 视频
Return: json对象, resp['data']['replies']为评论,里面没有floor参数
分析安卓版,需要xposed框架,安装TrsutForMe,否则抓不到https包。fiddler抓安卓包步骤为:
1 fiddler Tools Options 设置
HTTPS, 勾选"capture HTTPS", "decrypt https traffic", "Ignore server certificate errors"
Connect 勾选 "Allow remote computer to connect", "resuse client...", "reuse server ..."
fiddler设置完一定要重启fiddler才生效
2 windows防火墙添加fiddler允许
3 手机设置代理为pc的ip,如 xxx.xxx.xxx.xxx:8888
并访问此ip下载ca证书
4 xposed just trust me, TrustMeAlready
https的网站使用伪证书可以抓到,而在app里面同样的方法就抓不到用了SSL Pinning,
即SSL证书绑定,是验证服务器身份的一种方式,是在httpst协议建立通信时增加的代码逻辑,
它通过自己的方式验证服务器身份,然后决定通信是否继续下去。它唯一指定了服务器的身份,所以安全性较高。
同样也是Get获取,抓包后可以看到app端返回数据有floor,逐个测试去除不需要的参数,同理可以分析出来app端的api:
url: https://api.bilibili.com/x/v2/reply/cursor
"oid" : av号,
"max_id": 最大楼层数
'size': 返回信息条数
"sort": 0 时间倒序;2 热度倒序
"type": 1 视频
Return: json对象, resp['data']['replies']为评论,里面有floor参数
对于分析的api用python requests
或者firefox RESTClient
发包检查一下没问题。
我们刚才分析完了b站旧版api显示楼层编号api,现在还需要得到api的参数,这些参数往往在html上有体现。
比如说返回值有个rpid
,猜测是评论id,这个往往在页面上也有元素来定位,但是属性名不一定一样。我们随便看某条评论,ctrl+shift+i
查看html元素,发现属性值data-id
j就是rpid
。同理也可以把其他参数找出来,这里不再赘述。
获取各参数的jQuery如下:
相关api我们搞明白了,参数也已经搞清楚了,那么可以写js脚本简单测试一下了。
这时候可以先用chrome的snipplet
测试一下,这个调试起来比直接上油猴脚本方便一些,之后再用油猴脚本。
发送请求可以用$.get(url, params, (resp) => {})
,注意这个是异步的,可以用async
和promise resolve
封装一下,更加整洁避免回调地狱。
添加文本可以根据resp
里面的rpid
匹配html中的data-id
元素,然后prepend
楼层。
简单测试一下,大概是这种效果, 久违的楼层号终于出现了,太爽了。
到这里我们已经完成了主要的任务了,但是还有一个问题,我们这个脚本只是运行了一次,那每次切换页面都要手动点击运行,那么有没有办法自动进行呢?答案就是document.addEventListener("DOMNodeInserted",(event) => {}});
这个函数。在这个函数的回调函数中可以看到哪些页面变化,变化后的和上一次比较来判断是否切换页面。需要注意的是DOMNodeInserted
每个变化都会调用,需要用event.target
来筛选。
顺便一提,在监视target中海看到了插入了一条<script async src='...'/>
来提交异步加载请求,也可以根据这个来获取api参数。
另外,其实还有些具体问题需要优化,比如说如何知道某一页的max_id
值,这些就要参考replay\main
和replay\replay\cursor
等以前页面api了,但原理都差不多,此处不再追溯。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2020-7-11 16:00
被devseed编辑
,原因: