使用 Frida 拦截 Flutter 中的 HTTPS 通信

admin 2025年4月21日22:33:14评论12 views字数 13332阅读44分26秒阅读模式

【翻译】Intercepting HTTPS Communication in Flutter Going Full Hardcore Mode with Frida 

简要总结 在本篇博客中,我将分享在研究 Flutter 框架和 reFlutter 工具过程中获得的见解。文章将深入探讨 Flutter 的架构、其内部工作原理和依赖关系,最后深入分析 SSL 验证逻辑。文章最后将探讨 reFlutter 工具的实际工作原理以及我使用 Frida 复制相同行为的尝试。

注意:如果您在评估使用 Flutter 的移动应用时遇到困难,reFlutter 工具是一个很好的选择。本博客并不主张您必须使用 Frida 逻辑,这只是一个探索 Frida 等效方法是否存在的练习。

起因

在最近的一次评估中,我和同事在仅限平板电脑的移动评估中遇到了一个问题。具体来说,我们试图拦截 HTTPS 通信,但客户端应用程序不配合。为了寻找解决方案,我花了一些时间将 Burp CA 证书加载到平板电脑的系统存储中,这个过程相当复杂!

即使最终将 Burp CA 加载到系统存储中,移动应用程序仍然不允许拦截其 HTTPS 流量。我尝试使用各种 Frida 脚本,通过 Wi-Fi 接入点手动路由流量以及一些 Magisk 模块,但都没有效果。然后我回到应用程序的架构,发现它基于 Flutter 框架。

这不是我们第一次与 Flutter 打交道。几年前,另一位同事(嗨,Joe)曾遇到并与 Flutter 斗争过。在对使用 Flutter 的移动应用进行渗透测试时,一个主要困难是它使用原生库来处理通信和其他安全措施。因此,它不依赖于我们习惯看到的传统 Android 逻辑或库(如 OkHttp3)。这也意味着它不容易受到我们通常使用 Frida 和 Objection 应用的篡改技术的影响。例如,SSL 证书固定和验证在多个层次深处完成;Frida/Objection 不容易精确定位负责这些功能的函数。

从我们同事之前的经验中,我们了解到 reFlutter 工具。由于我们当前应用程序使用的确切 Flutter 版本尚未内置到该工具中,我在运行它时遇到了一些困难。经过一些头脑风暴和几个 Docker 容器后,我成功运行了它。该工具完美地修补了应用程序,允许拦截其 HTTPS 通信。但这感觉像是魔法,我感觉自己像个脚本小子。所以我想知道这个工具实际上在做什么,以及是否可以使用 Frida 逻辑复制它?本质上,我想深入了解并揭开 reFlutter 应用的魔法。

Flutter 是什么:101 入门

应用程序开发者面临的一个主要挑战是处理不同的移动生态系统,Android 与 iOS。Flutter 旨在通过提供一个统一的 API 接口,让开发者不必关心这些差异。

从本质上讲,Flutter 是一个 SDK。这个 SDK 暴露了 UI 元素和其他常见元素(例如 HTTP/S 客户端),这些元素在后台映射到 Android 和 iOS 领域中的原生等效项。SDK 通过 Dart 和 C/C++ 集成的组合实现这一点:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

从 Flutter 开发角度来看,开发者编写的代码与通常称为框架(Framework) 的部分交互。该框架是用 Dart 编写的跨平台层。它包括丰富的平台、布局和基础库集。开发者可能使用的许多高级功能都作为包实现,包括平台插件,这些插件可以使用设备的摄像头、显示 WebView、进行 HTTP 通信、显示动画和其他功能。

由于 Flutter 是跨平台的,它需要一个统一的层来转换到 Android 和 iOS。在 Flutter 中,这个统一层被称为引擎(Engine)。引擎是一个便携式运行时,用于托管包含 Android 和 iOS 所需 SDK 的 Flutter 应用程序。它主要用 C++ 编写,并提供原语来支持所有 Flutter 应用程序。

