攻击者使用规避技术、模糊处理和执行前的长时间延迟等技巧来躲过虚拟环境的检测。通常,这些技巧都有自定义实现,需要开发者付出大量的努力。
令人惊讶的是,FluHorse 内部没有使用自定义实现的技巧,因为恶意软件的开发者在开发过程中完全依赖开源框架。尽管一些应用程序部分是用 Kotlin 创建的,但恶意功能是用 Flutter 实现的。Flutter 是一个开源的用户界面软件开发工具包,由谷歌创建。它用于为各种平台开发跨平台应用程序,包括用于移动设备的 Android 和 IOS,使用单个代码库。Flutter 之所以成为恶意软件开发人员的一个有吸引力的选择,是因为它使用自定义虚拟机(VM)来支持不同的平台,而且它易于创建 GUI 元素。此外,由于自定义的虚拟机,分析此类应用程序非常复杂,这使得该框架成为 Android 网络钓鱼攻击的完美解决方案。
模拟应用程序
攻击者会为每个国家的目标开发一个虚假应用程序:攻击者努力仔细模仿所有关键细节,以避免引起任何怀疑。
网络钓鱼
让我们看一下如何在应用程序的不同变体中实现网络钓鱼,有趣的是,恶意应用程序不包含任何东西,除了为受害者提供输入可能性的几个窗口副本。没有添加额外的函数或检查。这种刻意的简单性让我们得出结论,恶意软件的开发者并没有在他们创建的编程部分投入太多精力,又或者他们可能故意做出这个决定,以进一步减少被安全解决方案检测到的机会。
不管他们的意图是什么,这个计划都很有效。受害者输入敏感数据后,这些数据会被泄露到 C&C 服务器。与此同时,恶意软件要求受害者在 " 处理数据 " 时等待几分钟。在这一步中,短信拦截功能发挥作用,将所有传入的短信流量重定向到恶意服务器。如果攻击者输入被盗凭证或信用卡数据,然后被要求输入双因素身份验证(2FA)代码,这也会被拦截。网络钓鱼方案如下:
请注意,根据恶意应用程序的类型(针对电子收费、银行或约会用户),可能不需要凭据或信用卡号。
感染链和目标
在受害者的设备上安装恶意应用程序之前,必须先发送恶意应用程序。这就是电子邮件诱饵派上用场的地方。我们追踪了不同类型恶意应用程序的感染链,并在这些电子邮件的收件人中发现了多个知名对象,包括政府部门和大型工业公司的员工。
电子邮件诱饵很好地利用了社会工程,并与随后安装的恶意 APK 的所谓目的一致:支付通行费。
这是一个带有 fetc.NET.tw-notice@twfetc.com 发件人地址:
攻击者使用的恶意 fetc-net [ . ] com 域与 fetc 公司的官方网站 fetc.net.tw 非常相似。
在这个恶意网站上,攻击者添加了一个额外的保护层,以确保只有受害者才能下载 APK:如果目标的用户代理与预期的用户代理匹配,就会下载 APK。此检查是通过客户端 JAVAScript 执行的:
在此步骤中获得的权限将在受害者输入敏感数据后生效。
恶意电子收费 APK
此应用程序仅包含 3 个窗口:
第一个窗口询问用户凭证,第二个窗口询问信用卡数据。所有这些敏感数据都被泄露到恶意的 C&C 服务器。接下来,第三个窗口要求用户等待 10 分钟,因为 " 系统繁忙 "。希望用户关闭应用程序,或者至少在合理的时间内不被怀疑。当用户被 " 系统繁忙 " 消息误导而产生虚假的安全感时,攻击者会执行所有必要的操作,即拦截所有带有 2FA 代码的短信,并利用被盗数据。
这个诱饵应用程序的整个 GUI 看起来像是原始 ETC 应用程序的一个简单副本,用于收取通行费。以下是恶意和合法应用程序入口窗口的可视化比较:
原始应用程序不显示任何用于登录或输入用户凭据的字段。相反,有一个单独的窗口用于此目的:
恶意 VPBank APK
此应用程序仅包含 2 个窗口:
其原理与其他恶意 APK 相同:要求用户输入凭据,然后等待 15 分钟(而恶意 ETC APK 则为 10 分钟)。在此期间,恶意软件拦截所有传入的 SMS,从而为攻击者提供他们可能需要的所有 2FA 代码。请注意,此应用程序不要求提供信用卡详细信息。
恶意和合法应用程序登录窗口之间的比较:
如上所示,即使缺少某些 GUI 元素,恶意副本看起来也很好。
恶意约会 APK
约会应用程序不包含任何窗口。相反,它实际上充当了一个浏览器,引导用户进入钓鱼约会网站。但是,窃取和处理数据的原理是一样的。
我们没有与受害者交互的所有步骤的屏幕截图,因为在撰写本文时,负责处理从该 APK 窃取的数据的恶意服务器尚未激活。根据代码,只有信用卡数据被盗,不需要凭证。
所示消息的翻译如下:
技术细节
与分析纯 Android 应用程序相比,分析基于 flutter 的应用程序需要一些中间步骤才能达到目的。
深度分析
如上所述,Flutter 使用自定义的虚拟环境来支持具有单一代码库的多平台开发。开发过程中使用了一种名为 Dart 的特定编程语言。分析 Flutter 平台代码变得更容易了,因为它是一个开源项目,但仍然是一个繁琐的过程。
让我们来看看在处理 Flutter 运行时的特殊领域时遇到的一些复杂情况。我们用哈希 2811f0426f23a7a3b6a8d8b7e1bcd79e495026f4dcdc1c2fd218097c98de684 解剖了一个 APK。
ARM 的 Flutter 运行时使用自己的堆栈指针寄存器(R15)而不是内置的堆栈指针(SP)。哪个寄存器用作堆栈指针在代码执行或反向工程过程中没有区别。然而,这对反编译器来说有很大的不同。由于寄存器的使用不规范,会生成错误且难看的伪代码。
启动恶意软件分析的一个好方法是确定与 C&C 服务器的通信协议。这可以说明很多恶意功能。里面有一个字符串,对应于我们在钓鱼电子邮件中看到的网站:
然而,当我们试图找到对此字符串的一些引用时,分析失败:
我们的目标是创建对该字符串的引用,以定位执行 C&C 通信的代码。
Flutter -re-demo 和 reFlutter 可以用来处理 Flutter 应用程序,其主要思想是使用运行时快照来创建 Dart 对象并查找对它们的引用。reFlutter 的主要目的是收集函数的名称,而 flutter re-demo 允许我们处理在应用程序执行期间收集的内存转储。
然而,除了内存快照之外,还需要一些更多的运行时信息。Flutter 运行时使用堆来创建对象,并将指向已创建对象的指针存储在一个称为对象池的特殊区域中。指向该池的指针被传递到寄存器 X27 中的方法。我们需要找到对象池的位置。
flutter-re-demo 使用 Frida 收集内存转储并获取对象池地址。如果我们使用在 flutter-re-demo 存储库中可用的 dump_flutter_memory.js 脚本运行 APK,我们会看到所需的地址:
现在我们已经拥有了开始一个高效的逆向工程所需的所有元素。
在用 map_dart_vm_memory.py 加载转储文件并运行 create_dart_objects.py 脚本后,我们现在至少可以看到一些对象:
有一个名为 create_dart_objects.py 的脚本,用于创建 dart 对象。该脚本通过遍历对象池、解析记录和创建对象来工作。脚本没有关于这些对象的信息,脚本会为它们创建以下描述对象格式的结构:
由 create_dart_objects.py 创建的结构
在 Flutter 应用程序逆向工程时,研究人员注意到最后一个字段(unk)经常被用作指针。可以考虑将该字段从简单的 Qword 转换为 OFFSET QWORD。这可能会给带来一些误报,但也可能非常有助于创建参考。因此,我们决定更改由脚本创建的 unkin 结构的字段类型。以下是对原始脚本的更改:
研究人员提到的存储库包含一个用于创建对 Dart 对象引用的脚本:add_xref_to_art_objects.py。当运行它时,该脚本会遍历代码并创建对 create_Dart_objects.py 脚本创建的 Dart 对象的引用。不过此时仍然只有一个对我们感兴趣的字符串的引用,即来自对象池的引用:
我们的第一个想法是,也许根本没有交叉引用?不过这不可能,存在几个交叉引用,例如,这个对象就具有引用:
这是从函数中引用的对象:
引用在函数代码中的外观
通过浏览 add_xref_to_dart_objects.py 的代码,我们可以看到文件 dart_obj_xref.py。该文件还遍历代码,尝试根据寄存器 X27 提取对数据的引用,计算这些引用的偏移量,最后创建 IDA 引用。对代码的分析表明,原始脚本支持访问该对象的两种 ARM 代码变体:
代码是否使用了一些其他指令来引用寄存器 X27?让我们检查一下。为了方便起见,让我们修改脚本,并为用 X27 处理的每条指令添加一条注释:
然后,我们可以检查用 X27 处理的结构的反汇编程序列表,这些构造没有附加对 Dart 对象的注释引用。我们可以通过 IDA 生成一个列表文件并使用 grep 实用程序进行 grep,从而部分自动化这些操作,如下所示:
首先,grep 查找具有 X27 的所有字符串。然后,所有这些字符串都给了第二个 grep 命令,只打印那些不包含对 Dart 对象引用的字符串。因此,我们只看到不受支持的 X27 引用。
当检测到不受支持的 X27 构造时,我们将在脚本中添加支持该构造的代码。经过几次迭代,我们终于获得了对 C&C 地址字符串的引用:
让我们从 sub_70FD611C0C 开始检查这些函数。简要概述显示,当与 C&C 服务器通信时,此函数打算使用路径为 "/addcontent3" 的 HTTP POST 方法来执行:
另一个 Dart 对象也有对这个函数的引用:
对 Dart 对象的引用
当我们遍历这些引用时,我们最终得到了带有以下代码的函数:
此函数为所有传入的短信安装一个侦听器。
为了确保我们做了正确的静态分析,我们在运行时在一个真实的设备上检查了这个函数。实际上,我们捕获了一个发送到 C&C 服务器的 POST 请求。
这是设备收到带有 "Fdsa" 文本的短信后的 C&C 请求示例:
除了被泄露的数据类型和服务器路径之外,函数 sub_70FD61EBC4 和 sub_70FD61EECC 看起来与已经分析的 sub_70FD 611C0C 非常相似。这些函数分别使用路径 "/addcontent" 和 "/addcontent2",用于泄露受害者的凭据和支付卡信息。
DEX 代码中没有服务器通信的痕迹,因此我们可以假设所有通信都位于应用程序的 Flutter 部分。在分析了与命令控制服务器通信相关的所有功能之后,我们可以描述网络协议。
C&C 通信
C&C 协议旨在将数据从受攻击设备发送到服务器。没有命令可以在相反的方向上发送,即从服务器发送到受攻击设备。HTTPS 用于传输数据,并且使用了几个终端。
以下是我们在分析样本中遇到的每个终端的介绍:
总结
这些恶意样本的技术实现由几个层组成,由于功能部分相对简单,我们可以得出结论,恶意软件开发人员没有在编程中投入太多精力,而是依赖 Flutter 作为开发平台。开发人员的主要关注点是 GUI。这种方法使他们能够创建危险且不易被发现的恶意应用程序。使用 Flutter 的好处之一是其难以分析的特性使许多当代安全解决方案形同虚设。