当前位置: 首页 > news >正文

Frida Hook绕过安卓APP SSL Pinning实现HTTPS抓包

1. 为什么HTTPS抓包在安卓APP上越来越像“开盲盒”

你有没有试过用Charles或Fiddler给一个刚下载的金融类APP做HTTPS抓包,结果所有请求全是红色的❌?证书安装了、代理也配了、手机和电脑在同一Wi-Fi下——一切看起来都对,但就是看不到任何HTTP/HTTPS流量。这不是你的操作问题,而是APP开发者早已把“防抓包”写进了启动逻辑里。我去年帮三个不同行业的客户做接口分析,平均每个APP要花2.3天才能绕过第一道SSL Pinning检测。不是工具不行,是现代安卓APP的HTTPS防护机制已经从“加把锁”升级成了“带生物识别的保险库”。

核心关键词:安卓APP、HTTPS抓包、Frida Hook——这三者组合在一起,本质上不是教你怎么“看流量”,而是教你如何在运行时动态干预APP的信任链决策点。它不依赖修改APK(不用重打包、不碰签名)、不依赖系统级证书信任(不用root后手动注入系统证书库)、甚至不强制要求你逆向出完整的Java层逻辑。Frida Hook之所以成为当前最主流的方案,是因为它直接作用于ART虚拟机的执行上下文,在Java方法调用即将发生、但尚未真正执行的毫秒级窗口中,把checkServerTrusted()这类关键校验函数的返回值“悄悄换成true”。这种能力,让抓包从“环境适配战”回归到“逻辑干预战”。

适合谁来看这篇?如果你是测试工程师,需要快速验证某次热更新是否引入了异常请求;如果你是安全研究员,想确认某款SDK是否在后台静默上传设备指纹;如果你是前端或后端开发,想反推竞品APP的数据结构以便做兼容性设计——那你不需要成为逆向专家,但必须掌握Frida Hook这一把“万能钥匙”。它不要求你读懂smali,也不需要你分析so文件的JNI调用栈,只要你能识别出目标方法名、理解Java/Kotlin的TrustManager/HostnameVerifier抽象概念,就能在30分钟内让绝大多数未加固APP“开口说话”。

提示:本文所有操作均基于真实项目复现,所用工具全部开源免费,不涉及任何破解、越狱或违反《网络安全法》的行为。我们只做合法授权范围内的协议分析与安全评估。

2. Frida Hook不是魔法,而是对Android SSL/TLS信任链的精准外科手术

要真正用好Frida Hook做HTTPS抓包,你得先明白:安卓APP的HTTPS通信为什么会失败?根本原因不是“网络不通”,而是信任链被主动掐断。这个过程可以拆解为四个不可跳过的环节:

  1. 证书加载阶段:APP通过CertificateFactory.getInstance("X.509")读取assets目录下的.cer.bks证书文件;
  2. 信任管理器构建阶段:将证书塞进TrustManagerFactory,生成X509TrustManager实例;
  3. 连接建立阶段OkHttpClientHttpsURLConnection在发起请求前,调用trustManager.checkServerTrusted(chain, authType)
  4. 主机名验证阶段HostnameVerifier.verify(hostname, session)判断域名是否匹配证书CN/SAN字段。

Frida Hook的威力,就体现在第3步和第4步——它不阻止证书加载,也不篡改证书内容,而是在checkServerTrusted()方法即将返回void的前一刻,把原本会抛出CertificateException的执行流,强行“打个补丁”,让它安静地返回。这就像在安检口不销毁X光机,而是给安检员戴上一副特制眼镜,让他把所有可疑物品都看成普通行李。

我实测过27款主流APP(含银行、电商、社交类),其中21款使用OkHttp作为网络框架,其SSL Pinning逻辑集中在OkHostnameVerifier和自定义X509TrustManager中;4款使用Retrofit+OkHttp组合,Hook点相同;剩下2款(某出行APP和某政务APP)使用了自研网络库,但最终仍调用SSLSocketFactory.getDefault(),因此HookSSLSocketFactorycreateSocket()方法同样生效。这意味着:你不需要逐个APP去逆向分析,92%的场景只需一套通用Hook脚本即可覆盖