以 Android 为例,Flutter 应用程序将用 Dart 编写。由于 Android 不能原生运行 Dart,框架指令将被转发到引擎。然后引擎包含一个 Dart VM,它将这些指令转换为 Java,最后由底层的 Android 执行。

使用 Frida 拦截 Flutter 中的 HTTPS 通信

然而,还有一个额外的方面需要记住。Flutter 不仅仅是一个 UI 框架。开发者可以用自己的代码扩展引擎中的逻辑。因此,在编译 Flutter 应用程序时,每次都会重新创建引擎 - 更好地称为 AOT(Ahead-of-Time)应用快照。快照包含 Flutter 框架和开发者源代码的机器代码。

考虑到上述内容,当审查 Flutter 移动应用程序的结构时,您会发现它与原生 Android 和 iOS 应用程序非常不同。

以下是一个示例 Android 应用程序的结构:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

注意上面输出中我们有一个 classes.dex 文件,然后是一个包含几个 Flutter 共享库的 lib 文件夹。在常规 Android 应用程序中,我们的重点将是 classes.dex 文件。使用 Jadx,可以逆向 Dalvik 指令。在 Flutter 中,这仍然是可能的;但 Dalvik 指令几乎只是调用嵌入式 Flutter 共享库。

鉴于上述情况,我们的注意力转向共享库文件。Flutter 应用程序通常有一个 lib 文件夹;在其中,您将找到一个特定于应用程序构建架构的目录。在 Android 情况下,您将找到 ARM64 和/或 ARM(即 arm64-v8a)。在该目录内,您将找到两个文件:libapp.so 和 libflutter.so

libflutter.so 文件包含使用操作系统(网络、文件系统等)所需的功能和 DartVM 的精简版本。从移动应用程序评估的角度来看,这个文件成为主要焦点;因为它包含 SSL 证书固定和验证逻辑,以及其他内容!

libflutter.so 文件不包含执行逻辑,也无法自行加载 Dart 源代码。相反,libapp.so 文件是一个包装器(或更确切地说,是围绕它的加载器)。

深入共享库

如上一节所示,基于 Android Flutter 的应用程序主要由两个共享库驱动:libapp.so 和 libflutter.so

虽然从技术上讲,评估不需要知道移动开发者使用的 Flutter 版本,但了解这一点确实有助于交叉引用我们可能想要更改的特定函数或逻辑。

libflutter.so 和 libapp.so 文件都包含一个 MD5 哈希值(称为 snapshot_hash),对应于构建版本。reFlutter 包含一个脚本,可用于 libapp.so 文件来检索此哈希值:

python3 get_snapshot_hash.py libapp.so    **adb4292f3ec25074ca70abcd2d5c7251**

在我们的应用程序案例中,脚本返回了上述 MD5 哈希值。通过这个哈希值,我们可以使用 reFlutter 的 enginehash 文件来确定确切的 Flutter 版本:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

第一列给出了 Flutter 版本,而第二列给出了引擎哈希值。引擎哈希值与包含用于构建该特定 Flutter 版本的所有依赖项和资源的 GitHub commit 相关联。

在我们的示例中,可以在以下位置找到该 commit 及其依赖项:

https://github.com/flutter/engine/blob/1a65d409c7a1438a34d21b60bf30a6fd5db59314/DEPS

你可能想知道为什么上述 commit 的引用很有用。要篡改 Flutter 逻辑,我们需要访问移动应用程序所依赖的特定 Dart SDK。毕竟,Dart SDK 负责网络通信 - 或者在我们的案例中,负责 SSL 证书验证。

通过上面的链接,我们可以确定 Flutter 3.7.12 构建过程中 Flutter Engine 所依赖的确切 Dart SDK commit:

# Dart is: https://github.com/dart-lang/sdk/blob/main/DEPS# You can use //tools/dart/create_updated_flutter_deps.py to produce# updated revision list of existing dependencies.'dart_revision''5b8936496673a285bf8f37472119bc2afb38a295',

再次,我们可以在 Dart SDK GitHub 仓库中搜索该修订版本:

https://github.com/dart-lang/sdk/tree/5b8936496673a285bf8f37472119bc2afb38a295

