
内容仅用于授权测试、课程学习和自有应用调试请不要用于未授权目标。此篇文章只供技术交流和理解代码bug和安全范围的交流和沟通。代码原理和灵感来源于reflutter功能线上视频地址https://www.bilibili.com/video/BV1YoGK6rEHZ/课件地址下载https://pan.quark.cn/s/250b4035f288提取码7yPuVM 虚拟机地址下载https://pan.quark.cn/s/901c5a403427提取码h7Mm这一期解决什么问题这期视频的主题很直接Flutter 应用遇到双向证书校验时普通抓包代理往往只能看到连接拿不到真正可读的请求。讲者给出的解决思路不是简单关闭校验而是把客户端证书 dump 出来再导入到抓包软件里让代理工具具备参与双向 TLS 握手的证书身份。视频一开始就说明了主线用到的工具、代码、示例 APK 和环境都会放在网盘后面的演示围绕这些材料展开。如果把这期内容压成一句话就是先对齐 Flutter engine 版本再在证书校验链路里导出客户端证书材料最后转换成抓包工具可用的 P12 并验证请求。为什么不能只做“返回 true”很多 Flutter 抓包教程会讲到证书校验绕过比如定位校验函数把结果强制改成成功。这个思路在单向 HTTPS 场景里可能有效因为问题主要是客户端是否信任代理证书。修改这个函数返回值知你解决sslping单向校验 而我们这次要说的是双向证书校验但双向证书校验不一样。服务端会要求客户端拿出自己的证书和私钥来证明身份。也就是说哪怕客户端侧校验被放行如果抓包代理没有正确的客户端证书服务端仍然可能拒绝连接或返回异常结果。关键判断是单向证书可以靠校验返回绕过双向证书还要把客户端证书拿出来。所以本期不是只讲“怎么过校验”而是讲一个更完整的闭环找到 Flutter 版本和对应 engine 源码。找到 X509 证书链校验相关逻辑。在合适位置 dump 证书材料。编译并替换对应的libflutter.so。从设备侧取出证书材料。转换为 P12导入 Reqable。重新触发请求观察是否能拿到明文数据。第一步先确认 APK 的 Flutter 版本和 Engine hash讲者反复强调不能“胡乱编译”。Flutter APK 里包含的 engine 版本不同对应源码、函数位置、构建产物都会不同。拿错版本后面的补丁和替换就很容易失效。视频中使用 Flutter APK 版本查询工具读取示例 APK拿到 Flutter 版本、Dart SDK 版本以及最重要的 engine hash。工具还会给出对应的 engine 源码链接和 Android SDK 相关链接。字幕里特别提到一个坑旧版文章里的仓库地址可能会 404新版本不能照着旧地址直接访问。正确做法是根据当前 APK 查询出来的 hash 和工具给出的地址去下载源码。换句话说这一步不是形式主义它决定了你后面编译出来的so能不能和样本对上。第二步围绕 X509 校验函数做补丁确定版本之后视频进入 reFlutter 相关代码。讲者打开utils.py搜索session_verify_cert_chain把视角落到 BoringSSL 的 X509 证书链校验逻辑上。字幕里说得很清楚“比如我们要去做的是这个 X509。”这就是本期的核心位置。Flutter engine 内部的 BoringSSL 负责 TLS 证书链校验双向证书场景下客户端证书链也会在这个流程里出现。讲者展示的思路不是盲目改 APK而是在源码补丁阶段处理。reFlutter 的补丁模式本质上是在编译前替换 engine 源码中的指定文件和逻辑。这样产出的libflutter.so会带上我们需要的 dump 行为。第三步不仅让校验通过还要把证书写出来视频里对“返回 true”做了一个重要补充。以前单向证书校验里强制返回成功可以解决一部分问题但这次目标是双向证书所以还需要从校验流程里把证书材料写出来。画面中可以看到讲者打开了整理好的ssl_crypto_x509_session_verify_cert_chain相关代码强调在合适位置把证书链内容写入文件最后仍然让流程继续往下走。这里可以把思路理解成两件事第一让证书校验链路不要提前失败。第二把后续代理工具需要的客户端证书材料 dump 出来。双向证书抓包真正麻烦的地方就在第二点。你看到的证书文件不一定都能直接用证书链里可能混着 CA 证书、服务端证书、客户端证书和私钥材料。后面还需要再做筛选和转换。第四步编译并替换对应的 libflutter.so讲者在字幕里提到直接修改 APK 可能会遇到签名校验问题。很多 APK 安装后会校验自身签名重新打包并不一定能顺利运行。因此视频采用的是在受控测试环境里替换安装目录中的libflutter.so。这一步需要用前面查询出来的 engine hash 编译对应版本生成 Android arm64 产物然后把新的so放回设备目录。视频中通过 MT 管理器进入应用相关目录并替换对应库文件。字幕里也提醒不是随便拿一个so放进去就能跑。必须是当前 APK 对应 engine 版本编译出来的产物。否则即使文件名一样也可能因为版本、符号或 ABI 不匹配导致运行异常。第五步dump 出来的 PEM 不能直接当客户端证书用替换完成并重新运行应用后证书材料会被导出。讲者随后打开课件中的证书转换工具说明 dump 出来的文件不是“马上就能用的证书文件”还需要转换。这个工具会分析 PEM 里的证书和私钥判断哪些可以转换成客户端身份。字幕里提到工具会把“有用的证书”吐出来不需要手动管里面到底有多少文件。这里有个很重要的概念能参与双向 TLS 的不是任意一张证书而是证书加匹配私钥组成的身份。如果只有 CA 证书或服务端证书它们可以用于校验链路但不能代表客户端向服务端证明身份。视频里的工具会把可用身份转换成 P12也可以导出 CRT但讲者后面更建议直接用 P12。第六步把 P12 导入 Reqable证书转换之后下一步是在 Reqable 里配置客户端 SSL 证书。视频中打开了 Reqable 的 SSL 证书配置界面导入转换出来的 P12并填写对应域名和密码。这一步是双向证书抓包的关键分水岭。普通 HTTPS 抓包里我们通常只关心设备是否信任代理 CA双向证书里代理工具还要能在访问指定服务时拿出客户端证书。否则流量可能能经过代理但握手或业务请求仍然失败。视频里还提到如果一个 APK 涉及多个证书只导入一个可能会有问题。实际测试时要根据请求域名和证书用途逐个确认。第七步重新触发请求看状态变化配置完证书之后讲者重新打开应用并观察 Reqable。中间也出现过一些不稳定现象比如应用缓存、数据清理、请求返回异常等。字幕里多次提到“重新抓一下”“清除一下数据”“让它去请求看一下”。第一次能看到请求出现但响应仍可能是 403 或错误页。这不一定代表证书 dump 失败它说明请求已经能进入可观测阶段后面还要继续判断是证书身份、域名匹配、业务鉴权还是服务端策略的问题。后面继续导入对应证书、重新触发请求后Reqable 中可以看到正常 HTTP 请求和 200 响应。视频字幕里说“拿到了他的一个数据了”并展示了响应体进入可读状态。这一段是整期视频的验证闭环不是只看到 CONNECT也不是只看到某个错误状态而是能看到请求头、响应状态和业务数据结构。对抓包调试来说这才算走通。P12 和 CRT为什么更推荐 P12视频结尾讲者补充了证书转换的使用建议。CRT 也可以导出但数量可能很多后续需要一个个测试哪个才是正确证书。相比之下P12 更适合直接作为客户端身份导入抓包工具因为它能把证书和私钥打包在一起。字幕里还强调这个工具和代码是配套的不是随便拿一个 PEM 就能转也不是随便一个so就能替换。正确顺序应该是根据 APK 查询 engine 版本。用对应源码和补丁编译。替换对应libflutter.so。运行应用生成证书材料。用配套工具转换 P12。导入 Reqable 并按域名验证。这个顺序一旦乱掉后面看到的错误就会变得很难解释。本期可以带走的几个判断Flutter 双向证书抓包不是单一工具问题而是运行时、证书链、客户端身份和代理配置共同作用的结果。只做证书校验返回成功可能解决单向 HTTPS但解决不了服务端要求客户端证书的场景。编译libflutter.so前必须确认 APK 对应的 Flutter engine hash不能随便拿一个版本替换。dump 出来的 PEM 只是原始材料还需要筛选并转换成抓包工具可用的客户端身份。Reqable 里导入客户端证书后还要结合请求域名、状态码和响应体判断是否真的走通。返回 403 或 Cloudflare 错误页不一定是 TLS 层失败也可能是业务鉴权、缓存、域名匹配或服务端策略问题。资料下载课件地址下载链接https://pan.quark.cn/s/250b4035f288提取码7yPuVM 虚拟机地址下载链接https://pan.quark.cn/s/901c5a403427提取码h7Mm线上视频Bilibilihttps://www.bilibili.com/video/BV1YoGK6rEHZ/结尾这期视频最有价值的地方是把 Flutter 双向证书抓包拆成了一个可验证的工程流程先确认版本再定位校验逻辑再 dump 客户端证书再转换 P12最后用真实请求验证。对学习 Flutter 逆向的人来说这比单纯记一个绕过点更重要。因为真正排查问题时你需要知道失败发生在哪一层是 engine 版本不对是证书没有导出来是 P12 没导入还是请求已经能看见但业务层拒绝。能把这条链路讲清楚才算真正理解了双向证书校验下的 Flutter 抓包问题。