2.1 为什么选Frida而不是Xposed或Cydia Substrate

很多人第一反应是“用Xposed模块不更方便?”——这是个典型误区。Xposed需要重启系统、依赖特定ROM、且在Android 9+上兼容性急剧下降;而Frida是纯用户态注入,通过frida-server进程attach到目标APP的Dalvik/ART运行时,完全绕过Zygote fork机制限制。更重要的是,Frida支持JavaScript/TypeScript编写Hook逻辑,语法简洁,调试反馈即时。比如你想绕过OkHttp的证书校验,一段代码就能搞定:

Java.perform(function () { var OkHostnameVerifier = Java.use("okhttp3.internal.platform.OkHostnameVerifier"); OkHostnameVerifier.verify.implementation = function (hostname, session) { console.log("[+] Bypass OkHttp HostnameVerifier: " + hostname); return true; }; });

这段代码的执行时机,是在OkHostnameVerifier.verify()方法体内部、return语句之前。它不修改字节码,不重写类,只是在JVM方法调用栈上“临时挂载”一个新实现。相比之下,Xposed需要编译Java模块、签名、安装、重启,整个流程耗时5分钟以上,而Frida从启动到生效,通常控制在15秒内。

注意:Frida对Android版本有明确适配要求。Android 8.0以下建议用Frida 12.x(兼容libdvm),Android 8.0+必须用Frida 14.2.18+(支持ART OAT格式解析)。我在华为Mate 30 Pro(EMUI 11,Android 10)上测试时,曾因误用Frida 12导致frida-ps -U无法列出进程,排查了47分钟才发现是版本错配——这是新手最容易踩的坑。

2.2 Frida Hook的三大黄金Hook点及其触发条件

不是所有SSL相关方法都值得Hook,抓包成功率取决于你是否命中了APP实际调用的校验入口。根据我分析的132个APK样本,以下是三个最高频、最稳定的Hook点,按优先级排序:

Hook点对应类/方法触发条件覆盖率实测绕过效果
X509TrustManager.checkServerTrustedjavax.net.ssl.X509TrustManagerAPP显式创建TrustManager实例(如OkHttp Builder.setSslSocketFactory)86%✅ 完全绕过证书链校验
OkHostnameVerifier.verifyokhttp3.internal.platform.OkHostnameVerifierAPP使用OkHttp 3.12+且未自定义HostnameVerifier79%✅ 绕过域名匹配校验
SSLSocketFactory.createSocketjavax.net.ssl.SSLSocketFactoryAPP使用系统默认SSLSocketFactory(如HttpURLConnection)63%⚠️ 需配合证书替换,否则仅绕过主机名

特别说明第三点:SSLSocketFactory.createSocket()本身不校验证书,但它返回的SSLSocket对象在startHandshake()时会触发底层BoringSSL校验。所以单纯Hook createSocket只能让连接建立成功,但握手仍可能失败。此时必须配合frida-ssl-pinning-bypass社区脚本,动态替换SSLSocketsetHostnameVerifier()方法。这个细节,90%的入门教程都不会提,导致读者以为Hook了就万事大吉。

3. 从零搭建可落地的Frida HTTPS抓包环境:避开95%的环境配置陷阱

很多教程一上来就贴命令:“adb install frida-server.apk”、“frida -U -f com.xxx.xxx -l hook.js”,然后戛然而止。但现实是:你在执行frida -U时大概率会遇到Failed to spawn: unable to find process,或者Error: unable to connect to remote frida-server。这不是你命令错了,而是环境链路上至少存在5个隐藏断点。下面是我用3台不同品牌手机(小米、华为、三星)反复验证后总结的最小可行配置清单,每一步都附带“为什么必须这么做”的原理说明。

3.1 手机端:frida-server部署的四个致命细节

第一步:确认CPU架构并下载对应frida-server别直接下arm64版本!先执行:

adb shell getprop ro.product.cpu.abi

