# ELF恶意软件的静态分析原理和方法（上）

本文，我们将为你提供实用的知识和工具，以进行有效的ELF恶意软件分析。

ELF(Executable and Linkable Format)是Linux下的一种格式标准，Linux中的ELF格式文件一共有四种：

1.可重定位文件(Relocatable File)：这类文件包含了代码和数据，可被用来链接成可执行文件或者共享目录文件，扩展名为.o

2.可执行文件(Executable File)：这类文件包含了可以直接执行的程序，一般没有扩展名

3.共享目录文件(Shared Object File)：这类文件包含了代码和数据，扩展名为.so。

共享目录文件一般可以在以下两种情况下使用：

4.核心转储文件(Core Dump File)：当进程意外终止时，系统可以将该进程的地址空间的内容以及终止时的一些其他信息转储在核心转储文件中。

目前，Linux在操作系统市场上占有很大份额，因为它是开源的，免费的且面向软件开发的，这意味着它丰富的生态系统使开发人员可以轻松访问许多不同的工件。 Linux是Web服务器，物联网，超级计算机和公共云工作载荷的主要操作系统。尽管Linux仅占台式机市场份额的2％，而Windows却占有88％的份额，但我们不应忽视Linux桌面安全性，这一点在2019年7月发现EvilGnome时得到了证明。

Linux几乎无处不在，但在整个杀毒行业中普遍存在低Linux威胁检测的趋势，这促使攻击者近年来积极地将其定位为该操作系统。研究人员已经披露了高度复杂的ELF恶意软件，事实证明，攻击者正越来越多地将Linux恶意软件添加到其武器库中。目前，没有足够的公司搜寻和发布有关最新Linux威胁的IOC和其他信息。此操作系统上有许多未发现的威胁，随着Linux继续流行，我们预计随着时间的推移会暴露出更多的威胁，安全研究人员必须具备分析和理解Linux恶意软件的能力。

本文，我们将为你提供实用的知识和工具，以进行有效的ELF恶意软件分析。这样你将更好地理解ELF格式，并学习如何使用静态和动态方法分析ELF文件。此外，我们还将介绍有用的分析工具并动手实践恶意软件分析。

在深入探讨ELF技术分析之前，先介绍一下ELF恶意软件，回顾ELF威胁状况，解析Linux设备最初是如何攻击恶意软件的，并详细说明为什么它对于安全研究人员或恶意软件分析师来说很重要，以获得ELF分析技能。

**Linux的威胁情况**

Linux攻击主要集中在DDoS僵尸网络和挖矿中。然而，实际比这复杂得多，而这是APT和其他网络犯罪组织开发的更为复杂的威胁的根源。在2019年，研究人员记录了20多个以前未发现的Linux威胁实例。这些威胁包括大规模的挖矿活动、僵尸网络、勒索软件和国家赞助的攻击。

以下Linux威胁只是研究社区已记录的一些示例：

QNAPCrypt：针对Linux文件存储服务器的勒索软件活动，此活动是俄罗斯网络犯罪组织FullofDeep实施的。

Cloud Snooper：Sophos的研究人员在Linux服务器上发现了RAT。该威胁已在Amazon Web Services EC2实例上被识别了，并通过使用不同的工具绕过安全措施加以应用。研究人员认为，由于其工具集和复杂性，攻击是由APT进行的。

Winnti：Winnti：在一家名为拜耳的德国制药公司的系统上发现了与WinntiUmbrella集团有关的后门，这是在野外公开的第一个Winnti Linux变体。

HiddenWasp：针对Linux服务器的RAT。它由一个rootkit，一个木马和一个初始部署脚本组成。在研究人员发现时，尽管使用了来自Mirai和Azazel rootkit等各种开源项目的代码，但仍未检测到该恶意软件。

EvilGnome：Linux桌面后门植入物，与俄罗斯Gamaredon集团有联系。该恶意软件具有许多功能，包括文件窃取，捕获桌面屏幕截屏，录音和模块扩展的功能。

Dacls：RAT与360 Netlab报告的Lazarus APT组有关，研究人员发现该恶意软件的ELF和PE版本，这是Lazarus最早公开的Linux恶意软件。

ManusCrypt：与Lazarus组绑定的RAT。据报道，该恶意软件主要针对Windows。最近发现了该恶意软件的Linux版本，类似于US CERT在2020年5月报告的ManusCrypt变体F PE恶意软件。

MESSAGETAP：由FireEye在电信公司的Linux服务器上发现的Infostealer。这些服务器充当短消息服务中心（SMSC），将SMS消息路由到收件人。该恶意软件旨在窃取SMS流量，并且还与Winnti集团有关。

