1. 为什么安卓模拟器抓包比真机更难却又是测试绕不开的一环很多人一上来就问“我用夜神、雷电、MuMu这些模拟器跑AppBurp怎么就是收不到包”——这问题我去年在三个金融类App的渗透测试项目里反复遇到过。不是Burp没开不是代理没配也不是证书没装而是整个链路里至少藏着五层“静默拦截”Android系统对非系统证书的默认拒绝、模拟器自带的网络代理策略覆盖、应用层的SSL Pinning硬编码、Burp证书在Android 7系统中无法自动信任、以及最关键的——多数模拟器默认使用Host-Only网络模式根本不会把流量导向宿主机的Burp监听端口。你看到的“无请求”其实是流量压根就没路过Burp。这个标题里的“全流程解析”不是教你怎么点几下菜单而是要把从模拟器启动那一刻起每一个网络栈环节的走向、每一个证书加载时机、每一个配置项背后的底层机制全部掰开揉碎讲清楚。它适合两类人一类是刚接触移动安全的测试同学卡在“配了代理却没包”上反复重启另一类是已经能抓到部分包但总被SSL Pinning拦住、对证书安装路径和系统分区权限还模糊的进阶者。整套流程不依赖任何第三方插件或魔改ROM只用官方Burp Suite Professionalv2024.7 Android Studio自带的Pixel模拟器API 30/33所有操作均可在Windows/macOS/Linux三端复现且每一步都对应一个可验证的网络行为反馈——比如配完代理后你能立刻在Burp的Proxy → HTTP History里看到DNS查询请求装完证书后能通过adb shell pm list packages -s | grep com.android.certificates确认系统证书库已更新。这不是理论推演是我在27个不同版本App上逐行调试出来的实操路径。2. 模拟器网络栈的本质别再盲目改IP先搞懂它到底走哪条路2.1 Android模拟器的三种网络模式与Burp适配逻辑很多人一上来就去模拟器设置里改“代理服务器地址为127.0.0.1:8080”结果毫无反应。根本原因在于你根本没搞清模拟器此刻用的是哪种网络模式。Android模拟器以Android Studio Emulator为例实际提供三种底层网络连接方式而Burp能否捕获流量完全取决于你当前启用的是哪一种网络模式底层实现Burp是否可捕获关键判断依据典型适用场景NAT默认模拟器通过宿主机的网络接口转发流量所有出站请求经由宿主机NAT表路由✅ 可捕获需正确配置代理adb shell getpropgrep dns显示net.dns1: 192.168.x.x指向宿主机Bridge桥接模拟器直接接入宿主机所在局域网获得独立IP如192.168.1.105❌ 不可捕获除非Burp监听0.0.0.0且防火墙放行adb shell ifconfig eth0显示inet addr:192.168.1.105非10.0.2.x段需要模拟器与局域网其他设备互通时Host-Only仅主机模拟器与宿主机组成独立私有网络如10.0.2.15 ↔ 10.0.2.2不对外联网❌ 完全不可捕获流量不经过宿主机网卡adb shell getpropgrep dhcp显示dhcp.eth0.ipaddress: 10.0.2.15提示绝大多数用户使用的都是NAT模式但很多人并不知道如何验证。执行adb shell getprop | grep net\|dns若输出中包含net.dns1: 10.0.2.3或net.dns1: 192.168.x.x说明处于NAT若出现net.dns1: 127.0.0.1则说明代理已被错误覆盖需重置。我踩过的第一个坑就是在雷电模拟器里手动启用了“桥接模式”以为这样更“真实”结果Burp监听0.0.0.0:8080后模拟器发出的所有HTTPS请求全部超时——因为桥接模式下模拟器的IP和宿主机不在同一子网Windows防火墙默认阻止了外部IP对8080端口的入站连接。后来我切回NAT模式问题当场解决。所以在动任何代理配置前请先执行这条命令确认网络模式adb shell getprop | grep -E (net\.dns|dhcp\.eth0\.ipaddress)如果返回值里net.dns1的值是10.0.2.3这是Android Emulator NAT网关的标准地址恭喜你站在了正确的起点上。2.2 为什么127.0.0.1在模拟器里永远连不通宿主机的Burp这是新手最常犯的认知错误。你在模拟器Wi-Fi设置里填127.0.0.1:8080以为这就是宿主机的本地回环地址——错。在Android模拟器的NAT网络架构中127.0.0.1指向的是模拟器自身而不是你的Windows/macOS宿主机。模拟器内部运行的是一个完整的Linux内核它有自己的localhost。你要访问宿主机必须用NAT网关预设的特殊IP10.0.2.2。这是Android Emulator硬编码的宿主机别名等价于你在宿主机上执行ipconfigWindows或ifconfigmacOS/Linux看到的虚拟网卡地址通常是10.0.2.2或192.168.x.1。验证方法极其简单在模拟器终端可通过adb shell进入执行ping 10.0.2.2如果收到响应说明网络通路正常如果超时说明模拟器NAT功能异常需重启模拟器或重装HAXM/Intel GPU驱动。注意某些国产模拟器如夜神会将宿主机映射为127.0.0.1但这属于厂商魔改不可靠且不通用。本文全程以Android Studio官方Emulator为准因其网络行为稳定、文档公开、调试接口完整。若你坚持用夜神请先在模拟器内执行adb shell ping 127.0.0.1确认其是否真的指向宿主机——我实测过夜神6.5.0.0版本127.0.0.1实际指向模拟器自身真正宿主机地址是192.168.199.100需查其网络设置面板。2.3 代理配置的两种生效层级系统级 vs 应用级很多同学配完Wi-Fi代理后发现Chrome能抓到包但目标App还是没动静。这是因为Android的代理设置存在两个作用域系统级代理Wi-Fi设置影响所有使用系统HTTP库的应用如Chrome、系统浏览器但对使用OkHttp、Retrofit等现代网络库的App无效——它们默认忽略系统代理直接走Socket连接。应用级代理代码强制需在App源码中显式调用OkHttpClient.Builder().proxy(Proxy)普通测试人员无法修改。所以当你在Wi-Fi里配了代理却看不到目标App的请求不要怀疑Burp要怀疑App本身。此时必须启用Burp的透明代理Transparent Proxying功能强制所有TCP 443/80端口流量重定向至Burp。这需要两步在Burp中开启Proxy → Options → Proxy Listeners → Edit → Binding →勾选Support invisible proxying (enable only if needed)在模拟器中执行以下ADB命令将所有出站443端口流量重定向到Burpadb shell settings put global http_proxy 10.0.2.2:8080 adb shell settings put global https_proxy 10.0.2.2:8080 # 注意此命令仅对API 28及以下有效API 29需用iptables见后文但这里有个致命陷阱Android 9API 28之后http_proxy系统属性被废弃上述命令不再生效。此时必须用iptables规则——这也是为什么很多教程在新系统上失效的根本原因。我们将在第4节详细展开iptables的精确写法包括如何绕过Android 12的SELinux限制。3. SSL Pinning攻防实战从证书安装失败到双向证书绕过3.1 Android系统证书库的三级结构与Burp证书安装失败的根因当你把Burp生成的CA证书cacert.der拖进模拟器点击安装却提示“证书类型不受支持”或“安装失败”这不是你的操作问题而是Android证书存储机制发生了根本性变化。自Android 7.0Nougat起系统引入了应用级证书信任锚Application-level Trust Anchors机制即每个App可声明自己只信任特定证书如银行App只信任其服务器证书或系统预置根证书完全无视用户手动安装的证书。这意味着即使你成功把Burp证书装进了“用户证书”目录App依然会拒绝建立TLS连接。Android证书库实际分为三层系统证书/system/etc/security/cacerts/只读分区存放预置CA如DigiCert、GlobalSign普通用户无法写入用户证书/data/misc/user/0/cacerts-added/可写存放用户通过设置安装的证书但自Android 7起默认不被App信任应用专属证书库/data/data/ /files/App自己管理用于SSL PinningBurp无法触达。因此“安装证书失败”的本质往往不是文件格式问题.dervs.crt而是你试图安装到错误的目录。Burp官网文档建议将证书转为.crt并重命名如cacert.crt再通过Settings → Security → Install from storage安装——这只能进用户证书库对SSL Pinning无效。真正有效的做法是将证书注入系统证书库但这需要root权限。好消息是Android官方模拟器默认启用root且/system分区可写。坏消息是直接adb push会失败因为/system挂载为只读。解决方案分三步重新挂载/system为可写adb root adb remount将Burp证书转换为PEM格式并计算hashAndroid系统证书名hash.0# 在宿主机执行需openssl openssl x509 -inform DER -in cacert.der -out cacert.pem openssl x509 -inform PEM -subject_hash_old -noout -in cacert.pem # 输出类似d6e677a3 → 这就是证书hash推送证书并设置权限adb push cacert.pem /system/etc/security/cacerts/d6e677a3.0 adb shell chmod 644 /system/etc/security/cacerts/d6e677a3.0 adb reboot提示subject_hash_old是关键Android 7-9使用旧版hash算法Android 10改用subject_hash但模拟器多为7-9务必用_old参数。我曾因漏掉_old导致证书hash错位折腾两小时才发现。3.2 OkHttp SSL Pinning的四种绕过方式与实测有效性排序当App使用OkHttp并启用CertificatePinner时即使你注入了系统证书连接仍会抛出javax.net.ssl.SSLPeerUnverifiedException。此时必须动态绕过Pin。我实测了四种主流方案按成功率和稳定性排序如下方案原理适用场景成功率关键限制Frida Hook推荐注入JS脚本在CertificatePinner.check()方法执行前返回true所有OkHttp 3.x/4.x App★★★★★需Frida Server运行Android 12需关闭SELinuxXposed JustTrustMe利用Xposed框架Hook SSL相关APIAndroid 8.1及以下★★★☆☆Xposed不兼容Android 9模拟器需刷Xposed镜像ObjectionFrida封装objection -g package explore --startup-command android sslpinning disable快速验证★★★★☆依赖Frida部分加固App会检测objection进程手动反编译修改smali修改check()方法逻辑为return;无加固、可调试App★★☆☆☆耗时长签名重打包后可能触发签名校验我最终选择Frida因为它是目前唯一能在Android 12模拟器上稳定工作的方案。具体步骤下载对应Android ABI的Frida Server如frida-server-16.3.4-android-x86_64.xz解压后推送至模拟器adb push frida-server /data/local/tmp/frida-server adb shell chmod 755 /data/local/tmp/frida-server adb shell /data/local/tmp/frida-server 在宿主机安装frida-toolspip install frida-tools执行绕过命令以某金融App为例frida -U -f com.xxx.bank -l ssl-pinning-bypass.js --no-pause其中ssl-pinning-bypass.js内容为Java.perform(function () { var CertificatePinner Java.use(okhttp3.CertificatePinner); CertificatePinner.check.overload(java.lang.String, java.util.List).implementation function (str, list) { console.log([] SSL Pinning Bypassed for: str); return; }; });注意--no-pause参数至关重要。它让Frida在App启动后立即注入避免因App启动过快导致Hook失败。我曾因漏掉此参数反复重启App十几次才成功。3.3 双向认证mTLS场景下的Burp配置要点少数高安全App如企业级VPN客户端采用双向TLS认证即不仅服务器验证客户端证书客户端也验证服务器证书。此时单纯安装Burp CA证书不够还需让Burp持有合法的客户端证书。操作分三步从App APK中提取assets/或res/raw/下的.p12或.bks证书文件用apktool d app.apk反编译将证书导入BurpProxy → Options → Client SSL certificates → Import在Burp中为该域名绑定证书点击Add→ 输入目标域名如api.xxx.com→ 勾选Use specific client SSL certificate→ 选择导入的证书。关键细节.bksBouncy Castle Key Store格式需先转为PKCS#12keytool -importkeystore -srckeystore client.bks -srcstoretype BKS -destkeystore client.p12 -deststoretype PKCS12密码默认为changeit若报错则尝试password或123456。实测发现某政务App的mTLS证书有效期仅7天且每次启动动态生成新证书。此时必须配合Frida HookKeyStore.load()方法实时捕获内存中的证书字节流——这已超出基础抓包范畴属于深度逆向本文暂不展开。4. iptables透明代理绕过Android 9系统代理限制的终极方案4.1 为什么Android 9的settings put http_proxy彻底失效Android 9Pie引入了NetworkSecurityConfig机制强制App遵守android:usesCleartextTrafficfalse和domain-config声明。更重要的是系统级代理设置被移入ConnectivityManager服务settings put命令不再修改底层Socket路由表。你执行adb shell settings put global http_proxy 10.0.2.2:8080后getprop仍能读到该值但tcpdump抓包显示所有流量仍直连目标IP未经过Burp。根源在于Android 9的TCP/IP栈在netd守护进程中完成路由决策http_proxy仅影响HttpURLConnection等高层API对OkHttp、Curl等底层Socket调用无效。4.2 iptables规则的精确构造与SELinux绕过技巧真正的解决方案是iptables——它工作在Linux内核Netfilter框架能劫持任意TCP连接。但在Android上有两大障碍权限限制iptables命令需root权限且Android 8默认禁用SELinux限制Android 5.0启用SELinux enforcing模式禁止net_admin能力的进程修改iptables。突破路径如下确认SELinux状态adb shell getenforce # 若返回Enforcing需临时切换为Permissive adb shell su -c setenforce 0注意setenforce 0仅临时生效重启模拟器后恢复。生产环境勿用但模拟器测试完全安全。编写精准iptables规则核心目标是将所有出站443端口流量重定向到Burp的8080端口。但必须排除Burp自身流量否则死循环且只针对目标App的UID避免影响系统服务。规则如下adb shell su -c iptables -t nat -A OUTPUT -p tcp --dport 443 -m owner ! --uid-owner u0_a123 -j REDIRECT --to-port 8080; iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner u0_a123 -j REDIRECT --to-port 8080; 其中u0_a123是目标App的UID通过adb shell pm list packages -U | grep com.xxx.app获取。! --uid-owner确保Burp进程UID为u0_a0的流量不被重定向。验证规则生效在Burp中开启Proxy → Intercept is on然后在模拟器执行adb shell curl -v https://httpbin.org/get若Burp Intercept窗口弹出请求则规则生效。若无反应检查两点iptables -t nat -L OUTPUT是否显示刚添加的规则adb shell su -c getenforce是否为Permissive。4.3 自动化脚本一键部署透明代理与证书注入手动敲命令易出错我编写了一个Bash脚本setup-burp-proxy.sh整合了网络模式检测、iptables注入、证书安装、SELinux切换全流程。核心逻辑如下#!/bin/bash APP_PACKAGEcom.xxx.app BURP_IP10.0.2.2 BURP_PORT8080 # 1. 检测网络模式 DNS$(adb shell getprop net.dns1 2/dev/null) if [[ $DNS ! *10.0.2.* $DNS ! *192.168.* ]]; then echo Error: Not in NAT mode. Please switch to NAT network. exit 1 fi # 2. 获取App UID APP_UID$(adb shell dumpsys package $APP_PACKAGE | grep userId | cut -d -f4) # 3. 设置SELinux为Permissive adb shell su -c setenforce 0 # 4. 添加iptables规则 adb shell su -c iptables -t nat -A OUTPUT -p tcp --dport 443 -m owner ! --uid-owner $APP_UID -j REDIRECT --to-port $BURP_PORT adb shell su -c iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner $APP_UID -j REDIRECT --to-port $BURP_PORT # 5. 注入Burp证书需提前准备好cacert.pem和hash adb shell su -c mount -o rw,remount /system adb push cacert.pem /system/etc/security/cacerts/d6e677a3.0 adb shell su -c chmod 644 /system/etc/security/cacerts/d6e677a3.0 adb reboot实操心得脚本中dumpsys package获取UID比pm list packages -U更可靠后者在多用户环境下可能返回多个UID。另外mount -o rw,remount /system必须在adb root后执行否则权限不足。5. 抓包后的深度分析从HTTP History到漏洞定位的闭环路径5.1 Burp Proxy History的隐藏信息挖掘技巧很多人把Proxy History当“请求列表”用其实它是个富数据源。例如右键某个请求 → Send to Repeater后在Repeater中修改User-Agent为sqlmap观察响应是否含SQL syntax error可快速识别注入点在History中按CtrlF搜索password或token找到明文传输的敏感字段查看Response的Render标签页直接渲染HTML发现未授权访问的管理后台入口如/admin/config**对JSON响应右键 → Engagement tools → Find comments**暴露前端埋点的调试信息如debug: true。我曾在某电商App的/api/v1/user/profile响应中通过Find comments发现一行注释// TODO: remove this debug flag before release后面跟着is_debug_mode: true。开启此模式后所有API响应额外返回sql_query字段直接暴露后端SQL语句——这是典型的开发疏忽但若不深挖History极易错过。5.2 使用Burp Intruder爆破弱Token与业务逻辑漏洞当发现App使用JWT或自定义Token时不要只盯着Header解码。Intruder是利器在Proxy History中选中登录请求右键 → Send to Intruder在Intruder的Positions选项卡点击AutoBurp会自动标记所有可替换参数手动清除无关参数只保留Authorization: Bearer token中的token部分Payloads中选择Simple list填入常见弱Token如eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...开始攻击观察Status列是否出现200且Length显著不同如200 OKvs200 OK但长度差2000字节说明返回了用户数据。关键技巧在Options → Grep-Match中添加正则user_id\s*:\s*\dBurp会高亮匹配该模式的响应极大提升人工筛选效率。5.3 Collaborator Everywhere无回显漏洞的主动探测对于盲注、SSRF、XXE等无回显漏洞Collaborator是必杀技。操作极简在Proxy History中选中任意请求右键 → Engagement tools → Collaborator everywhereBurp会自动将所有参数值替换为Collaborator生成的唯一URL如xxx.burpcollaborator.net发送请求后打开Burp Collaborator客户端等待DNS或HTTP回调。我曾用此法发现某App的/api/v1/report?url接口存在SSRF当传入urlhttp://xxx.burpcollaborator.net时Collaborator立即收到DNS查询请求证明服务端发起了一次外部HTTP请求——这可被利用读取内网Redis、打内网端口扫描。最后分享一个小技巧在Collaborator中点击Poll now按钮后若看到DNS lookup但无HTTP request说明目标服务只做了DNS解析未发HTTP请求此时应尝试file://协议如file:///etc/passwd探测本地文件读取。