Mac使用Charles抓取macOS/iOS/Android数据包
Table of Contents
Charles抓包原理
抓包的原理
要想抓一个系统(macOS/iOS/Android)的数据包(即网络请求),你必须让该系统的所有请求都经过Charles,这样Charles才能从经过自己身上的所有请求中过滤出(即抓到)你想要的请求。那怎样才能让一个系统的所有请求经过Charles呢?答案是:代理!
Charles启动后,会监听一个或两个端口,此时它就是一个“代理服务器”,我们只需要把你要抓包的系统的代理设置为Charles的ip和端口即可。
对于macOS来说,因为Charles就在本机,所以代理ip是127.0.0.1,而对于手机来说,ip就是你运行Charles的那台电脑的局域网ip(按住option键,单击macOS上的WIFI图标即可看到它的ip),端口的话,在启动Charles之前是可以设置的,下面会说到。
监听一个或两个端口
在Charles顶部菜单的proxy
→proxy settings
→http proxy
或socks proxy
中设置这一个或两个端口(如下图)
http proxy
和socks proxy
是两个不同层级的代理,http proxy
是应用层的,它只能代理http/https/websocket请求,而socks proxy
是代理传输层流量的,用到非http类协议的软件,就需要socks proxy
来代理,所以一般来说需要把socks proxy
勾上(HTTP Proxy前面是没有勾的,因为它是必须开启的)。
启动后我们使用lsof-i:xxx
(xxx是端口号)来检测一个端口是否被占用,可以看到,8888和8889端口被Charles占用(也就是说Charles在监听这两个端口的数据)
关于科学上网
在使用Charles时请先关闭科学上网工具,否则有可能会冲突,至于既要使用Charles又要科学上网的方法,后面这里有说到。
抓取macOS(本机)的请求
在mac上安装根证书(用于支持https抓包)
点击顶部菜单栏中的help
→SSL Proxying
→Install Charles Root Certificate
上一步点击Install Charles Root Certificate
后它会自动打开钥匙串,显示Add Certificates,不用任何修改,直接点add
即可添加
双击证书→在弹出的窗口中点Trust(信任)
左侧的三角箭头展开Trust选项→选择Always Trust
(始终信任),然后直接关闭窗口(没有保存按钮,也不用点保存,直接点关闭窗口即可,关闭时它会弹出要输入系统密码以把这个更改保存到系统中,输入密码后点击Update Settings(更新设置)
即可,然后就可以把钥匙串窗口关掉了)
在Proxy
→SSL Proxy Settings
里,要把*:443
加上(如果没有的话),*
表示任何ip,:443
表示443端口,因为443端口是https的端口,所以要允许,否则无法抓取https的包
设置监听端口和自动设置代理
在proxy
→proxy settings
→macOS
里,把所有都勾上,那么每次启动的时候,Charles会自动把自己的代理端口设置到系统代理设置里面去
当然在启动之后,你还可以通过点击proxy
→macOS proxy
来切换系统是否走Charles代理。
其实它设置的原理,就是在系统偏好设置
→网络
→选中当前使用的网卡→点击右下角高级
→代理
里设置(如下图),也就是说,你也可以手动设置
前面说“选中当前使用的网卡”,一般是WiFi,如果你是用扩展坞(转接头)插网线上网的,那就选择对应的有线网卡即可。
开始抓包
上面全部配置好,随便刷新一个网页,在Charles里看,应该就能看到请求了(看不到请一步一步对一下,看漏了哪里,实在不行关掉Charles再开看看)
抓取iPhone手机的请求
安装根证书
这里说的很清楚,配置你的设备以使用Charles作为它在http://192.168.0.102:8888
的代理,然后用iPhone的Safari浏览器访问这个地址chls.pro/ssl
来安装证书。
根据上面所说的,我们在iPhone的设置
→无线局域网
点右边那个¡
点击配置代理
选择手动
,然后填写Charles提示的IP和端口,注意,ip和端口不要照填我的,上面Charles弹出的那个提示框里有你自己的ip和端口。
点击存储
保存,保存后mac上的Charles会提示有一个链接试图连接Charles,这个就是手机的链接,这时当然要允许,即点左边的Allow(允许)
按钮。如果你不小心点了Deny
(即拒绝),你可以在顶部菜单proxy
→Access Control Settings
里自己添加
允许之后,iPhone打开Safari浏览器,输入前面Charles提示的地址:chls.pro/ssl
,然后根据提示一步一步安装证书。
点击允许
点击右上角的安装
(2020.10.16注:在iOS14中发现需要自己去设置
→通用
→描述文件
里找到下载的描述文件,点击安装)
输入密码
点击安装
点击右上角的完成
开始抓包
手机随便打开一个app或网页,随便点一下,即可看到Charles抓到的请求(但是网页或app接口不能是你电脑本地的)
设置调试本地网站
前面说了,抓包不能抓本地网站或接口,其原因是,本地域名是直接在hosts文件中指定的,公网DNS是找不到这个域名的,所以我们要手动指定,mac可以直接在hosts文件指定,但iOS是不可能修改hosts文件的(除非越狱),那怎么办呢?还好,Charles提供了这个功能。
在Charles的Tools
→Spoofing
里,可以添加DNS映射(如下图),由于iPhone所有请求都代理到了Charles,所以Charles想把某个域名指向哪个ip,它就可以指向它(同样可以用于在线上的但域名还没生效的网站)
增加:据测试,其实直接改电脑里的/etc/hosts
也是可以的,因为手机的请求代理到电脑后,网络也走电脑的,DNS解析自然也会走电脑的。
另外不使用的时候手机要关闭代理,否则会上不了网(离开你办公室后),或者很慢(因为请求被Charles抓包了,肯定比较慢)。
还有,其实不安装证书直接设置代理也是可以的,只是这样就只能抓http的包,https的就抓不了,而现在大多服务都用https了,所以还是要安装证书!
抓取Android手机的请求
安卓与iPhone完全一样,但有些浏览器可能无法安装证书,遇到这个问题可以换换浏览器。
手机使用pac
忘关代理无法上网问题
你可能遇到过这种情况:手机用WIFI怎么也上不了网,但用流量就可以。于是你怀疑WIFI是不是有问题,但是你电脑用的也是同一个WIFI,或者问其它人连的也是这个WIFI,都没有问题,那说明也不是WIFI的问题。
然后你找了好久,卧槽,原来是因为测试接口抓包的时候把手机设置代理到电脑的Charles上,忘记关掉了,于是你把它关掉就可以上网了,但是下次测试接口又得重新设置代理,搞来搞去特别麻烦。
解决忘记关代理的方法
事实上我们使用自动代理,就可以实现“即使忘了关代理也不会上不了网”。自动代理是让配置文件决定要不要代理,配置文件我们叫pac文件(pac: proxy auto config),后缀也是.pac
结尾。
直接在手机的代理里选择自动代理
,然后填入pac文件地址即可(如下图)
现在有两个问题
- 1.PAC文件怎么写?
- 2.PAC文件地址如何获取?
PAC文件怎么写?
pac文件是用js写的,它有很多预定义的函数(查看),最终决定是否走代理的是下边这个函数,网络请求会根据这个函数的返回值来判断是否走代理
function FindProxyForURL(url, host) {
return 'DIRECT';
}
返回值一定是一个字符串,它有几种值:
DIRECT 不走代理
PROXY 192.168.1.232:8888 走http或https代理
SOCKS 192.168.1.232:8889 走传输层代理
SOCKS5 192.168.1.232:8889 走传输层代理
这些代理方式可以串联起来,用分号;
隔开,比如:
return "PROXY 192.168.1.232:8888; SOCKS5 192.168.1.232:8889; SOCKS 192.168.1.232:8889; DIRECT";
上边这句的意思是先走PROXY 192.168.1.232:8888;
,即http(s)代理,如果这个代理不通,它会走下一个,下一个再不通,它再下一个,直至最后的DIRECT
,DIRECT表示直连,不走代理。
上边的SOCKS5和SOCKS其实相当于是同一个,SOCKS5的5是指版本,现在所有的SOCKS代理都是用这个版本了(毕竟比较新),而用SOCKS的原因,是因为据说Safari浏览器是不识别SOCKS5关键字的,不过Safari一样是用SOCKS5协议的,只不过关键字要写成SOCKS而已。
PAC文件还支持其它函数,如果你需要使用,可以自己上网查,我这边目前用不到其它函数,所以就不介绍了。
下边是我自己使用的PAC文件,用于手机/pad等,把你需要走代理的域名填到下边“要走代理的域名”数组里,则手机访问这些域名时就会走你指定的代理,否则会直连(效果跟没有设置PAC代理一样)
var direct = 'DIRECT';
//代理的ip
var lan_ip = '192.168.1.232';
//代理的http(s)端口和socks端口
var http_port = 8888;
var socks_port = 8889;
//最终返回的代理字符串
var proxy = 'PROXY ' + lan_ip + ':' + http_port + '; SOCKS5 ' + lan_ip + ':' + socks_port + '; SOCKS ' + lan_ip + ':' + socks_port + '; ' + direct;
//alert(proxy)
//要走代理的域名(二级或三级域名)
var local_dev_host = [
"www.test.com",
"picuploader.com",
];
var local_dev_obj = {};
for (var i = 0; i < local_dev_host.length; i += 1) {
local_dev_obj[local_dev_host[i]] = true;
}
function host2domain(host) {
var dotpos = host.lastIndexOf(".");
if (dotpos === -1)
return host;
// Find the second last dot
dotpos = host.lastIndexOf(".", dotpos - 1);
if (dotpos === -1)
return host;
return host.substring(dotpos + 1);
};
//FindProxyForURL函数用于最终返回代理字符串
function FindProxyForURL(url, host) {
//alert(JSON.stringify(local_dev_obj));
var level2domain = host2domain(host);
var proxy_cmd = (local_dev_obj[host]!==undefined || local_dev_obj[level2domain]!==undefined) ? proxy : direct;
//alert(proxy_cmd);
return proxy_cmd;
}
PAC文件地址如何获取?
很简单,使用nginx配置一个访问地址即可,但是却分本地和线上。
如果你在本地电脑配置,最好不要用域名,而是直接用ip。因为用域名还要自己指定DNS,但由于手机不方便设置DNS(特别是iOS),所以还要使用Charles来设置,我实测在本地电脑可以直接访问到,但在手机上访问不知道为什么要输入电脑的账号密码,这样肯定是没法用的,因为我是在浏览器里测试访问需要账号密码,但是你直正设置到代理里是没有地方让你输入账号密码的,但是不输入账号密码又无法访问,所以相当于这种方法是不行的。
如果你是本地,我建议你本地设置一个默认的localhost域名,并且localhost可访问目录autoindex on;
,这样只要你把前面的pac代码保存成proxy.pac
文件并放到root
关键字指定的目录中(我这里是/Users/bruce/www
)即可用http://192.168.1.232/proxy.pac
来访问(其中192.168.1.232
是我电脑的ip,你换成你电脑的ip就行)
server {
listen 80 default_server;
server_name localhost;
charset utf-8;
access_log /usr/local/var/log/nginx/localhost.access.log;
error_log /usr/local/var/log/nginx/localhost.error.log;
root /Users/bruce/www;
autoindex on;
autoindex_exact_size off;
#显示格式,默认为html,另外还可以为xml/json/jsonp
autoindex_format html;
#是否显示当地时间(不设置默认off,off则显示UTC时间)
autoindex_localtime on;
location / {
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
include fastcgi.conf;
}
}
说实话我不推荐本地,因为本地经常有可能因为电脑睡眠了手机就上不了网了,国内的话其实gitee上放个proxy.pac应该也是没问题的,不一定需要有自己的服务器。
如果你有外网服务器,我建议你用外网服务器来搭一个pac文件访问地址,因为这样手机可以不依赖于电脑,一直可以获取该文件。
把前面的pac代码保存成proxy.pac
文件,并放到/path/to/pac/
目录下,然后使用以下nginx配置即可(把域名和root路径换成你的),浏览器访问http://pac.example.com/proxy.pac
即可访问到该文件,浏览器测试访问没问题后把它填到前面说的pac代理里即可
server {
listen 80;
server_name pac.example.com;
default_type application/x-ns-proxy-autoconfig;
access_log /path/to/pac.example.com.access.log combined buffer=1k;
error_log /path/to/pac.example.com.error.log error;
root /path/to/pac;
location = /proxy.pac {
try_files $uri /proxy.pac;
}
}
最后,要特别注意,使用pac时不要开启科学上网软件(如果你手机有的话),否则我们设置的PAC会失效。因为代理软件会把手机系统的请求全部设置成走到它上边去,我们自己设置的PAC路径就不会被使用,所以就会导致用不了。
其它参考:
PAC自动代理文件格式,教你如何写PAC文件
PAC 文件及其调试
Charles与科学上网工具同时使用
对科学上网原理稍微了解一点的童鞋,应该知道,科学上网客户端的“全局模式”、“pac模式”、“手动模式”,还有后来的什么“清除系统代理”、“自动配置系统代理”、“不改变系统代理”等等,无论它是什么名字,都只是叫法不同,其实就是一个设置代理的快捷菜单,它本质就是对系统的网络代理选项进行设置,也就是说,即使不用这些菜单,你也可以手动设置.
点击系统偏好设置
→网络
→选择当前使用的网卡(如WIFI)→右下角高级...
→选择代理
选项卡(如下图所示)
由于Charles和科学上网工具两者都是对系统的代理进行设置,所以肯定会冲突,所以在使用Charles时,你需要先关闭你的科学上网工具(如果你有的话),否则可能会有导致你无法抓包。
当然其实是可以开着的,两者其实是相互覆盖的,比如你正在用着科学上网工具,你一打开Charles,Charles就会把系统代理设置到Charles监听的端口里,这时你肯定就无法科学上网了。如果你再调一次科学上网工具的代理模式(比如从自动模式调到全局模式),又或者关一下再开一下科学上网软件,则它会把系统的代理设置到它身上,Charles就会失效。
有些人可能会说,我既想用Charles,又想科学上网怎么办?我想用Charles抓包的接口,就是google的,就是facebook的,怎么办?其实是可以的,只需要从Charles再设置一个代理即可,用业内术语来说就是“套娃”。
首先要把科学上网工具的代理模式设置成“手动模式”或“清除系统代理”(新版本改成这个了)模式,然后在科学上网工具里找到http和socks监听端口是多少,然后取消再重新勾选一下Charles的proxy
→macOS proxy
(为了让Charles重新接管系统的网络代理,因为前面设置科学上网软件的代理模式时,它是会覆盖Charles的代理设置的)。
Charles接管代理后,点击Charles的proxy
→External Proxy Settings
,然后在弹出的窗口中勾选一下Use External Proxy Servers
然后勾选下边的三个代理出口,并分别填上科学上网工具对应的ip和端口,一般来说,ip肯定就是127.0.0.1了(当然如果你用路由器做科学上网的话,那么这个ip就是你路由器的ip,比如有可能是192.168.1.1
,这得具体看你路由器ip)。而对于端口,HTTP和HTTPS的端口是一样的(事实上科学上网工具是不区分HTTP和HTTPS的),只有SOCKS端口不同,你在你的科学上网工具里找到对应监听的端口,把它填到下边的对应位置里即可
- Web Proxy(HTTP)
- Secure Web Proxy(HTTPS)
- SOCKS Proxy
其实就相当于多加了一层,我们来对比一下使用Charles前后,科学上网的变化:
使用Charles前:浏览器→科学上网客户端→外网
使用Charles后:浏览器→Charles→科学上网客户端→外网
可以看到,使用了Charles后,浏览器的请求先给Charles,再由Charles交给科学上网客户端,浏览器的请求怎么给Charles呢?就是在系统偏好设置
→网络
→找到对应网络(如WIFI或有线)→右下角高级
→代理
里面设置的。而Charles再转发给科学上网工具,就是前面说的,在Charles的proxy
→External Proxy Settings
里设置。
结束使用Charels时,需要把科学上网软件重新设置一次自动代理模式(或者全局模式)才能让科学上网软件重新起作用,否则有可能无法科学上网,我之所以说“有可能”,是因为目前我这里测试的情况是,我关掉Charles或者在proxy
→macOS
里把勾去掉,它会自动切换回科学上网的代理,可以说是非常自动,我估计是Charles在设置前就保存了之前的设置吧,反正如果无法正常抓包,记得检查一下代理是否设置正确就行。