Linux威胁不仅基于恶意软件利用受害者计算资源的风险来确定。它们还包含有害和侵入性恶意软件，这些恶意软件可能会攻击受害者的私有域。

**ELF恶意软件如何攻击系统？**

与台式机钓鱼不同，台式机是网络钓鱼的常见攻击方法，而希望渗透到服务器和物联网平台的攻击者则不能依靠最终用户代其安装恶意软件。用户无需与浏览器和电子邮件帐户进行交互，这使得网络钓鱼攻击在这些环境中几乎无关紧要。这意味着恶意软件进入系统的入口点必须更具针对性。以下是用于攻击非桌面Linux设备的主要攻击媒介：

1.漏洞利用：攻击者将搜索可利用且未修补的面向公众的组件，以访问系统。例如，NOTROBIN后门背后的攻击者利用Citrix NetScaler中的漏洞CVE-2019-1978传播了恶意软件。攻击者在Sophos XG防火墙中发现并利用了零日攻击（SQL注入远程代码执行）后，就开始了Asnarok木马攻击。错误配置的服务还可以充当攻击者的切入点，攻击者利用配置错误的开放式Docker Daemon API端口后，恶意软件便开始传播。

2.使用有效凭证：默认软件凭证或攻击的凭证。攻击者可以通过多种方法来窃取密码，包括密码喷雾，凭据填充和本地发现。研究人员认为，Cloud Snooper攻击是由攻击者通过SSH访问服务器发起的，而SSH受密码身份验证保护。

3.滥用信任关系：攻击者可以利用进入可以直接访问受害者系统的第三方组织的入口，这些组织对受害人维护的基础结构的访问权限可能有限，但可以存在于同一网络中。例如，攻击者可以在获得这些组织的有效凭据后，违反IT服务承包商的要求，然后将其客户作为目标。

**Linux恶意软件**

不仅是安全厂商完全无法发现的新型复杂Linux恶意软件，而且是常见的恶意软件。 Mirai是一个很好的例子，Mirai是一个DDoS僵尸网络，其源代码被广泛发布，现在许多僵尸网络变体都基于此代码。攻击者使用此特定Mirai样本绕过检测时所需要的就是通过混淆文件的字符串来进行一些签名更改。

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXSO79OYNz8-QbxfJ%2Fimage.png?alt=media\&token=48edca1b-7aa7-4b08-a2ed-8a2fd9d8d42f)