输出可能是armeabi-v7a(旧机型)、arm64-v8a(主流)、x86_64(模拟器)。我见过太多人因为下了arm64版却装在32位CPU手机上,导致frida-server启动即崩溃。正确做法是去 https://github.com/frida/frida/releases 找对应版本,例如frida-server-16.1.4-android-arm64.xz

第二步:赋予可执行权限必须用chmod 755,不能用777

adb push frida-server /data/local/tmp/ adb shell "chmod 755 /data/local/tmp/frida-server"

为什么不是777?因为Android SELinux策略会拒绝u:r:shell:s0域对/data/local/tmp/目录下777权限文件的执行。755是经过SELinux策略白名单认证的安全权限组合。

第三步:frida-server必须以后台服务模式运行

adb shell "/data/local/tmp/frida-server &"

注意末尾的&符号。如果不加,终端会卡住等待输出,且一旦关闭ADB Shell,frida-server进程自动退出。更稳妥的做法是:

adb shell "nohup /data/local/tmp/frida-server > /dev/null 2>&1 &"

第四步:检查frida-server是否真正在监听

adb shell "netstat -tuln | grep 27042"

正常应返回tcp6 0 0 :::27042 :::* LISTEN。如果无输出,说明frida-server未启动成功。此时需查看日志:

adb logcat -s frida

常见错误是Permission denied——这说明你漏掉了第二步的chmod。

提示:华为/荣耀手机需额外开启“USB调试(安全设置)”选项(在开发者选项最底部),否则frida-server无法attach到非调试签名APP。这个开关在EMUI 12之后被隐藏得极深,需连续点击“版本号”7次进入工程模式才能解锁。

3.2 电脑端:Python环境与frida-tools的精准匹配

别用pip install frida!这是最大的坑。官方PyPI上的frida包只包含Python binding,不包含frida-server二进制文件,且版本常滞后于GitHub release。正确姿势是:

  1. 卸载所有旧版本:
    pip uninstall frida frida-tools
  2. 从GitHub Release页面下载对应平台的frida-tools-*.whl文件(如frida_tools-16.1.4-py3-none-any.whl);
  3. 本地安装:
    pip install frida_tools-16.1.4-py3-none-any.whl

为什么强调.whl文件?因为pip install frida-tools会自动拉取最新版,而新版frida-tools(如16.2.0)可能与你手机上运行的frida-server 16.1.4不兼容,导致frida-ps -U报错Protocol version mismatch。我曾因此浪费整个下午,最后发现只需降级一行命令:

pip install frida-tools==16.1.4

3.3 抓包工具链协同:Charles/Fiddler与Frida的握手协议

Frida本身不抓包,它只是让APP“信任”你的代理证书。真正的抓包仍需Charles或Fiddler。但这里有个关键协同点:Charles的代理证书必须以Android系统可识别的格式安装

错误做法:直接在手机浏览器访问chls.pro/ssl下载证书 → 安装为“用户证书”。
正确做法:

  1. 在Charles中导出证书(Help → SSL Proxying → Export Charles Root Certificate);
  2. .pem文件重命名为charles.crt
  3. 用ADB推送至手机:
    adb push charles.crt /sdcard/Download/
  4. 手机设置 → 安全 → 加密与凭据 → 安装从SD卡安装的证书 → 选择charles.crt→ 安装类型选“VPN和应用”(不是“WLAN”)。

为什么必须选“VPN和应用”?因为Android 7.0+对用户证书做了分级:WLAN证书仅用于Wi-Fi认证,而“VPN和应用”证书才会被OkHttp等网络库读取。这个选项名称在不同厂商UI中差异极大(华为叫“VPN和应用”,小米叫“应用证书”,三星叫“用户证书”),但本质都是指KeyStore中的User类型证书。

4. 实战:用Frida Hook绕过某银行APP的双重SSL Pinning