查看提交历史,我们发现该链接指向 Dart SDK v2.19.6。SDK 可能相当复杂,但主要关注区域是 /runtime/bin 目录。在其中,你会找到许多包含 Flutter 底层使用逻辑的 C/C++ 文件。

如果我们想要篡改 Flutter 应用程序的代理配置,你需要将搜索范围缩小到 socket_android.cc 文件:

https://github.com/dart-lang/sdk/blob/5b8936496673a285bf8f37472119bc2afb38a295/runtime/bin/socket_android.cc#L57

缩小 X509 验证逻辑范围

因此,我们可以使用上一节的步骤缩小特定文件和部分的范围,这些文件和部分可能是我们想要篡改或更改的,以改变 Flutter 应用程序的行为。

不幸的是,当我沿着上述路线深入时,我在 Dart SDK 中找到了对 X.509 的引用,但无法确定 SSL 证书验证是如何完成的。然后我注意到一些文件顶部的头文件:

#include<openssl/ssl.h>#include<openssl/x509.h>

在线搜索揭示,Flutter 并不在 Dart SDK 内部执行 SSL 证书验证。相反,它依赖于第三方 SSL 库。回到之前的 Flutter 依赖链接,我将范围缩小到了 BoringSSL 库:

'dart_boringssl_rev''87f316d7748268eb56f2dc147bd593254ae93198',

这里的版本控制可能不那么重要,因为 BoringSSL 库不会频繁变化。但是,可以使用上面的提交哈希值(最初来自 Flutter 依赖页面)来确定特定的库版本。

在仔细查阅 BoringSSL 库时,我成功确定了 SSL 证书验证逻辑位于 /ssl/ssl_x509.cc 文件和其中包含的 ssl_crypto_x509_session_verify_cert_chain 函数中:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

该函数返回一个布尔值,指示所提供的 SSL 证书是否有效。要绕过验证逻辑,需要修改返回值使其始终为 'true'。

注意:在 Android Flutter 应用程序的上下文中,BoringSSL 库不使用设备的 CA 存储。相反,它使用自己的存储,在某些情况下,甚至可能依赖于 Google 自己的在线验证程序。

然而,上述逻辑深藏在 Flutter 引擎文件(libflutter.so)的多层之下。由于它是原生 C/C++,使用 Frida 或 Objection 时没有直接引用。更复杂的是,当创建 libflutter.so 文件时,BoringSSL 库和 Dart SDK 的符号被剥离。

这时我意识到为什么像 reFlutter 这样的工具存在。你必须在构建时修改 Dart SDK 中的逻辑,甚至在 libflutter.so 文件创建之前。至少,那时我是这么理解的!

使用 reFlutter 工具进行修补

正如我们在前面章节中所看到的,如果想要修改嵌入在 Flutter 应用程序中的逻辑,需要深入研究 Flutter 框架的依赖树。这是一项耗时的工作,你不会想要经常重复。

reFlutter 工具的开发是为了简化在 Dart SDK 中跟踪特定安全措施并对其进行修补的过程,使得对基于 Flutter 的应用程序的测试更容易进行。

该工具的作者(Philip Nikiforov)意识到,由于 libflutter.so 文件中的压缩和符号剥离,直接对文件进行修补或修改将极其困难。基本上,每次都必须进行逆向工程并应用自定义逻辑。因此,这不是一个容易重复的过程。更不用说,Flutter 和 Dart SDK 的每个版本都会改变这个过程。

相反,可以专注于构建到 libflutter.so 文件中的引擎的原始源代码。由于 Flutter 和 Dart SDK 是开源的,生成该文件的构建过程是公开的(在这里和这里有解释)。因此,可以从源代码开始,修改它,然后编译 libflutter.so 文件的自定义版本 - 前提是你需要知道移动应用程序依赖的确切 Flutter 版本,我们前面看到这是可以实现的。

重新追踪官方 Flutter 构建过程的步骤,reFlutter 工具从 GitHub 下载 Flutter SDK 及其所有依赖项。然后创建如下的文件夹结构:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