该样本于3月份上传到VirusTotal，检测为零。当时研究人员发表[一篇文章](https://www.intezer.com/blog/linux/evasion-techniques-dissected-mirai-case-study/)，讨论了在检测这种恶意软件和其他Linux威胁时，代码重用分析和基于签名的检测的有效性。到目前为止，该文件的病毒报告只列出了[一个检测](https://www.virustotal.com/gui/file/1fc49503c92bce012cc9210a0490fb3657ff9177d342ce61a86dbabd530b7a15/detection)。

在调查ELF恶意软件时，当前的杀毒解决方案并不可靠。这就是将分析ELF文件添加到技能组中很重要的原因之一。

如果你想了解更多有关为何传统解决方案无法正确检测到ELF的信息，请查看[此文](https://www.youtube.com/watch?v=c2IChPlYgHE)。

**ELF文件分析的挑战**

因此，如果你有一个要分析的可疑ELF文件，应该怎么开始？

互联网上充斥着有关PE文件分析的信息，并且还有各种易于使用的工具和教程。但是，在搜索有关ELF分析的信息时，很容易迷路。缺少有关分析方法论，判决确定和恶意软件规避技术的相关统一信息，以及缺乏最新的开源工具，这可能会让分析变得更困难。

当前没有可用于执行ELF的在线沙箱解决方案，有少数几个Linux沙箱（Limon，Detux和LiSa）需要创建沙箱实例，并且没有得到积极维护。接下里，我们将为你提供相关的ELF分析工具，以执行静态和动态分析。

**初始分析**

我们已经介绍了ELF恶意软件的概况，并说明了恶意软件如何攻击系统。我们讨论了当前缺乏ELF恶意软件可见性的情况，这反映在主要引擎的检测率低于标准以及记录Linux威胁的公共资源不足方面。在本文中，我们将着重于ELF文件分析，重点是静态分析。

初始分析的目的是在不花太多时间在行为分析等高级分析技术上的情况下，尽可能多地收集有关文件的见解。

初始分析过程需要查看文件的不同工件，虽然人工分析本身可能不足以做出决定，但是人工分析的收集可以帮助我们确定分析实际结果。最终结果可能是我们知道文件是什么，或者我们必须进行更深入的分析。

ELF文件中缺少有价值的元数据（例如证书和资源），提供的起点比PE文件弱，尤其是在区分受信任文件和恶意文件时。这就是为什么重要的一点是要考虑分析文件的上下文以及分析所需的结果。无论你是要验证文件是受信任的还是恶意的，还是已经知道文件是恶意的但要对威胁进行分类以确定适当的响应，本文中提供的信息和工具都将帮助你进一步支持初始分析结论。

现在我们将介绍以下工件，并强调它们如何帮助我们收集有关文件的详细信息：

**·** ELF格式静态组件；

**·** 符号；

**·** 段和节；

**·** ELF标头；

**·** 文件输出；

**·** 字符串；

**·** 代码重用；

**·** Packer（一个开源工具,用于从单一配置来源为多平台创建相同的机器映像）；

**·** Interpreter(解析器)；

介绍了分析工具集之后，我们将通过分析野外发现的真实样本来使用它们。

**工具集**

以下是我们将要使用的工具和命令（按字母顺序）：

**·** Detect It Easy

**·** ElfParser

**·** Intezer Analyze

**·** Linux VM

**·** objcopy

**·** Pyinstaller

**·** readelf

**·** shc

**·** strings

**·** UnSHc

**·** UPX

**·** VMprotect

**配置运行环境**

我们将使用Linux虚拟机（VM）作为演示环境。如果你没有Linux VM，请按照此[指南](https://itsfoss.com/install-linux-in-virtualbox/)进行安装。

我们还将编译不同的示例，如果你对此步骤不感兴趣，为方便起见，我们已将编译后的示例存储在专用存储库中，我们将在全文中引用这些示例。

让我们准备我们的环境：

1.运行你的VM；

2.如果你刚刚安装了VM，请确保为计算机截屏；

3.允许共享剪贴板从主机转移到访客：

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXW_kqYZddbGFFtyb%2Fimage.png?alt=media\&token=f565fd72-d4a2-4fc0-a6c2-dd5857d2dfb3)

4.编译以下代码（你可以从[此处](https://raw.githubusercontent.com/intezer/ELF-Malware-Analysis-101/master/Part-2-Initial-Analysis/Article-samples/training-sample)下载编译的文件）：

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXZBACI3-RviAhHiW%2Fimage.png?alt=media\&token=59544877-3f8f-49b6-aa19-48fba1902cd6)

4.1运行nano training\_sample.c，复制代码，然后保存（ctrl + x）

4.2运行gcc training\_sample.c -o training-sample

**ELF格式静态组件**

在本节中，我们将使用编译后的文件来审查与初始分析相关的ELF格式的组件。

在分析ELF文件的静态功能时，readelf命令是最有用的工具。 readelf应该已经安装在Linux VM上。运行readelf -h复查其所有潜在标志，在整篇文章中，我们将使用此命令。

**符号**

符号描述了存储在源代码中的数据类型，例如函数和变量，可以将其导出以进行调试和链接。符号可以帮助我们发现开发人员在代码中使用了哪些函数和变量，从而使我们可以更好地了解二进制文件的功能。我们可能还会找到可以在线搜索的唯一函数或变量名称，以确定它是否是已知文件，换句话说，是否有人已经分析过类似的二进制文件，或者这是否是开源工具。

在实践中，我们也会使用readelf命令读取文件的符号。

首先，运行：readelf -s training-sample

你会注意到输出包含两个表：.dynsym和.symtab。 .dynsym表（动态符号表）存在于动态链接和共享的对象文件中。

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXa8bVIjmxlEFD9VU%2Fimage.png?alt=media\&token=04479c00-d7cb-4fda-824a-1bf51d472e7c)

动态链接的二进制文件使用外部源，例如在运行时存储在操作系统上的libc库。另一方面，将静态链接的二进制文件与这些库一起编译。这意味着静态链接的文件通常比动态链接的文件大。静态链接的文件可能包含大量与库相关的代码，而与实际文件的逻辑无关。

.dynsym表包含动态链接的符号，如libc函数，.symtab表包含源代码中定义的所有符号（包括.dynsym表中的符号）。在上图中，你可以在.dynsym表下看到源代码中使用的libc函数：fgets()，popen()和system()。

符号表可能很长，为简单起见，让我们分别查看每种符号类型。

OBJECT：代码中声明的全局变量。

FUNC：在代码中声明的函数。

FILE：用二进制文件编译的源文件(这是一个调试符号)。如果文件从调试符号中删除，符号表将不包含此类型)。

**readelf -s training-sample | grep OBJECT**

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXcUnNBPLTbypNBqg%2Fimage.png?alt=media\&token=3b3b0df1-5eae-42b6-a35a-54866a2d164d)