理论讲完,现在来一场真实的“攻防对抗”。我选取某国有大行手机银行APP(v8.2.5,2023年10月上架)作为案例。这款APP的特点是:同时启用OkHttp内置Pin和自定义TrustManager双校验,且自定义类名做了字符串加密,常规静态分析几乎无法定位。整个过程我记录了完整时间线:从首次运行失败到最终抓到登录请求,共耗时42分钟,其中37分钟花在环境排查,仅5分钟用于核心Hook。

4.1 第一轮失败:为什么基础Hook脚本对它无效?

我先用社区最火的frida-ssl-pinning-bypass脚本(GitHub star 4.2k)执行:

frida -U -f com.bank.mobile -l ssl-pinning-bypass.js --no-pause

结果APP闪退,logcat报错:

java.lang.NoClassDefFoundError: Failed resolution of: Lcom/bank/security/SecureTrustManager;

这说明APP在Application.onCreate()中就初始化了自定义TrustManager,而frida脚本还没来得及注入,类加载器已抛出异常。解决方案不是改脚本,而是调整注入时机:用--no-pause参数让APP启动后不暂停,等它完成初始化再attach。

正确命令:

frida -U com.bank.mobile -l ssl-pinning-bypass.js -o log.txt

即先让APP正常启动,再用frida attach到已运行进程。此时log.txt中终于出现日志:

[+] Hooked X509TrustManager.checkServerTrusted [+] Hooked OkHostnameVerifier.verify

但Charles里依然空空如也——说明Hook成功了,但APP还有第二道防线。

4.2 第二轮突破:动态定位隐藏的HostnameVerifier实现类

我意识到:既然OkHostnameVerifier.verify被Hook了却无效,那APP一定用了自定义HostnameVerifier。但类名被混淆,怎么找?答案是用Frida枚举所有已加载的HostnameVerifier子类

Java.perform(function () { var classes = Java.enumerateLoadedClassesSync(); classes.forEach(function (className) { if (className.includes("verifier") || className.includes("host")) { try { var clazz = Java.use(className); if (clazz.$init && clazz.verify) { console.log("[+] Potential HostnameVerifier: " + className); } } catch (e) {} } }); });

运行此脚本,输出中赫然出现:

[+] Potential HostnameVerifier: com.bank.security.a.b

这就是被混淆的类!接着用Java.use("com.bank.security.a.b")获取其实例,并Hook其verify方法:

var CustomVerifier = Java.use("com.bank.security.a.b"); CustomVerifier.verify.implementation = function (hostname, session) { console.log("[+] Bypass Custom HostnameVerifier: " + hostname); return true; };

4.3 最终验证:抓到登录请求并解析加密参数

当双Hook生效后,Charles终于开始显示绿色200响应。我定位到登录接口/api/v1/login,请求体是标准JSON:

{ "mobile": "138****1234", "password": "U2FsdGVkX1+...", "device_id": "86a2e3c1-..." }

注意到password字段是Base64编码的AES密文。这时Frida的价值再次体现:我不需要逆向解密算法,只需Hook密码输入框的onTextChanged()方法,实时获取明文:

var EditText = Java.use("android.widget.EditText"); EditText.onTextChanged.implementation = function (text, start, count, after) { if (text && text.toString().length === 11 && text.toString().startsWith("1")) { console.log("[+] Detected login mobile: " + text.toString()); } if (text && text.toString().length > 6 && !text.toString().includes("*")) { console.log("[+] Detected raw password: " + text.toString()); } this.onTextChanged.call(this, text, start, count, after); };

运行后,控制台立刻打印:

[+] Detected raw password: 123456Abc!

至此,整个HTTPS抓包闭环完成:从环境搭建、Hook点定位、双校验绕过,到明文参数捕获,全部基于Frida动态插桩实现,无需反编译、无需重打包、无需root。

经验心得:银行类APP常在onResume()中做二次证书校验,所以即使你Hook了所有TrustManager,APP切到后台再切回来时仍可能断连。解决方案是在Hook脚本中监听Activity生命周期,对onResume()方法也做一次checkServerTrusted的强制重置。这个技巧我在3家银行项目中都验证有效,但99%的公开教程从未提及。

5. 进阶技巧与避坑指南:那些文档里不会写的实战真相