在这里,可以找到创建 Flutter 快照所需的所有文件:artifactsflutter_patched_sdk_product 和 gen_snapshotlib.stripped 文件夹包含 libflutter.so 引擎,在编译 APK 时将被复制到包含 libapp.so 的文件夹中。

在 lib.stripped 文件夹内,你会找到所有第三方依赖项的源代码。例如:

src/third_party/dart/runtime/bin/socket.cc <--- Proxy capabilitysrc/third_party/boringssl/src/ssl/ssl_x509.cc <--- SSL cert verify

为了修补 BoringSSL 证书验证逻辑,reFlutter 工具使用常规的 Python 文本替换来调整 ssl_x509.cc 文件,从而绕过验证逻辑。修补逻辑可以在这里看到:

https://github.com/Impact-I/reFlutter/blob/main/src/init.py#L325

追踪替换逻辑,之前的 ssl_crypto_x509_session_verify_cert_chain 函数将被调整如下:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

由于 Flutter 框架不遵循 Android 设备的代理设置,reFlutter 工具还包含调整 Dart SDK 的 Socket 创建逻辑(socket.cc)以强制使用代理的功能:

https://github.com/Impact-I/reFlutter/blob/main/src/init.py#L322

在上述情况下,socket.cc 文件将被调整为包含硬编码的代理 IP 地址和端口:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

完成修补后,将从调整后的源代码构建 libflutter.so。然后可以将其嵌入到原始移动应用程序中。之后,可以使用拦截代理,在移动设备上加载自定义 CA 并代理网络流量。

注意:为了避免对每个 APK 和 IPA 重复此过程,reFlutter 作者预先修补了几个版本的 Flutter。这些预先修补的 libflutter.so 文件可以在 GitHub 仓库的 releases 中找到。使用 reFlutter 工具时,它首先检查目标 APK 或 IPA 是否已存在预先修补的文件。如果存在,它只需下载必要的文件。如果不存在,你将不得不手动执行上述步骤 – 一个 Dockerfile 有助于这个过程!

硬核模式:寻找 Frida 等效方案

reFlutter 工具执行的修补是在源代码级别完成的。它运行得非常好并完成了任务!但是,在帮助我的同事时,我开始思考是否可以使用 Frida 实现类似的结果。毕竟,这似乎不是一项不可能完成的任务。至少,对于证书验证逻辑来说不是。更改布尔返回类型很简单 – 大多数情况下!

我的搜索从调查 Frida 和 Objection 在目标移动应用程序运行时可以获取的类和类方法开始:

com.org.package on (google12) [usb] # android hooking list classes  ...  [Landroid.animation.Keyframe$FloatKeyframe;  [Landroid.animation.PropertyValuesHolder;  [Landroid.app.AppOpsManager$RestrictionBypass;  [Landroid.app.LoaderManagerImpl;  [Landroid.app.VoiceInteractor$Request;  [Landroid.app.admin.PasswordMetrics$ComplexityBucket;  [Landroid.app.appsearch.AppSearchSchema$PropertyConfig;  ...

我立即遇到了追踪 libflutter.so 文件中类的问题。Objection 的 'hooking list classes' 功能只显示 Java 类,而不显示原生 C++ 类。因此,它不会显示 libflutter.so 文件中的类。

第二个问题更为复杂。理论上可以钩取 libflutter.so 文件中的函数,前提是该文件导出了这些函数。然而,当我使用 Ghidra 对 libflutter.so 文件进行逆向工程时,我发现该文件导出的函数非常少,而且它们都被剥离和混淆了:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

与 @leonjza(Objection 的创建者)交流时,他提到可以先尝试在移动应用程序运行时定位内存中的 libflutter.so 模块。因为这可能会提供访问其中托管函数的入口。

我启动了 Frida 并将其附加到正在运行的应用程序上。然后使用 Process.enumerateModules() 查看 libflutter.so 文件是否已加载:

[Android Emulator 5554::com.org.package ]-> var modules = Process.enumerateModules()  [Android Emulator 5554::com.org.package ]-> modules  [  ...          {          "base""0x795181600000",          **"name""libflutter.so",**          "path""/data/app/~~QXyGrDRGt5-Lj2Jd_tmopw==/com.org.package-TZxV9QSv5kQ5gUNcaBv5LQ==/base.apk!/lib/x86_64/libflutter.so",          "size"11165696      },  ...  ]