如上图所示，我们可以看到文件的源代码中声明的全局变量。

**readelf -s training-sample | grep FUNC**

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXeSg0erIgUrFYEt8%2Fimage.png?alt=media\&token=3843d970-aeda-4bbf-bd59-cfd7e6ce2c82)

我们还可以观察文件源代码中声明的函数以及使用的libc函数，.dynsym和.symtab表中都存在libc函数，这就是为什么我们将它们都列出两次的原因。

**readelf -s training-sample | grep FILE**

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXgrxB-QV0vwESTpd%2Fimage.png?alt=media\&token=64dd5c80-7680-4516-9a98-04b116e11e9b)

用二进制文件编译的源文件是我们的源代码（training\_sample.c）和ctrstuff.c文件。 ctrstuff.c源代码在二进制文件内默认编译。它包含用于在文件的主要逻辑之前和之后运行的函数（例如，register\_tm\_clones，register\_tm\_clones和frame\_dummy）。

通过解析文件的符号，你可以从已编译的样本的源代码中提取标记的函数和变量：

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXiKJTGm7mFbIrVPh%2Fimage.png?alt=media\&token=60ce3cfd-076a-492f-8c6f-91dd72f10fb5)

在[此处](https://www.intezer.com/blog/elf/executable-linkable-format-101-part-2-symbols/)浏览有关符号的更多上下文。

**段和节（Segments and Sections）**

定义及其如何帮助我们：

段，也称为程序标头，描述二进制文件的内存布局，它们是执行所必需的。在某些情况下，段表结构中的异常可以帮助我们确定二进制文件是否已被封装，或者文件是否已自我修改（例如文件攻击器）。

段可以分为几个部分，以进行链接和调试。这些部分是程序标题的补充，它们对于文件的执行不是必需的。通常通过节信息检索符号。唯一的段名称可以帮助我们确定不同的编译方法。

运行readelf -l training-sample：

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXk4vLNG7qTaEvyVq%2Fimage.png?alt=media\&token=f7496f5e-d0b6-49a3-b0e7-e76d003a2560)

可以看出样本中有9个程序标头（段），每种段类型都描述二进制文件的不同组成部分。本文中，我们将专注于PT\_LOAD段。

PT\_LOAD段描述了加载到内存中的代码，因此，一个可执行文件应始终至少具有一个PT\_LOAD段。在上面的屏幕截图中，你将看到样本包含2个PT\_LOAD段。每个段都有不同的标志：

1.RE（读取和执行）标志：这是PT\_LOAD段，描述了可执行代码，文件的入口点应位于此段内。

2.RW（读和写）标志：这是PT\_LOAD段，其中包含文件的全局变量和动态链接信息。

在段的输出中，我们还会得到一个从段到段的映射列表，其顺序与段表相对应。注意，包含可执行代码指令的.text部分被映射到PT\_LOAD R E段，样本的段表结构是“正常”结构的一个示例，如果文件是封装文件或自我修改的文件，我们将看到表的结构不同。

这是封装文件的段表的示例：

![](https://3519990514-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mc9RUlvJLCDxdpf1zh2%2F-MccB4PcHgbMhDAp_7se%2F-MccXrCKyjBSe6nGqzEA%2Fimage.png?alt=media\&token=cc7d52cc-9868-4597-b1a6-4ca760e030fd)

该表仅包含3个段：2个PT\_LOAD段和一个PT\_GNU\_STACK。 PT\_GNU\_STACK的存在向链接器指示文件是否需要可执行堆栈（这也是其大小为零的原因），这不是ELF程序标头表的典型结构。

文件段表中的异常可能是：

1\. Segment types and count：该文件仅包含PT\_LOAD段（和PT\_GNU\_STACK）。

2.标志：文件包含具有所有3个标志（RWE）的段。

**在packer部分中使用这些异常**

我们将在packer中复查唯一节名称的示例并解析各节，点击[此处](https://www.intezer.com/blog/research/executable-linkable-format-101-part1-sections-segments/)以获取有关ELF段和节的更多信息。

注意：恶意软件开发人员通常会删除或篡改文件的符号或节，使研究人员更难以分析文件。这样几乎不可能调试二进制文件。

以下是开发人员可以用来删除文件符号的方法：

1.运行objcopy -S training-sample training-sample-stripped；

2.运行readelf -s training-sample-stripped，你将看到只有一个动态符号表；

删除工具还可以将节和补丁字段保留在ELF标题中（e\_shoff：节标题表的偏移量和e\_shnum：节标题的数量）。结果，该二进制文件将被检测为没有任何节。

本文，我们回顾了ELF恶意软件的威胁概况和背景信息，下一篇文章我们将详细介绍具体的静态分析过程。