Frida Hook HTTPS抓包看似简单,但真正用到生产环境时,你会遭遇一堆“理论上可行、实际上翻车”的细节。这些不是Bug,而是Android系统、JVM机制、APP加固策略共同作用的结果。我把过去两年踩过的23个坑,浓缩成5条血泪经验,每一条都配了可直接复用的代码片段。

5.1 坑:APP使用Conscrypt作为SSL Provider,导致X509TrustManager Hook失效

现象:Hook脚本执行无报错,但Charles仍显示SSL handshake failed。
根因:Conscrypt是Google开源的高性能SSL Provider,它绕过Java层TrustManager,直接调用C++层ConscryptEngineSocket进行证书校验。此时Java层的checkServerTrusted()根本不会被调用。
解决方案:Hook Conscrypt的Native方法。需用Frida的Module.findExportByName()定位so文件中的符号:

// 查找libconscrypt.so中的verifyCertificateChain函数 var libconscrypt = Module.findBaseAddress("libconscrypt.so"); if (libconscrypt) { var verifyFunc = libconscrypt.add(0x12345); // 实际偏移需用readelf -s libconscrypt.so | grep verify Interceptor.replace(verifyFunc, new NativeCallback(function () { console.log("[+] Bypass Conscrypt certificate verification"); return 0; // 返回0表示验证通过 }, 'int', [])); }

注意:Conscrypt的so文件偏移地址随版本变化极大,必须用readelf -s libconscrypt.so在目标APP的APK中提取。我维护了一个常见版本偏移表,可私信索取。

5.2 坑:APP启用Android Network Security Config(NSC),禁止用户证书

现象:证书已安装,Frida Hook也生效,但APP仍拒绝连接代理。
根因:APP在AndroidManifest.xml中声明了android:networkSecurityConfig="@xml/network_security_config",且xml中设置了<certificates src="system"/>,强制只信任系统证书。
解决方案:两种路径。
路径一(推荐):用Frida HookNetworkSecurityPolicy.getInstance(),强制返回允许用户证书的策略:

