使用Objection与Frida绕过SSL Pinning实现移动应用抓包分析 📅 2026/6/21 7:02:24 1. 项目概述当抓包工具遇上“沉默”的App最近在分析一个移动应用时我遇到了一个典型的“拦路虎”使用常规的抓包工具如Charles或Fiddler设置好代理后目标App的网络请求要么直接失败要么干脆一片空白一个数据包都抓不到。这通常意味着应用启用了SSL Pinning证书绑定机制。简单来说App不仅会验证服务器的SSL证书是否由受信任的CA签发还会进一步验证服务器返回的证书是否与预先“钉”在App内部的某个特定证书或公钥完全匹配。一旦不匹配即使你安装了抓包工具的根证书App也会直接中断连接让你的抓包工具“失明”。这不仅仅是抓包失败的问题它直接阻断了后续的协议分析、API接口梳理、数据流理解等一系列安全研究或功能逆向工作。面对这种情况我们不能停留在“抓不到包”的挫败感里必须深入App内部从运行时层面去“说服”它接受我们的代理证书。这就是Objection和Frida这对“黄金搭档”大显身手的地方。Frida作为一个强大的动态插桩框架允许我们在App运行时注入JavaScript代码来修改其行为而Objection则是基于Frida构建的一个“瑞士军刀”式命令行工具专门用于移动端的安全评估它封装了许多常用操作包括绕过SSL Pinning让我们的工作事半功倍。本文将详细记录我如何从抓包失败开始一步步使用Objection和Frida定位App中实现SSL Pinning的关键代码位置并最终成功绕过它让网络流量重新“流淌”在抓包工具中的全过程。这个过程不仅适用于安全研究人员对于需要进行合法合规的接口测试、自动化脚本开发的开发者来说也是一项非常有价值的技能。2. 核心思路与工具选型为什么是ObjectionFrida面对SSL Pinning常见的绕过思路有几类修改App的安装包重打包、使用Xposed模块、或者进行动态运行时Hook。每种方法各有优劣。修改安装包如使用apktool反编译定位并修改验证证书的smali代码或so库是一种静态方法。它的优点是一劳永逸修改后安装即可。但缺点也很明显过程繁琐需要对App的代码结构有一定了解对于加固的App反编译本身就是一个挑战而且每次App更新都需要重新分析并修改。Xposed框架同样强大但它需要修改系统环境需要Root并安装Xposed环境并且模块的编写和维护也有一定门槛。我选择ObjectionFrida的动态Hook方案主要基于以下几点考量无需修改App本身所有操作都在App运行时内存中进行不会对原始安装包做任何改动。这保持了App的完整性也避免了因修改不当导致App崩溃的风险。即时生效与可逆注入的脚本在App进程启动时或运行时加载效果立竿见影。关闭Frida或重启App一切恢复原样操作非常干净。强大的定位与探索能力Frida的frida-trace和Objection的搜索命令可以帮助我们快速定位关键的函数和类即使我们对目标App的代码一无所知。跨平台与灵活性Frida支持Android和iOSObjection同样如此。我们编写的JavaScript Hook脚本具有很高的灵活性可以应对各种自定义的验证逻辑。工具链准备Frida核心注入引擎。需要在电脑上安装frida-toolspip install frida-tools并在已Root的Android设备或越狱的iOS设备上运行对应版本的frida-server。Objection基于Frida的命令行工具集。通过pip install objection安装。抓包工具Charles或Fiddler用于最终验证流量是否成功捕获。目标环境一台已经Root的Android测试机本文以Android为例。确保电脑与手机在同一网络adb连接正常且frida-server已在手机后台运行。注意所有操作应在你拥有合法权限的应用上进行例如自己开发的App、明确授权测试的App或用于学习研究的开源App。未经授权对他人的App进行逆向分析可能涉及法律风险。3. 初步侦查与Objection的快速尝试在开始复杂的逆向定位之前我们先尝试用Objection提供的“一键绕过”功能来碰碰运气。很多应用使用了一些常见的SSL Pinning库如OkHttp3、Android的Network Security Configuration等Objection内置的脚本可以自动识别并禁用它们。首先我们将目标App安装到测试机上并确保其未在运行。然后通过Objection启动并注入Appobjection -g com.example.targetapp explore-g参数指定目标App的包名explore命令会启动App并进入Objection的交互式REPL环境。进入Objection后我们首先可以运行android sslpinning disable命令[usb] # android sslpinning disable这个命令会尝试执行一系列内置的Hook脚本针对已知的SSL验证类如TrustManager、CertificatePinner、X509TrustManager等进行绕过。执行完毕后我们切换到抓包工具Charles配置好手机代理然后尝试在App内进行需要网络请求的操作。如果运气好App使用的是标准库且未做深度定制那么此时网络流量应该已经能够被抓取到了。但现实往往更骨感。在我这次遇到的情况中执行disable命令后抓包工具依然一片寂静。这说明了几个问题App可能使用了非标准的或自定义的SSL Pinning实现。App可能使用了Native代码C/C进行证书验证。App可能集成了额外的安全SDK进行了多层次的防护。此时“一键禁用”失效我们的工作才真正开始需要手动定位App中执行证书验证的具体代码位置。4. 深入逆向定位自定义SSL Pinning的关键代码既然通用方法无效我们就需要扮演“侦探”的角色在App的代码海洋中寻找线索。我们的目标是找到那些负责检查证书是否受信任的关键函数。4.1 使用Objection进行初步搜索Objection提供了强大的搜索功能可以帮助我们快速缩小范围。我们可以搜索与“SSL”、“pin”、“certificate”、“verify”等相关的类或方法。[usb] # android hooking list classes这个命令会列出App中加载的所有类但列表可能非常长。我们可以结合grep在Objection的REPL中可以通过!执行系统命令来过滤[usb] # !objection -g com.example.targetapp explore -c “android hooking search classes ssl”或者更精准地我们可以在启动Objection时直接搜索objection -g com.example.targetapp explore -c “android hooking search classes certificate”在我的案例中通过搜索“certificate”我发现了一个非常可疑的类名com.example.security.CustomX509TrustManager。从命名上看这很可能是一个自定义的X509TrustManager实现而X509TrustManager正是Android中负责决定是否信任服务器证书的核心接口。4.2 分析可疑类并Hook关键方法找到可疑类后我们需要查看这个类有哪些方法。使用Objection的android hooking list class_methods命令[usb] # android hooking list class_methods com.example.security.CustomX509TrustManager输出可能类似于public void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String) public void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String) public java.security.cert.X509Certificate[] getAcceptedIssuers()BingocheckServerTrusted方法正是SSL握手过程中客户端用来验证服务器证书的关键方法。如果这个方法内部实现了证书比对逻辑即SSL Pinning那么它就是我们Hook的绝佳目标。4.3 编写Frida脚本进行精准Hook虽然Objection可以快速Hook方法android hooking watch class_method但为了更精细地控制逻辑例如不仅绕过验证还想打印出证书信息用于分析我选择直接编写Frida JavaScript脚本。创建一个名为bypass_ssl.js的文件内容如下Java.perform(function () { console.log(“[*] 开始Hook自定义SSL Pinning...”); // 定位到我们找到的可疑类 var CustomX509TrustManager Java.use(“com.example.security.CustomX509TrustManager”); // Hook checkServerTrusted 方法 CustomX509TrustManager.checkServerTrusted.implementation function (chain, authType) { console.log(“[*] checkServerTrusted 被调用”); console.log(“[*] 证书链长度: ” chain.length); // 打印服务器证书信息可选用于分析 for (var i 0; i chain.length; i) { var cert chain[i]; console.log(“[” i “] Subject: ” cert.getSubjectDN().getName()); console.log(“[” i “] Issuer: ” cert.getIssuerDN().getName()); // 可以进一步打印公钥、序列号等 // var pubKey cert.getPublicKey(); // console.log(“[” i “] Public Key Algo: ” pubKey.getAlgorithm()); } // 关键不做任何验证直接静默返回让验证通过 console.log(“[*] 绕过证书验证直接返回。”); // 注意原方法可能声明抛出异常这里我们什么都不做等于“信任”所有证书。 // 如果原方法有返回值可能需要 return null 或一个空数组具体看原方法签名。 // 对于 void 方法像这样直接结束即可。 }; // 有时也需要Hook checkClientTrusted但服务器验证主要看checkServerTrusted CustomX509TrustManager.checkClientTrusted.implementation function (chain, authType) { console.log(“[*] checkClientTrusted 被调用同样绕过。”); }; console.log(“[*] Hook 设置完成。”); });这个脚本做了几件事使用Java.use获取目标类的引用。重写OverridecheckServerTrusted方法的implementation属性。在新的实现中首先打印一些调试信息证书详情这对于理解App的Pinning逻辑很有帮助。最关键的一步在新的实现中我们没有调用原方法也没有抛出任何异常。对于checkServerTrusted如果它认为证书无效通常会抛出CertificateException。我们什么都不做就等于告诉系统“证书没问题”从而绕过了验证。4.4 注入脚本并测试保存脚本后我们使用Frida命令行工具将脚本注入到正在运行的目标App进程中frida -U -f com.example.targetapp -l bypass_ssl.js --no-pause-U: 连接到USB设备。-f: 启动指定的App。-l: 加载JavaScript脚本。--no-pause: 启动后不暂停让App立即运行。如果App已经在运行我们可以先获取其进程IDPID然后用-p PID的方式注入。注入成功后Frida会输出我们脚本中的console.log信息。此时我们再次操作App触发网络请求。如果看到控制台打印出“checkServerTrusted 被调用”以及证书信息紧接着是“绕过证书验证”那么Hook就成功了。迅速切换到Charles刷新或重新进行网络操作。这一次期待已久的HTTP/HTTPS请求和响应应该清晰地呈现在抓包工具列表中。5. 应对复杂情况与深度排查技巧上面的过程描述了一个比较理想的场景。在实际操作中你可能会遇到更多挑战。5.1 情况一Hook后App崩溃或网络依然失败这可能是因为我们的Hook脚本逻辑有问题。例如原checkServerTrusted方法可能不是一个简单的void方法它可能有返回值或者它内部调用了父类方法。更安全的Hook方式是调用原方法但吞掉异常或者修改其参数。修改后的稳健版Hook示例CustomX509TrustManager.checkServerTrusted.implementation function (chain, authType) { console.log(“[*] 尝试进行服务器证书验证...”); try { // 首先尝试调用原方法如果它正常执行说明证书本身是受信任的比如抓包工具的证书已安装 var result this.checkServerTrusted(chain, authType); console.log(“[*] 原验证逻辑通过。”); return result; // 返回原方法的返回值 } catch (e) { // 如果原方法抛出了异常很可能是CertificateException说明Pinning验证失败 console.log(“[*] 原验证逻辑抛出异常: ” e); console.log(“[*] 忽略异常强制验证通过。”); // 什么也不做或者根据需要返回一个值例如对于返回数组的方法返回一个空数组 // 这里静默吞掉异常相当于验证通过 return; // 对于void方法 // 或者 return null; / return []; 根据方法签名决定 } };5.2 情况二找不到明显的自定义TrustManagerApp可能没有自定义X509TrustManager而是通过其他方式实现Pinning例如使用OkHttp的CertificatePinner搜索类okhttp3.CertificatePinnerHook其check方法。使用HostnameVerifier搜索并Hookjavax.net.ssl.HostnameVerifier.verify方法直接让其返回true。在Native层验证如果Java层找不到验证逻辑可能写在so库里。这时需要使用Frida的Interceptor来Hook Native函数如SSL_CTX_set_cert_verify_callback。这需要更多的逆向工程技能可以先使用frida-trace来跟踪SSL相关的库函数调用如libssl.so中的函数。使用frida-trace进行动态跟踪frida-trace -U -f com.example.targetapp -i “SSL_*” -i “*cert*”这个命令会跟踪App中所有以SSL_开头或包含cert字符的库函数调用生成大量的调用日志帮助我们定位关键的Native验证点。5.3 情况三App存在反调试或反Frida机制一些安全意识较强的App会检测Frida的存在例如检测特定端口、进程名或内存特征。这会导致我们的脚本无法注入或注入后App立即退出。应对策略修改Frida Server名称和端口重新编译frida-server修改其默认的27042端口和进程名。使用强隐藏模式的Frida如frida-server的某些修改版。先绕过反调试使用Objection的android antiroot disable或搜索反调试相关的类和方法进行Hook。常见检测点包括检查/proc/self/status中的TracerPid、检查调试器端口、检查Build.TAGS等。时机把握在App启动完成、反调试检查之后再进行注入。可以使用setTimeout延迟脚本执行或者使用Frida的spawn模式并设置适当的延迟。6. 实操心得与避坑指南经过多次实战我总结出一些宝贵的经验和容易踩的坑环境隔离与稳定性进行移动端逆向最好使用专门的测试机或模拟器。频繁的注入、崩溃、重启会对系统稳定性有影响。推荐使用Android模拟器如Genymotion的快照功能可以快速回滚到干净状态。信息收集先行在动手Hook之前尽可能多地收集信息。使用jadx-gui或apktool反编译APK全局搜索“ssl”、“pin”、“certificate”、“trust”等关键词浏览AndroidManifest.xml看是否有networkSecurityConfig配置。这些静态分析能为你提供重要的路标。Hook的粒度一开始不要试图Hook太底层的通用函数如所有X509TrustManager的实现这可能导致系统或其他合法库的功能异常。先从App自定义的、名称特殊的类开始逐步扩大范围。日志是你的眼睛在Hook脚本中大量使用console.log()打印方法参数、返回值、调用堆栈Java.use(“android.util.Log”).getStackTraceString(Java.use(“java.lang.Exception”).$new())。这些日志是理解程序逻辑和排查问题的关键。注意多线程与性能Hook的函数可能被高频调用如在SSL握手期间。如果你的Hook脚本逻辑复杂或日志输出太多可能会严重影响App性能甚至导致超时。在生产性Hook脚本中应考虑条件性打印日志或优化逻辑。法律与道德边界时刻牢记这些技术只能用于自己拥有合法权限的App、安全研究在合法范围内或学习目的。未经授权对他人App进行逆向和修改是违法行为。从抓包失败到成功绕过SSL Pinning这个过程就像一次精细的外科手术。Objection提供了快速入门的“手术刀”而Frida则给了你进行“显微操作”的能力。成功的关键在于耐心、细致的观察和基于逻辑的推理。当你在Charles中看到那些原本被隐藏的HTTPS请求和响应明文时那种成就感无疑是对你所有努力的最佳回报。这不仅解决了眼前的问题更为你打开了一扇深入理解移动应用安全机制的大门。