通用抓包
抓包通常有两个目的,查看和修改,如果是只查看旁路嗅探即可,而要修改(含丢弃)则通常要插入链路中间,也就是说要让数据穿过我们的抓包工具,下面列下会用到的包分析工具:
- wireshark类:优点是能解析各种数据包,缺点是无法修改。通常只是用它做数据包分析,含本地和外部流量抓取,数据包解密,这个不多说。
- 插桩类:直接在代码里插桩(含二进制),自己写分析代码
- http类:如burp suite/charles/fiddler everywhere (根据这篇文章实现破解)/...
证书安装
android
首先是下载证书,不管是burpsuite/fiddler/Charles,都是先导出证书(也可以在代理时访问对应的url下载:chls.pro/ssl/http://burp)
接着是安装,简单描述下,安卓里的证书分系统和用户两类,应用通常在协商时会根据AndroidManifest.xml中的networkSecurityConfig配置来决定使用(信任)哪些证书,比如低版本默认都使用,高版本默认只使用系统证书,而应用还能更进一步设置只信任指定证书,即证书固定,一些插件可被用于绕过证书固定,不多说,回到安装,这里分为两阶段:
1.android 7.0之前直接安装(打开设置 > 安全性 > 凭证存储 > 从存储空间安装)
2.android 8.0 ~ android 9.0需要允许未知来源,然后有锁屏才行(设置 > 安全性 & 屏幕锁定 > 加密与凭证 > 安装证书),此时系统默认不再信任用户安装的证书了,需将其安装为系统级证书:
openssl x509 -inform DER -in burp.der -out burp.pem # 需要格式为pem
openssl x509 -inform PEM -subject_hash_old -in burp.pem | head -1 # 获取hash值
mv burp.pem <hash>.0 # 必须重命名为上一步的hash值
adb push <hash>.0 /sdcard/
adb shell
mv /sdcard/<hash>.0 /system/etc/security/cacerts/ # 放在对应位置
chmod 644 /system/etc/security/cacerts/<hash>.0
上面的过程可通过一些magisk插件自动完成,例如AlwaysTrustUserCerts/Magisk-MoveCACerts/MoveCertificate等。
如果上面的过程执行失败,可能是由于android 10以上,/system分区是只读挂载没处理好,可通过如下命令处理:
# 直接重新挂载
mount -o rw,remount /system
# 使用bind mount去改,需在zygote启动前,或许不用孵化器直接启动也可?
mkdir /data/local/tmp/bind_mounts
cp /system/etc/hosts /data/local/tmp/bind_mounts/
mount -o bind /data/local/tmp/bind_mounts/hosts /system/etc/hosts
即时设置了系统证书,应用也可能不会使用,可使用JustTrustMePlus/JustTrustMe绕过ssl证书检查。
注:据说chrome只信任有效期少于825天的证书,如果以后遇到证书有效期太长的错误再改吧
mac
直接打开钥匙串就可以导入证书,信任它即可。
ios
ios可以直接安装证书,只是需要注意它安装的是描述文件,最简单的方式是直接下载,如:
-
在wifi里配置http代理
-
直接访问
chls.pro/ssl/http://burp安装描述文件 -
通用->描述文件 安装描述文件
-
通用->关于手机->证书信任设置,打开
harmony
鸿蒙Next目前可以直接信任证书,路径是 安装根证书:推进去(pem格式),安装
抓包
android
系统代理类
即直接使用android系统提供的代理机制,可在系统的Wi-Fi或蜂窝网络中设置,更简单的是用adb:
# 设置
adb shell settings put global http_proxy 192.168.0.33:8080
# 删除
adb shell settings delete global http_proxy
adb shell settings delete global global_http_proxy_host
adb shell settings delete global global_http_proxy_port
reboot
# 更简单的删除方法
adb shell settings put global http_proxy :0
应用默认会使用系统的代理设置,当然它可以选择不使用(Proxy.NO_PROXY)。这种方式应用能感知,还有一种,通过设置DNS来配置虚假服务器,将流量转走,像burp等需要开启透明代理功能,监听原始端口(如80/443),这种通用性与隐蔽性会更好。
iptables类
android使用Linux内核,自然也支持netfiler框架,其在网络数据包处理的的各个阶段插入钩子来实现对数据包的过滤、修改、转发等功能,手机厂商也会使用它实现各种功能,比如统计、限制流量使用等。在用户态我们使用iptables去配置和管理netfilter,它们之间通过netlink通信,iptables命令操作分三个部分:
1.表(Table):iptables主要由四个表组成:
- filter表:用于基本的包过滤功能,决定哪些包能通过
- nat表:用于网络地址转换(NAT),改源/目的地址的
- mangle表:用于修改数据包的某些字段(如TTL、TOS等)
- raw表:用于数据包免于连接追踪
2.链(Chain) :每个表包含多个链,链是规则的集合,数据包在经过链时会依次匹配规则。如NAT表含三个链Prerouting、Output、Postrouting分别用于入站前、本地数据包出站前、所有数据包路由决策后三个位置的处理
3.规则(Rule) :规则定义了如何处理匹配的数据包,例如ACCEPT、DROP、REJECT、RETURN等。
netfilter的处理流程如下:

- 数据包进入内核:数据包通过网卡进入内核,首先被送到 PREROUTING 链。
- PREROUTING链处理:在PREROUTING链中,Netfilter会根据规则决定是否进行DNAT(目标地址转换)。
- 路由决策:如果数据包的目标地址是本地系统,则进入 INPUT 链;如果是转发到其他系统,则进入 FORWARD 链。
- INPUT链处理:在INPUT链中,Netfilter会根据规则决定是否允许数据包进入本地系统。
- FORWARD链处理:在FORWARD链中,Netfilter会根据规则决定是否转发数据包。
- OUTPUT链处理:在OUTPUT链中,Netfilter会根据规则决定是否允许本地进程生成的数据包离开系统。
- POSTROUTING链处理:在POSTROUTING链中,Netfilter会根据规则决定是否进行SNAT(源地址转换)。
- 数据包离开内核:经过所有链的处理后,数据包最终被发送到目标系统
所以我们可以直接在NAT表的OUTPUT/POSTROUTING链上加一个规则,将流量转发到目标设备上去。首先去burp上监听80/443端口,并在这些端口上开启透明代理,再在手机上设置下:
1.直接执行iptables -t nat -A OUTPUT -d 0.0.0.0/0 -p tcp -j DNAT --to 192.168.197.134将所有流量转发到mac上
2.使用dns解析去将特定流量转发过来
iptables -t nat -A OUTPUT -d 0.0.0.0/0 -j DNAT --to 172.20.10.5
下面也是一些常用的命令:
# 转发tcp/udp的所有源/目的到172.20.10.5
iptables -t nat -A OUTPUT -d 0.0.0.0/0 -j DNAT --to 172.20.10.5
# 只转tcp / udp的流量
iptables -t nat -A OUTPUT -d 0.0.0.0/0 -p tcp -j DNAT --to 192.168.199.129
iptables -t nat -A OUTPUT -d 0.0.0.0/0 -p udp -j DNAT --to 192.168.199.129
# 只转到443端口的tcp的流量
iptables -t nat -A OUTPUT -d 0.0.0.0/0 -p tcp --dport 443 -j DNAT --to 192.168.105.99
# 将quic转发到另一个端口
iptables -t nat -A OUTPUT -p udp --dport 443 -j DNAT --to-destination 192.168.86.91:8081
iptables -t nat -A POSTROUTING -p udp --dport 443 -j MASQUERADE
# 在支持ipv6时,可能一些数据会使用ipv6通信,这需要ip6tables,而有时内核没编相关模块,最简单的就是禁用它
echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6
echo 1 > /proc/sys/net/ipv6/conf/default/disable_ipv6
其实proxydroid也是使用的iptables,它在赋予root权限后做了一样的事,将流量转发到本地的代理(如redsocks)再转发出去。
注:其实nftables更现代,能同时支持ipv4和ipv6,然鹅很多安卓没编译它,所以先忽略吧~
vpn类
VPN类不需要ROOT权限就能转发所有流量,它是由Android 的 VpnService API 实现的,该API可创建一个一个虚拟网络接口(TUN)并将设备所有流量全部重定向到这个接口上,再由它转发到指定位置。PCAPdroid就是一个支持VPN抓包的APP,不过它是内置了mitmproxy去响应。还有很多其他普通APP支持VPN,如利用wireguard转发流量,在电脑上用mitmproxy做更精细化的处理。
注:VPN可以工作在数据链路层(TAP)和网络层(TUN),这里是TUN哦
tcpdump类
直接下载Android tcpdump,运行抓包,可使用ns去限定抓包应用,抓包后用wireshark分析。不过它更多是用来排错的,比如为啥抓不到包,为啥连不上网~
HOOK类
通常需要root权限,要不就是运行在容器里或重打包。
- ecapture:直接使用ebpf从网络栈拿到原始数据,通过uprobe在用户态hook获取密钥信息,可作为通用型的抓包工具
- r0capture:它也是直接hook底层的ssl库,不过使用的是frida。
ios
系统配置类
和安卓类似,可以直接设置代理或者fakedns。
vpn类
直接使用wireguard等vpn将流量重定向到mitmproxy等。
harmony next
Wi-Fi里设置代理,不过应用可能不用它,FakeDNS会更好用
mac
mac当然可以使用ios支持的那些方法,这里再列出两种它多出来的:
pf类
packet filter是BSD提供的网络层防火墙机制,也是mac还在广泛使用的,它支持策略路由和NAT,可以用来实现类似iptables的效果:
sudo pfctl -d
sudo sysctl -w net.inet.ip.forwarding=1 # 开启转发 和Linux一样
sudo sysctl -w net.inet6.ip6.forwarding=1
# 新建conf文件,编写转发规则
nat on en0 from utun3:network to any -> (en0) # SNAT 将 utun3 的流量通过 en0 转发
rdr pass on en0 inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080 # DNAT 将发往 en0 接口的 HTTP 流量重定向到本地的 127.0.0.1:8080
sudo pfctl -f /usr/local/etc/pf-nat.conf -e # 启动服务
sudo pfctl -vnf /usr/local/etc/pf-nat.conf # 验证规则正确性
网络框架扩展类
mac现在已经不允许普通开发者开发内核扩展了,但新增了系统扩展功能,其中的网络扩展(Network Extension)框架就能被用于强制流量重定向,可以编写相应软件。不过一般都是直接使用proxifier。
骚操作
- 可利用arp欺骗直接把流量导入到电脑
- 可利用软路由/电脑直接设置热点来抓全部流量
特定应用
Chrome
方法如下:
1.导入证书,协议降级:如果默认就是用RSA协商则可以只导入证书,若用DH协商则需要先降级(服务端/客户端能降哪个降哪个,降服务端需客户端支持)
2.DUMP SSL KEY LOG:这取决于是否实现该功能,比如chrome/firefox设置环境变量即可,其他工具可能通过调用(hook)ssl库激活该功能,像mitmproxy直接在启动时指定环境变量MITMPROXY_SSLKEYLOGFILE=/Users/xiaojun/xxxx.log (也可以在代码中指定,但需要在初始化mitmproxy库之前,否则默认不会生效)
3.应用层HOOK:直接hook解密后的数据,比如利用epbf实现,也可以自己去hook特定软件,但得弄成wireshark好分析的格式
安卓上的chrome需要特殊对待,它同时信任系统和用户证书,但是对于系统证书它还会进行CT校验,这一步是通不过的,所以要抓包最好把它装成用户证书!
BXX
都说要先阻止长连接,直接搜LongLink可发现在com.xunmeng.basiccomponent.titan.api.helper下存在ApiNetChannelSelector类,它用于决定一个请求是否通过长连接走,因此直接hook该类里的判断函数即可强制不走长连接。
YZ
分两步,一个是它有强制证书校验,另一个是QUIC,都是在libsscronet.so里,之前可以直接去掉这个文件或禁用org.chromium.CronetClient.tryCreateCronetEngine强制降级,但效果并不好。通常是用patch/hook so来做,对前者找证书校验的点强制返回0,后者就是强制打破QUIC,比如在SetQUICHint/AddQUICHint等处pass。
这里特别提下,它使用了cronet,这本来是chromium的网络栈,后来被谷歌提出来作为一个库供其他app使用(也是Google Play的一部分),它的特点就是高效,且支持HTTP3,所以在抓包上会有些特别,对此还有种降级方式就是直接把UDP禁了。
FB
也是直接禁用SPDY去降级mtopsdk.mtop.global.SwitchConfig.isGlobalSpdySslSwitchOpen
解包
抓到tls的明文后,数据最好是可读格式(如json),但很可能是被编码、压缩、加密的,这里接触常见的编码方式:
1.protobuf:这是最常见的编码方式,遇到后先试试用它能不能解析就对了
2.bson:即binary json,在monggodb🥭里出现的
3.messagepack:也是一种二进制编码格式,比pb信息多,比bson省空间
4.语言自带序列化协议:如PHP的phar,Python的pickle,Java...等,特征就是会有一些类名啥的
其它
协议补充
之前最常见的是http1.x,它的升级版是websocket,spdy,后者后来升级为http2了,它们都是基于TCP的。而最近越来越多使用了QUIC,它是谷歌开发的基于UDP的传输层协议,它集成了TLS1.3去提供高效安全的传输,而HTTP3是基于QUIC的。

不是所有软件都支持http3,目前已知burp和mitmproxy是支持的,不行就降级吧!
抓包检测
在抓包时,需注意客户端和服务端可能会检测是否正在被抓包,通常是检测是否存在中间人/是否配置了代理,容易被忽略的:
1.使用JA3等指纹:中间人方案需要重新打包tls流量,JA3通常存在差异,需保持一致,如burp可使用burp-awesome-tls。类似的还有http的指纹。
2.额外的操作:例如burp可能默认勾着unpack gzip/deflate in response会导致客户端直接接收到解包后的数据
3.检测代理:直接看是否设置了全局代理/VPN