很多搞客户端开发的朋友第一次接触抓包,都是从“电脑开热点、手机连Wi-Fi、Charles里填代理”这套流程入手的。等你在真实环境里帮同事查过几次接口问题就会发现,Wi-Fi代理方案远没有教程里那么岁月静好:公司网络开了AP隔离,手机和电脑根本不在一个网段;现场没有无线路由器,临时开热点又连不上;再倒霉一点碰到网管做了端口策略,代理端口直接被掐掉。这种时候还死磕Wi-Fi方式,就是浪费时间。
这次我想分享的是在Windows上借助USB网络通信实现应用抓包的完整方案。一台Windows笔记本、一根能传数据的USB线、一部Android手机,加上本机装好的Charles,完全不需要Wi-Fi环境,就能稳定地把手机App的HTTP、HTTPS流量抓下来看。文章会从为什么需要USB方式讲起,把背后的网络链路讲清楚,然后给出一套可以直接照做的实操流程,最后把我踩过的坑和排查思路都整理出来。主要内容基于我在日常调试项目X时的实际经验,不同设备上细节会有差异,但思路是通用的。
1. 为什么Wi-Fi代理抓包总出问题,USB方式反而更稳
1.1 那些让Wi-Fi代理方案翻车的真实场景
用Charles抓包,最常规的做法是让手机和电脑连到同一个Wi-Fi,然后在手机网络设置里把HTTP代理指向电脑的局域网IP。这个方案在家庭网络、自己搭建的测试环境下很顺,但只要出了这个范围,问题就成堆往外冒。
遇到最多的是AP隔离。公司、酒店、商场里的公共无线网络,为了安全通常会开启AP隔离,也就是每个接入设备只能和网关通信,设备之间互相隔离。你用手机连上这个Wi-Fi,再在Charles里填电脑的IP,请求根本发不到电脑上。其次是Wi-Fi信号不稳定,抓包过程中网络抖动一下,Charles那边会断开一堆连接,复现一个偶现问题的时间成本直接翻倍。还有一种情况是现场压根没有Wi-Fi,只有一台笔记本和一部手机,想在车里、户外、客户现场的弱网环境里抓包,Wi-Fi方案直接失效。
USB方式的优势恰恰体现在这些场景里。USB线只要物理连通,手机和电脑之间就是一条独立的数据链路,不依赖任何无线网络,也没有跨网段的烦恼。而且USB链路本身非常稳定,不会因为旁边有人走动、微波炉开了一下就丢包。数据线还能顺便给手机充电,长时间抓包不用担心手机电量撑不住。
1.2 USB网络通信的本质:一根线把手机变成网卡
很多人一听“USB网络通信”就以为要写什么底层驱动,其实这里用的就是Android系统自带的USB网络共享(USB Tethering)功能。它的原理可以理解成手机把自己模拟成一块USB网卡,通过物理数据线和电脑连接,然后在这条USB链路上跑标准的IP协议。
从Windows的角度看,手机插上并开启USB网络共享之后,系统里会多出一个网络适配器。Windows 10和Windows 11通常自带RNDIS驱动,多数情况下无需额外安装驱动就能识别。这个时候手机和电脑之间就是一个迷你局域网,两者可以互相ping通,TCP连接也能正常建立,Charles的代理流量完全可以走这条链路。
这里有一个容易混淆的点需要先理清:USB网络共享这个功能本身是把手机的网络传递给电脑,让电脑通过手机上网。但如果只是这样,手机上App发出去的请求还是走手机自己的蜂窝网络,并不会经过电脑。要让Charles截获手机App的流量,关键是让手机把代理指向电脑上那个USB网卡的IP地址,这样手机App发出的HTTP请求就会先通过USB线到达Charles,再由Charles转发出去。
1.3 一次请求在USB链路里到底是怎么走的
为了让后面的操作不迷路,先把数据流走一遍。假设手机开启USB网络共享后,网络链路已经建立,手机代理指向电脑USB网卡的IP和Charles监听端口。
手机App里点了某个按钮,发起一个HTTPS请求。这个请求首先来到手机的网络协议栈,发现系统配置了HTTP代理,于是不再直接访问目标服务器,而是把请求发给代理地址,也就是电脑的USB网卡IP。数据包通过USB线传到电脑,Windows网络协议栈把它交给正在监听8888端口的Charles。Charles收到请求后,用自己的SSL证书和App完成TLS握手,解密出明文,然后代替App向目标服务器发起真正的请求。服务器返回数据后,Charles同样能解密查看,再原样加密回传给App。
这个过程听起来步骤多,但实际体验上差别不大,只是多经过了一道本机代理,对定位接口问题完全够用。理解了这条链路,后面配置的时候就知道每一步是在干什么了。
2. 动手前先做准备:工具、驱动和网络适配器检查
2.1 需要准备的东西和选型建议
这个方案需要用到的软件和硬件都不复杂,但每一样都有讲究。
电脑端需要Windows系统,版本Win10或Win11都可以,老一点的Win7也能做,只是驱动上可能要手动处理。Charles推荐用4.x以上版本,不管用什么版本,核心功能都在,我下面讲的操作在4.x和5.x上基本通用。
手机端推荐用Android手机,原因是Android对USB网络共享和代理配置的支持都比较完整。系统版本最好在Android 8以上,Android 7以上其实也行,但涉及证书信任问题后面会细说。iOS设备理论上也能通过USB共享网络,但Windows上接入iPhone的数据链路要先装驱动,而且iOS系统里并没有为USB网络单独提供HTTP代理配置入口,实际硬抓iOS的包会麻烦很多。所以本文主要以Android手机为例。
USB数据线是最容易被忽视的坑。很多线买回来只支持充电,不支持数据传输,插上之后电脑完全认不到设备。判断方法很简单:把手机连上电脑,看系统有没有弹出来USB连接提示,或者看设备管理器里有没有出现新设备。没有反应就换一根线,别在这个环节纠结太久。
2.2 Windows对不对,先看RNDIS网卡有没有出现
手机连上电脑之后,先不要急着开Charles。第一步是确认Windows正确识别了USB网卡。
插上手机,在手机上下拉通知栏,点击USB连接方式,选择“USB网络共享”或者“USB Tethering”(不同手机厂商叫法略有差异,本质是一个功能)。有些手机第一次开这个开关,会提示需要安装驱动,Windows 10和Windows 11一般能自动搞定,如果提示驱动安装失败,去设备管理器里手动更新一下驱动,或者装一下手机厂商提供的USB驱动包。
打开命令提示符,输入ipconfig /all,回车,找到描述里带“Remote NDIS”或者“USB Ethernet/RNDIS”字样的网卡,确认它已经拿到IP地址。常见情况下,手机是192.168.42.129这类地址,电脑USB网卡分到的是192.168.42.x网段的另一个地址。不同手机品牌网段可能不同,见识过192.168.43.x、192.168.44.x,甚至10.42.x.x的也有,不用记死,以实际显示为准。
这里有一个可以顺手验证的操作:Windows里ping一下手机的IP,能通说明USB链路是好的。如果ping不通,先看Windows防火墙是不是拦了ICMP,但这一步即使ping不通也不一定影响Charles,后面设置代理后只要TCP能通就行。
2.3 Charles端监听参数应该怎么填
Charles默认监听8888端口,但默认只监听本机回环地址,手机流量要想进来,必须让Charles监听所有网卡。打开菜单Proxy > Proxy Settings,在Proxies选项卡里,勾选“Allow remote access”,确保监听端口是8888,或者改成自己习惯的其它端口。这个操作很容易被忽略,忘了勾的话手机那边填了代理也不会有任何流量进入Charles。
还有一个关联设置不容忽略。如果目标是抓HTTPS包,必须去SSL Proxying Settings里添加一个条目,Host填*,Port填443,作用是对所有走443端口的TLS连接进行解密。不加这个配置的话,Charles里只能看到一堆CONNECT请求,点开看不到任何内容,很多人第一次抓包就卡在这。
2.4 手机端代理的两种设置方式
有了USB链路,手机和电脑已经能互相访问,接下来的关键操作是把手机上的HTTP代理指向Charles。
很多教程会让你去“设置 > WLAN > 修改网络 > 高级选项 > 代理”里面填。但这里有个容易掉坑的点:如果手机开启了USB网络共享,手机App当前的网络出口通常是蜂窝移动数据,而不是Wi-Fi,WLAN里的代理设置根本不会生效。这时候要么去移动网络的接入点设置里配代理,要么用adb直接设置全局代理。
第二种方式在调试中更常用。手机打开USB调试,连接电脑,执行:
adb shell settings put global http_proxy 192.168.42.100:8888把IP换成电脑USB网卡的实际IP。设置完验证一眼:
adb shell settings get global http_proxy能看到192.168.42.100:8888就说明全局代理已经生效。这个方式的好处是不用手在手机上翻设置,而且对整个系统生效,不用管当前网络走的是Wi-Fi还是数据流量。取消代理时执行:
adb shell settings put global http_proxy :03. 完整实操:从连手机到看到明文HTTPS包
3.1 第一步:先把数据线和驱动链路打通
这一步的完成标准是Windows设备管理器里能看到Android设备,并且网络适配器里出现了新的USB网卡。
实际操作时记住一个顺序:先用USB线连接手机和电脑,再打开手机的USB网络共享开关,打开开关之后Windows才会去识别新的RNDIS网卡。如果先开开关再插线,一部分手机会比较迟钝,识别得慢,容易让人误以为线有问题。打开手机USB网络共享后,如果Windows提示无法识别设备,去设备管理器看看是不是有设备带了感叹号,对应更新驱动即可。正常情况下,连接成功后系统右下角会弹网络连接提示,这时ipconfig /all能看到新网卡。
3.2 第二步:记录关键IP地址
这一步是全部配置的地基,整套方案里需要用到的IP有手机地址和电脑USB网卡地址。
手机开启USB共享后,查看手机“关于手机 > 状态信息”里的IP地址,或者更简单的方法是直接进手机“设置 > 网络共享与便携热点 > USB网络共享”页面,有些手机会直接显示一个IP,比如192.168.42.129。电脑端执行ipconfig,找到那个带RNDIS描述的网卡,记下它的IPv4地址,比如192.168.42.100。
如果手机那个页面看不到IP,也可以用adb命令查询:
adb shell ifconfig或者:
adb shell ip addr show找到类似192.168.42.129/24的地址就是手机侧IP。这两个IP确认之后,后面所有配置都围绕它们展开。
3.3 第三步:配置Charles并允许远程访问
打开Charles,按上一节说的,在Proxy > Proxy Settings里勾选Allow remote access,确认端口8888。再到SSL Proxying Settings里添加一条规则,Host填*,Port填443,勾选Enable SSL Proxying。
这里可以顺手验证一下电脑上的Charles是否真的能通过USB网卡访问:在当前Windows环境里,浏览器或curl直接请求手机的IP或者本机USB网卡IP的8888端口,看Charles有没有收到请求。保险起见,如果Windows防火墙之前拦过Charles,可以给8888端口加一条入站放行规则:
netsh advfirewall firewall add rule name="charles-8888" dir=in action=allow protocol=TCP localport=88883.4 第四步:设置手机全局代理
手机打开USB调试并连接电脑后执行:
adb shell settings put global http_proxy 192.168.42.100:8888执行完记得检查一下:
adb shell settings get global http_proxy如果输出192.168.42.100:8888,说明代理已生效。此时打开手机上的任意浏览器访问一个网站,正常情况下Charles主界面会开始出现大量条目,说明流量已经通过USB链路进入Charles了。
有个细节需要注意:设置全局代理之后,部分系统自带应用可能不走代理,或者个别App会忽略系统代理直接连接,这是正常现象,放宽心继续往后看。
3.5 第五步:安装并信任Charles根证书
如果目标是抓HTTPS明文,这一步绕不开。手机浏览器访问chls.pro/ssl,会下载一个名为charles-proxy-ssl-proxying-certificate.pem的证书文件。Android系统会弹出安装证书的引导,按提示把证书安装到“CA证书”或“凭据存储”里。
Android 7及以上版本有一个非常重要的限制:App默认只信任系统证书,不信任用户安装的证书。这意味着很多App即使你装了用户证书,抓包时依然会报SSL错误。这种情况下有两种出路。如果手机已Root,可以把证书文件转成系统格式后放到系统证书目录/etc/security/cacerts/下,并设置644权限。如果没有Root,只能抓那些没有特殊证书校验的App,比如浏览器、WebView页面,以及自身声明了信任用户证书的应用。
证书安装完以后,记得在手机“设置 > 安全 > 加密与凭据 > 信任的凭据”里确认能看到Charles的证书。看不到说明没装成功,需要重新走一遍。
3.6 第六步:验证抓包效果并开始调试
到了这一步,完整链路已经建立。在Charles主界面的Structure或Sequence视图里,应该能看到来自手机的请求。
验证的时候有几个判断要点。如果Charles里大量出现灰色的CONNECT请求但内容为空,说明SSL Proxying没有生效,回去检查配置。如果连CONNECT都看不到,说明代理没有指对,或者请求压根没有走USB链路,检查adb shell settings get global http_proxy的值。如果能看到完整的HTTPS明文请求,说明证书信任和代理链路都正常,可以开始正常调试了。
调试阶段有一些常规操作可以帮助提升效率。Charles底部有一个过滤条,可以直接输入目标域名,只显示该域名的请求,省得被一堆CDN、统计平台的噪音流量干扰。Structure视图适合按域名整理查看,Sequence视图适合按时间顺序排查一次性问题,切换视图的快捷键在菜单View里都能找到。
4. 抓包时最容易翻车的几个环节(经验速查表)
USB方式抓包整体稳定,但真的跑起来以后还是有一堆小问题。这些坑我基本都踩过,整理成一张速查表,按症状排查就行。
| 现象 | 最常见原因 | 处理方式 |
|---|---|---|
| 手机App请求在Charles里完全看不到 | 手机代理没设置成电脑USB网卡IP | 执行adb shell settings get global http_proxy确认代理值;确认IP不是Wi-Fi网卡IP |
| Charles里全是CONNECT,点开没内容 | SSL Proxying没开启或规则没加 | Proxy > SSL Proxying Settings,加*:443 |
| 手机浏览器能打开,App打开就报SSL错 | App不信任用户证书 | Root后把证书移到系统证书目录;或改用无证书校验的调试包 |
证书下载页面chls.pro/ssl打不开 | 代理没生效,或8888端口被防火墙拦 | 检查代理设置;放行Windows防火墙8888入站TCP端口 |
| USB网络共享开了但电脑网卡没出现 | 数据线不支持数据传输 | 换一根确认能传数据的线;检查手机USB连接模式是否被选成“仅充电” |
| 设置了全局代理后部分App仍直连 | App不走系统代理 | 需要结合root环境重定向流量,属于进阶方案 |
| 电脑通过手机USB上网正常,但抓包慢 | USB网络共享带宽有限 | 抓包时关闭电脑上的自动更新、后台下载,把带宽留给代理流量 |
| 手机提示“无法连接到代理” | 电脑Charles没监听在USB网卡上 | 确认勾选Allow remote access,不要只监听127.0.0.1 |
再补充一个容易被忽略的操作细节:每次修改完手机代理设置,最好让手机断开再重新连接一次网络,或者直接开关一次飞行模式,让系统网络状态刷新一下,否则代理变更不一定立刻生效。用adb设置全局代理的时候,这个操作尤其重要,设置完成后可以执行adb shell cmd connectivity相关命令看网络状态,或者重启一下App再试。
还有一个排障顺序要记牢:先看网络链路,再看代理指向,最后查证书问题。这三个环节层层依赖,链路不通,后面什么都是白搭。
5. 流量打通后的几个实用玩法
抓包不是为了看图,关键是拿到明文数据以后怎么用。实际工作中我最常用的几个功能是过滤、断点和Mock,这几招对排查线上问题和本地联调都非常有用。
过滤是个基本操作,但很多人用不好。Charles顶部的Filter输入框支持通配符和正则,比如只关心某个接口域名,直接输入*.example.com,列表里就只剩下该域名下所有请求。还可以在某个请求上右键,选择Highlight,给特定域名标个颜色,多人协作调试时一眼就能分清目标流量。
断点调试可以说是抓包最有价值的功能之一。在Charles里选中一个请求,右键选择Breakpoint,下次这个请求到达时Charles会先拦截下来,你可以修改请求头、请求参数或者响应内容再放行。比如App上线后接口出了问题,都可以用这个方式模拟不同的异常返回,验证前端页面在不同响应下是否处理正确。具体操作是Proxy > Breakpoint Settings里添加匹配规则,规则里的Host、Path、Port都可以填正则来精确匹配。
Mock接口也是个高频需求,尤其是后端还没开发完或者线下环境不稳定的时候。右键一个请求,选择Save Response,把响应体存成本地文件,然后用Map Local功能把这个URL映射到本地文件上。后续App再请求这个URL时,Charles直接返回本地文件内容,完全不用经过真实服务器。配合断点功能,可以轻松构造各种测试数据和异常场景。
如果你需要把抓到的请求分享给同事分析,直接用Charles的文件菜单导出Har文件,把后缀为.har的文件发过去就行。主流的接口调试工具都能导入Har文件,对方打开就能看到完整的请求头和响应体,比截图传话高效得多。
再提一个USB抓包特有的优点:整个抓包过程不依赖任何无线环境,手机的网络出口保持真实状态,不像连上电脑热点之后IP段、DNS都会变,一些在特定网络环境下才会暴露的问题用USB方式更容易复现。我自己排查过不少“只有用户现场能复现,办公室怎么弄都不出现”的接口问题,USB抓包是效率最高的手段之一。
最后再啰嗦一句:抓包务必针对自己负责或有明确授权的应用,别在别人的App上乱来,隐私这条线什么时候都不能碰。工具本身没有善恶,用在调试排查上是正经事,越界了就完全是另一码事了。