如上所示,libflutter.so 文件确实已加载到正在运行的进程中。这至少允许我们获取该模块的句柄并对其进行检查:

[Android Emulator 5554::com.org.package ]-> var flutter = Process.getModuleByName("libflutter.so")  [Android Emulator 5554::com.org.package ]-> flutter  {      "base""0x795181600000",      "name""libflutter.so",      "path""/data/app/~~QXyGrDRGt5-Lj2Jd_tmopw==/com.org.package-TZxV9QSv5kQ5gUNcaBv5LQ==/base.apk!/lib/x86_64/libflutter.so",      "size"11165696  }

使用上面获取的句柄,我开始探索模块的导入和导出,但很快意识到这并没有多大成效——正如 Ghidra 也确认的那样。例如,导出项仅显示以下内容:

[Android Emulator 5554::com.org.package ]-> var exports = flutter.enumerateExports()  [Android Emulator 5554::com.org.package ]-> exports  [      {          "address""0x79518196cd99",          "name""JNI_OnLoad",          "type""function"      }  ]

没有思路之际,我重新查阅了之前的谷歌搜索结果。在这个过程中,我发现了两篇来自 2019 年和 2020 年的公开博客文章,其中 Jeroen Beckers 使用 Frida 绕过了 Flutter 中的 SSL 证书固定。回顾这些博客文章,我意识到 Jeroen 使用内存模式匹配从 libflutter.so 模块中获取特定函数(即ssl_verify_result):

使用 Frida 拦截 Flutter 中的 HTTPS 通信

我重复了他发布的步骤,但未能复现结果。自然地,Flutter 和 Dart SDK 自 2019 年以来已经发生了变化,这意味着他钩取的函数不再存在或已经改变。尽管如此,这些博客文章确实缩小了哪些函数可能有用的范围。

继续在网上研究,我注意到 Jeroen 在 2022 年发布了一个更新:

https://blog.nviso.eu/2022/08/18/intercept-flutter-traffic-on-ios-and-android-http-https-dio-pinning/

虽然与我们当前的应用程序不完全相同,但他在更新中简要提到 Flutter 已经转移了一些逻辑。在最新版本中,绕过 SSL 证书验证逻辑的目标函数是ssl_crypto_x509_session_verify_cert_chain

没错,这与 reFlutter 使用的函数相同,也是我们之前确定的函数。此时我已经确定了目标函数,但我仍然需要找到一种使用 Frida 在内存中钩取它的方法。为了实现这一点,我必须找到表示函数开始的汇编指令——类似于 Jeroen 上面的脚本。

回到 Ghidra,我搜索了对 ssl_x509.cc 文件的字符串引用:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

通过搜索,我了解到 libflutter.so 文件(至少是我们当前应用程序中存在的文件)包含九个对该文件的引用:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

这些是 Flutter 和 Dart SDK 在 BoringSSL 库中依赖的任何内容的交叉引用。因此,在这九个引用中,我必须找出哪一个是 session_verify_cert_chain 函数。

不幸的是,识别这个函数变成了一项相当困难的任务。请记住,libflutter.so 文件是经过剥离的,这意味着没有可用的符号。例如,当导航到 ssl_x509.cc 文件的交叉引用时,Ghidra 显示的输出如下:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

起初,我不知道如何理解这些交叉引用。我继续在网上搜索,但主要找到的是引用 Jeroen 研究的其他博客文章。直到我设法找到了这篇越南文章:

https://sec.vnpt.vn/2022/04/frida-hooking-va-bypass-ssl-pinning-cho-flutter-aplication/

在这篇博客文章中,作者有以下注释:

session_verify_cert_chain 函数 的定义在文件ssl_x509.cc中。

好的,现在的目标是将上述函数的返回值更改为 true。还要注意,上述函数传递了 3 个参数(这将帮助我们在使用 Ghidra 反编译时找到正确的函数)。