var NetworkSecurityPolicy = Java.use("android.security.net.config.NetworkSecurityPolicy"); NetworkSecurityPolicy.isCertificateTransparencyEnabled.implementation = function () { return false; // 关闭CT检查 }; NetworkSecurityPolicy.isTrustAnchorsInUserStoreAllowed.implementation = function () { return true; // 允许用户证书 };

路径二:重打包APK,修改network_security_config.xml,但这会破坏签名,需重新签名——违背了“不重打包”的初衷。

5.3 坑:多进程APP导致Hook只生效于主进程

现象:APP有com.xxx.maincom.xxx.push两个进程,Frida只attach到main进程,push进程的HTTPS请求仍被拦截。
解决方案:用frida-ps -U列出所有进程,对每个目标进程单独Hook:

frida -U -f com.xxx.main -l hook.js & frida -U -f com.xxx.push -l hook.js &

或用Python脚本批量处理:

import frida device = frida.get_usb_device() processes = device.enumerate_processes() for proc in processes: if "com.xxx" in proc.name: print(f"Spawning {proc.name}") session = device.spawn(proc.name) script = session.create_script(open("hook.js").read()) script.load() device.resume(session._session_id)

5.4 坑:APP使用Kotlin协程,导致Hook点在suspend函数中无法捕获

现象:Hook了OkHttpClient.newCall().execute(),但没日志输出。
根因:Kotlin协程的suspend函数会被编译成状态机,其实际执行在Continuation对象中,传统Java Hook无法捕获。
解决方案:Hook协程调度器Dispatchers.IOdispatch()方法,或直接HookOkHttpClientenqueue()(非suspend版):

var OkHttpClient = Java.use("okhttp3.OkHttpClient"); OkHttpClient.newCall.implementation = function (request) { var call = this.newCall.call(this, request); console.log("[+] Intercepted request: " + request.url().toString()); return call; };

5.5 坑:Frida脚本内存泄漏,导致APP运行10分钟后OOM崩溃

现象:Hook脚本运行初期正常,但长时间抓包后APP卡死、闪退。
根因:Frida脚本中大量console.log()或未释放的Java对象引用(如Java.use("xxx")返回的对象),会持续占用JS引擎内存。
解决方案:严格遵循“最小日志原则”,生产环境脚本禁用所有console.log(),改用send()发送到Python端处理;且每次Hook后立即释放引用:

var TrustManager = Java.use("javax.net.ssl.X509TrustManager"); TrustManager.checkServerTrusted.implementation = function (chain, authType) { // ... bypass logic }; // 关键:释放Java.use返回的对象引用 TrustManager.$dispose();

最后分享一个我压箱底的技巧:当你面对一款全新APP,不确定该Hook哪个类时,用这条命令快速定位SSL相关类:

adb shell "run-as com.xxx.xxx sh -c 'find /data/data/com.xxx.xxx -name \"*.so\" 2>/dev/null | xargs -r nm -D 2>/dev/null | grep -i \"ssl\|pin\|trust\"'"

它会直接列出so文件中所有含ssl/pin/trust符号的函数,比静态分析APK快10倍。这个命令,我至今仍在每天的项目中使用。

http://www.jsqmd.com/news/864878/

相关文章:

  • 知网AI率稳降10%内?2026年5月4款降AI工具实测推荐 - 仙仙学姐测评
  • BotW Save Manager:打破平台壁垒的《塞尔达传说:旷野之息》存档转换神器
  • Unity3D舞蹈动画穿模根因与实时修正方案
  • 2026 东莞黄金变现攻略|正规回收机构测评与避坑技巧 - 奢侈品回收测评
  • HoRain云--Claude Code 基础用法
  • 如何通过New API快速搭建统一AI模型网关:完整部署指南
  • 中医AI革命:如何用1.8B参数模型实现专业中医诊疗助手
  • 小程序加密流量破解:CE内存定钥+Burp Galaxy自动化加解密
  • 省钱妙招:大润发购物卡回收与使用指南 - 团团收购物卡回收
  • 如何通过DeepEval解决LangChain应用的可观测性与评估难题
  • 小程序加密流量逆向:CE内存定钥+Burp Galaxy自动化加解密
  • 金融合规严、情绪识别难?适用金融行业的好用的AI客服推荐 - 品牌2025
  • ElevenLabs方言适配避坑清单,深度解析TTS模型对平仄调值的误判机制,附广西话声调映射表
  • 2026年智能语音机器人厂商推荐,不只拨号,更支持动态话术生成 - 品牌2025
  • 5步构建你的智能饰品交易数据监控系统
  • 仅限内部技术委员会解密:Lovable CRM的“情绪响应式后端”设计(含Spring Boot情感状态路由源码片段)
  • 企业级应用如何利用 Taotoken 实现多模型智能路由与成本控制
  • AKShare终极指南:如何用免费工具快速获取金融数据
  • 安卓APP HTTPS抓包失效原因与Frida全链路Hook实战
  • 泉盛UV-K5/K6开源固件改造:从百元对讲机到专业无线电设备的终极进化指南
  • PentestGPT:Kali原生AI渗透工具实战部署指南
  • UE5 Pak文件逆向解析:从FModel到Dumper-7的完整技术链路
  • 成本降低15%:橡皮筋批发厂家得力合作案例解析 - 速递信息
  • 类器官微生理模型免疫共培养D3-2
  • 【2026 AI知识管理工具权威榜单】:基于37项技术指标、127家团队实测与Gartner交叉验证的TOP 5终极推荐
  • 四川蓝淼环保科技有限公司:聚丙烯酰胺PAM水处理药剂供应商推荐 - 深度智识库
  • Lovable多语言+多币种商城搭建:跨境卖家必看的5步合规落地法(含Stripe/PayPal双通道实测配置)
  • PentestGPT本地AI渗透测试工具实战部署指南
  • ShawzinBot:在《Warframe》中实现MIDI自动演奏的终极指南
  • 终极指南:5分钟掌握免费AI图像放大神器Upscayl