在一瞬间的领悟中,我理解了作者的意思。即使在剥离后,session_verify_cert_chain 函数的参数仍然保持完整。或者简单地说,该函数仍然需要接收三个参数:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

因此,我可以将搜索范围缩小到具有三个参数签名的交叉引用。幸运的是,九个交叉引用中只有一个满足这个要求:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

我不知道这段代码如何映射回原始逻辑。也许这与 Ghidra 对库的逆向有关,但如果没有那篇越南博客文章,我永远不会知道这就是我要找的函数。

之后,在确定了函数后,我可以使用 Ghidra 捕获前几条汇编指令,这些指令(希望)能在内存中唯一标识该函数:

使用 Frida 拦截 Flutter 中的 HTTPS 通信

注意:上面显示的汇编取自 x86_64 libflutter.so 文件;因为我使用的是 Android Studio 模拟器

有了汇编指令后,我重新查看了 Jeroen 的博客文章,并从他之前编写的 Frida 脚本中获取灵感,编写了自己的脚本:

function hook_ssl_verify_result(address) {  Interceptor.attach(address, {    onEnterfunction (args) {      console.log('Disabling SSL validation');    },    onLeavefunction (retval) {      console.log('Retval: ' + retval);      retval.replace(0x1);    },  });}function disablePinning() {  var m = Process.findModuleByName('libflutter.so');  **var pattern =    '55 41 57 41 56 41 55 41 54 53 48 83 ec 38 c6 02 50 48 8b af a8 00 00 00';**  var res = Memory.scan(m.base, m.size, pattern, {    onMatchfunction (address, size) {      console.log('[+] ssl_verify_result found at: ' + address.toString());      hook_ssl_verify_result(address.add(0x00));    },    onErrorfunction (reason) {      console.log('[!] There was an error scanning memory');    },    onCompletefunction () {      console.log('All done');    },  });}setTimeout(disablePinning, 1000);

展示 Frida 脚本

为了结束这篇博客文章,我将首先演示当引入拦截代理(Burp Suite)来代理 Flutter 应用程序而没有任何绕过措施时的失败情况:使用 Frida 拦截 Flutter 中的 HTTPS 通信

上面的截图显示,BoringSSL 库拒绝了 SSL 握手,因为端点的证书现在是自签名的。请记住,即使在系统 CA 存储中加载了 Burp CA,这种情况仍然会发生!

上述问题源于 session_verify_cert_chain 函数返回了无效响应,这导致 SSL 握手被中止。使用 Frida 拦截 Flutter 中的 HTTPS 通信

如果上面的 Frida 脚本有效,我们可以更改该响应,允许 SSL 握手完成。在那一刻,我们就可以拦截网络流量并继续我们的工作!

因此,让我们退出正在运行的移动应用程序,然后在重新启动应用程序的同时运行 Frida 脚本:

 frida -U -l bypass.js -f com.org.package

应用程序启动后不久,Frida 脚本根据内存中的汇编指令钩住了目标函数:使用 Frida 拦截 Flutter 中的 HTTPS 通信

然后是关键时刻!我们能否在通过 Burp Suite 代理的同时捕获 Flutter 应用程序的通信?当然可以!使用 Frida 拦截 Flutter 中的 HTTPS 通信

回到 Frida 控制台,我们注意到被钩住的函数原本会返回 0x1 响应,但我们的脚本修改了它,使其返回 0x0

使用 Frida 拦截 Flutter 中的 HTTPS 通信

因此,我们绕过了 SSL 证书验证步骤,SSL 握手与 Burp Suite 顺利完成,没有任何干扰。自然地,此时移动应用评估将开始关注网络流量及其可能包含的任何漏洞。

附注:代理流量

如果你眼睛敏锐,你可能记得在博客文章前面,我说过 Flutter 不支持代理感知。所以你可能会问自己,我是如何拦截上面的流量的?

由于我使用的是 Android Studio 模拟器,我可以在硬件/模拟级别控制网络。在 Android Studio 中,你可以通过导航到设备的设置->代理为模拟设备设置全局代理:使用 Frida 拦截 Flutter 中的 HTTPS 通信

注意:Android Studio 的较新版本已更改了此设置的位置。但仍然可以进行配置。

上述设置强制所有流量路由到代理,无论应用程序是否支持代理感知。这是处理 Flutter 应用程序时的一个非常巧妙的技巧。

另外,如果你使用的是普通的 Android 设备,你可以通过在设备上设置自定义 /etc/hosts 文件或使用自定义 Wi-Fi 接入点+DNS 服务器并将特定主机名指向 Burp Suite 实例的 IP 地址来实现相同的结果。

结论与总结

你已经读到了这篇博客文章的结尾。这本身就是一项成就!

在这篇博客文章中,我分享了关于 Flutter 框架结构及其不同元素的见解。我们了解到,在底层,它使用 Dart SDK 以及其他几个依赖项(如 BoringSSL)。

通过探索 reFlutter 工具,我们了解到可以在编译并嵌入到 APK 或 IPA 之前修补 Flutter 引擎的原始源代码。为此,reFlutter 工具完成了大部分繁重工作,使修补过程变得更加简单。更重要的是,相关的 GitHub 仓库包含了几个预先修补的 Android 和 iOS 的 libflutter.so 文件。

在清楚了解 reFlutter 工具的内部工作原理后,注意力转向了 Frida 等效方案。使用几篇公开的博客文章、libflutter.so 文件并在 Ghidra 中摸索,我编写了一个 Frida 脚本来钩住 BoringSSL 库中的 session_verify_cert_chain 函数并绕过 Flutter 的 SSL 证书验证逻辑。

需要明确的是,这个 Frida 脚本仅适用于 x86_64 架构和我帮助同事处理的应用程序中的 libflutter.so 文件。也就是说,这篇博客文章的步骤和 Frida 脚本可以作为模板,如果有人很快在真实设备上处理 Flutter,可以为 ARM 和 ARM64 重复这些步骤。

我希望这篇博客文章的内容很有趣。在这项研究之前,我对 Flutter 的运作方式以及为什么基于它的移动应用程序很难进行渗透测试知之甚少。经过探索,它是一个奇怪的存在,需要相当多关于 Dart、C/C++ 和使用 IDA 或 Ghidra 进行逆向工程的见解。

下次再见,保持好奇心,happy hacking!

参考资料

  • https://swarm.ptsecurity.com/fork-bomb-for-flutter/
  • https://blog.nviso.eu/2019/08/13/intercepting-traffic-from-android-flutter-applications/
  • https://blog.nviso.eu/2020/06/12/intercepting-flutter-traffic-on-ios/
  • https://blog.nviso.eu/2022/08/18/intercept-flutter-traffic-on-ios-and-android-http-https-dio-pinning/
  • https://github.com/Impact-I/reFlutter/
  • https://docs.flutter.dev/
  • https://github.com/frida/frida/issues/434
  • https://github.com/frida/frida/issues/2265
  • https://frida.re/docs/javascript-api/
  • https://raphaeldenipotti.medium.com/bypassing-ssl-pinning-on-android-flutter-apps-with-ghidra-77b6e86b9476
  • https://www.horangi.com/blog/a-pentesting-guide-to-intercepting-traffic-from-flutter-apps
  • https://github.com/google/boringssl/blob/master/ssl/ssl_x509.cc
  • https://sec.vnpt.vn/2022/04/frida-hooking-va-bypass-ssl-pinning-cho-flutter-aplication/
  • https://github.com/horangi-cyops/flutter-ssl-pinning-bypass/blob/main/flutter-bypass-sslpinning.js
  • https://blog.nviso.eu/2020/11/19/proxying-android-app-traffic-common-issues-checklist
  • https://medium.com/hackernoon/intercept-https-traffic-on-a-android-emulator-46023f17f6b3

原文始发于微信公众号(securitainment):使用 Frida 拦截 Flutter 中的 HTTPS 通信

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月21日22:33:14
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   使用 Frida 拦截 Flutter 中的 HTTPS 通信https://cn-sec.com/archives/3980224.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息