恶意样本分析手册——文件封装篇

加壳器属于一种封装工具,它可以对反病毒软件,复杂的恶意代码分析过程隐藏恶意代码的存在,另外,能缩小恶意代码可执行文件的大小,因此它们在恶意代码编写者中很受欢迎。大部分加壳器都是免费且易于使用的。基础静态分析技术对加壳后的程序毫无办法,要想进行静态分析,必须先将加壳的恶意代码脱壳,这就给恶意样本分析增加了很大的难度。

加壳器综述

加壳可执行文件的两个主要目的是缩小程序的大小,阻碍对加壳程序的探测和分析。虽然加壳程序的种类繁多,但它们都遵循相似的模式:将一个可执行文件转换创建一个新的可执行文件,被转换的可执行文件在这个新的可执行文件中作为数据存储,另外新的可执行文件还包括一个供操作系统调用的脱壳存根(stub)。

在讲解加壳后的文件结构前,先要了解一下加壳器的工作原理。

剖析加壳

所有的加壳器都是将一个可执行文件作为输入,输出一个新的可执行文件。被加壳的可执行文件经过压缩,加密或者其他转换,目的是使他们难以被识别,难以被逆向分析。

多数加壳器用压缩算法压缩可执行文件,通过加密原始可执行文件并且实施一些反逆向技术实现,如对抗反汇编、反调试和反虚拟机等。加壳器既可以打包整个可执行文件,包括所有的数据与资源节,也可以仅打包代码节和数据节。

要保持原程序的功能,加壳程序需要存储程序中的导入函数表信息。这些信息可以用任何格式存储。

脱壳存根

未加壳的可执行程序由操作系统加载,被加壳程序中的脱壳存根也是由操作系统加载,然后它负责加载原始程序。可执行程序的入口点指向脱壳存根,而不是原始代码。原始程序通常存储在加壳程序的一个或多个附加的节中。

我们可以查看脱壳存根,理解脱壳存根的不同部分是脱壳的基本规则。因为脱壳存根不负责执行程序的主体功能,所以它通常很小。另外,它的功能也很简单,只是脱壳原始程序。一般脱壳存根会执行以下三步操作:

  • 将原始程序脱壳到内存中

  • 解析原始可执行文件的所有导入函数

  • 将可执行程序转移到原始的程序入口点(OEP)

加载可执行程序

当加载一个可执行文件时,加载器会首先读取硬盘上可执行文件的PE头部信息,然后根据PE头部信息为可执行文件的各个节分配内存。然后,加载器将这些节复制到分配的内存空间中。

加壳后的可执行文件会组成PE头部,让加载器为它的节分配空间,它的节要么来自原始程序,要么是脱壳存根创建的节。脱壳存根会脱壳每个节的代码,并将它们复制到分配的内存空间中。具体使用哪种脱壳方法随加壳者的目的而定,一般情况下它们会存放在存根中。

解析导入函数表

未加壳的PE文件中有一个节段告诉加载器需要导入哪些函数,同时还有一个节存储了需要导入的函数名字与地址。Windows加载器读取导入信息,确定需要导入哪些函数,然后填入导入函数的地址。

Windows加载器不能读取被加壳可执行程序的导入函数表。对于加壳过的可执行文件,脱壳存根负责解析导入函数表,具体方法取决于使用的壳。

脱壳存根最常使用的方法是仅导入LoadLibrary和GetProcAddress两个函数。脱壳存根在脱壳出原始可执行文件之后,才能读取可执行文件的导入函数信息。为了将每个DLL加载到内存,脱壳存根将调用LoadLibrary函数导入每个函数库。然后使用GetProcAddress获取每个函数的内存地址。

另外一种方法是保持原始导入函数表的完整,让Windows加载器能够加载所有DLL和导入函数。这是最简单的方法,然而静态分析加壳程序就可以发现所有原始导入表,所以这种方法缺乏隐蔽性,此外,导入函数以明文存储在可执行文件中,因此这种方法的压缩性也不理想。

第三种方法是为原始导入表中的每个DLL保留一个函数。分析时,这种方法只能查看每个导入库中的一个函数,因此它比第二种方法的隐蔽性更高,但分析时仍然能够看到原始可执行文件所有的导入库。因为导入库不需要被脱壳存根加载,所以这种加壳方法比第一种方法简单,但脱壳存根仍需要解析大部分导入函数。

最后一种方法是不导入任何函数。加载程序在不用函数的前提下,自己从库中查找所有需要的函数,或者加壳程序首先找到LoadLibrary函数和GetProcAddress函数,然后用它们定位其他的库。这种方法的好处是加壳程序不导入任何函数,因此具有很高的隐蔽性,然而,为了使用这种方法,脱壳存根必须很复杂。

尾部跳转

一旦脱壳存根完成脱壳,它就必须转到OEP运行。转到OEP的指令通常被叫做尾部跳转指令。jump指令是最简单且最流行的转移运行指令。它非常普通,所以多数恶意的加壳程序试图使用ret或者call指令来隐藏这种行为。有时,恶意代码会使用操作系统转移控制的函数来掩盖尾部跳转,例如使用函数NtContinue或者ZwContinue。

图示脱壳过程

1.png

2.png

图一:原可执行文件。它的头部和各节都是可见的,而且代码开始点被设置为指向OEP。

图二:存放在硬盘上的一个加壳后的可执行文件。它的可见部分有新的头部,脱壳存根及加过壳的原始代码。

图三:载入内存中的一个加壳的可执行文件。此时脱壳存根已经脱出了原始代码,原来可执行文件的.text和.data节都可见。但可执行文件的入口点仍然指向脱壳存根,这种情况下,导入函数表一般无效。

图四:一个完全脱壳的可执行文件。导入表已经被重构,入口点也被设置为指向OEP。

加壳程序的标识

下面几条总结了常见的恶意代码是否加壳的特征:

  • 程序中导入函数很少,导入函数仅有LoadLibrary和GetProcAddress时,应该引起特别注意。

  • 当使用IDA Pro打开程序时,通过自动分析,只有少量代码被识别。

3.png

  • 当时用OllyDbg打开程序时,会有程序可能被加壳的警告。

4.png

  • 程序的节名中包含某款加壳器的标识。

5.png

  • 程序拥有不正常的节大小,例如.text节的原始数据大小为0,但虚拟大小非零。

加壳后的文件特征

压缩壳

UPX

恶意代码最常使用的加壳器是Ultimate Packer for eXecutables(UPX)。UPX的特点是开源、免费且易于使用,同时还支持多种平台。UPX用于压缩可执行文件,它为性能而不是安全所设计。UPX之所以流行,是因为它有很高的压缩速度,较小的空间占用,而且压缩例程需要的内存也很少。

upx的工作原理其实是这样的:首先将程序压缩。所谓的压缩包括两方面,一方面在程序的开头或者其他合适的地方插入一段代码,另一方面是将程序的其他地方做压缩。压缩也可以叫做加密,因为压缩后的程序比较难看懂,主要是和原来的代码有很大的不同。最大的表现也就是他的主要作用就是程序本身变小了。变小之后的程序在传输方面有很大的优势。其次就是在程序执行时,实时的对程序解压缩。解压缩功能是在第一步时插入的代码完成的功能。联起来就是:upx可以完成代码的压缩和实时解压执行。且不会影响程序的执行效率。

upx和普通的压缩,解压不同点就算在于upx是实时解压缩的。实时解压的原理可以使用一下图形表示:

1==>2==>3==>4==>5==>6

假设1是upx插入的代码,2,3,4是压缩后的代码。5,6是随便的什么东西。

程序从1开始执行。而1的功能是将2,3,4解压缩为7,8,9。7,8,9就是2,3,4在压缩之前的形式。

1==>7==>8==>9==>5==>6

连起来就是:

最初代码的形式就应该是:7==>8==>9==>5==>6

用upx压缩之后形式为:1==>2==>3==>4==>5==>6

执行时的形式变为:1==>7==>8==>9==>5==>6

UPX压缩可以大大的减少可执行文件的大小,如下图所示

6.png

压缩前的大小

7.png

压缩后的大小

UPX压缩同时会改变文件中的节信息,如下如所示,在压缩前,可执行文件有多个节,但是在压缩后,原始的节只剩下.rsrc,不过添加了UPX增加的两个节。

8.png

压缩前的节信息

9.png

压缩后的节信息

ASPack

ASPack的目的是为了安全,它采用一些技术让脱壳变得十分困难。ASPack使用了自我修改代码,让设置端点和分析它变得困难。

在ASPack加壳的程序上设置端点,程序会立即终止,但是我们可以在栈地址上设置硬件断点完成对ASPack加壳程序的手动脱壳。另外,由于ASPack十分流行,因此很多自动脱壳程序都能对其进行脱壳。

经过ASPack加壳的可执行文件会多出一个节.aspack,而原始的文件中并没有这个节。

10.png

ASPack会对程序的代码进行压缩

11.png

使用IDA加载可以发现,经过ASPack加壳的文件显示的函数和导入表中的函数比原始程序明显少了很多。

12.png

图:经过ASPack加壳的可执行文件

13.png

图:原始的可执行文件,部分截图

PECompact

PECompact是一个能压缩可执行文件的工具,通过压缩代码、数据、相关资源使压缩能达到100%,由于在运行时不需要恢复磁盘上压缩后的数据,所以与没有压缩的程序在运行时没有明显的速度差异,在某种程度上还有所改善。它同样也是一款能压缩可执行文件的工具(支持EXE、DLL、SCR、OCX等文件)。相比同类软件,PECompact提供了多种压缩项目的选择,用户可以根据需要确定哪些内部资源需要压缩处理。同时,该软件还提供了加解密的插件接口功能。

经过PECompact压缩的程序在大小上有明显的变化

14.png

通过查看节信息也可以看出差异

15.png

图:原始节信息

16.png

图:经过PECompact压缩的节信息

FSG

FSG同上面三个一样,也是一种压缩壳,由于fsg壳比较常见,可以使用软件将其识别出来。

17.png

经过fsg压缩后,软件的大小明显变小了

18.png

节的数量也变少了

19.png

加密壳

Themida

Themida是一个非常复杂的壳,拥有多种功能。其中大部分功能是反调试与反逆向分析,这保证了他是一个非常安全的壳,难以脱壳和分析。

Themida包含组织VMware、调试器以及Procmon分析的功能。除此之外,Themida还有一个内核模块,这让分析变得尤其困难。运行在内核中的代码显示很少,并且分析程序通常运行在用户空间中,因此分析会受到很多限制。

由于Themida拥有这么多功能,因此使用它加壳文件变得很笨重。除此之外,与大多数壳不同,Themida代码会在原始程序运行后一直运行。

有一些专门为脱壳Themida文件而设计的自动脱壳工具,它们的成功与否,取决于程序加壳时使用的Themida版本和设置。

如果不能自动脱壳,则另一种较好的策略是使用ProcDump工具从内存中转储不在进行调试的进程。ProcDump是微软提供的一个工具,用来转储一个Windows进程的内容。设计他的目的是与调试器一起工作,但是它本身不是调试器。ProcDump的最大优点是在不停止进程或者调试进程的情况下,转储进程中的内存。这对转储那些使用了反调试机制的壳来说,非常有价值。甚至当不能调试一个可执行文件时,仍可以使用ProcDump工具转储正在运行可执行文件的脱壳内容。这个过程并不能完全恢复可执行文件,但那时他能让我们在代码上使用Strings工具并做一些分析。

如下图所示,可以看出文件的大小明显增加。

20.png

通过查看节的信息,发现此工具会对节进行修改,并且添加了节,从而造成文件大小增加。

21.png

使用IDA加载加壳后的文件,只能看到很少解析出来的函数和导入函数

22.png

ASProtect

ASProtect是一款非常强大的Windows 32位保护工具,它拥有压缩、加密、反跟踪代码、反-反汇编代码、CRC校验和花指令等保护措施。它使用Blowfish、Twofish、TEA等强劲的加密算法,还用RSA1024作为注册密钥生成器。还通过API钩子(API hooks,包括Import hooks(GPA hook)和Export hooks)与加壳的程序进行通信。甚至用到了多态变形引擎(Polymorphic Engine),反Apihook代码(Anti-Apihook Code)和BPE32的多态变形引擎(BPE32的Polymorphic Engine)。并且ASProtect为软件开发人员提供SDK,实现加密程序内外结合。

此款加壳工具的界面如下所示:

11.png

从图中可以看出来,通过这款工具可以为可执行文件添加不同的功能,同时,也将增加可执行文件的大小。

12.png

通过对比查看节的信息也可以看到,加壳后节的大小和数量也发生了变化。

13.png

VMProtect

VMProtect是一款纯虚拟机保护软件。它是当前最强的虚拟机保护软件,经VMProtect处理过的代码,至今还没有人公开宣称能还原。虽然保护强度高,但是会影响程序速度,因此在一些对速度要求很高的场合就不适用了。

这款工具拥有很多选项,可以按照字节的目的进行修改。

14.png

此次的重点不在于加壳,所以都选用默认的值,直接进行编译。然后VMProtect会生成一个.vmp.exe的文件。使用ResourceHacker来查看原始文件和经过加壳的文件,对比图如下所示:

15.png

16.png

通过查看资源文件的差异,可以发现很多资源文件都被VMProtect隐藏了起来。接下来再来看看节信息:

11.png

通过对比节信息可以发现,经过VMProtect加壳后的应用程序多了两个节。

资源段

有些恶意样本会将它所需要的工具之类的文件隐藏在资源段中,然后在运行的时候将其释放出来。一种是申请内存,将所需要的工具释放到内存中,也就是所说的无文件运行,通过这种方法可以躲避杀毒软件的静态检测,比较安全。一种是直接将所需的工具释放到磁盘中,这种方法就没有上一种方法安全,由于将文件释放到了磁盘中,很容易被杀毒软件查杀。

12.png

如上图所示,样本名为EternalRocks.exe,在它的资源段中包含了shadowbrokers.zip,这个压缩包中包含了样本将要使用的漏洞利用程序。样本会在运行时,将这个压缩包释放到磁盘中并进行解压,然后执行文件夹中的漏洞利用程序进行攻击。

固件格式

对于路由器固件的格式和前面所说的PE文件格式大不相同,下面通过几个小工具对固件的解析结果来对其格式进行说明。

首先使用file命令来查看一下它的文件类型。

13.png

可以看出来它的文件类型为data,接下来使用hexdump工具来查看文件中的每一个字节,使用-C命令可以设置hexdump输出为hex+ASCII的方式,便于阅读。通过这个工具输出的txt的文件很大,通过看输出文件的前一部分可以知道此固件是属于dlink的。

14.png

作为初始的信息收集,strings可以说是最常用的工具之一,它可以显示文件中所有可打印的数据。从获得的string信息中可以看到它的类型为firmware。

15.png

binwalk会分析进制文件中可能的固件头或者文件系统,然后输出识别出的每个部分以及对应的偏移量。从下图的输出结果中可知该固件采用的是Squashfs文件系统。

16.png

封装工具

有些软件是使用python,ruby等语言写的,如果没有特定的环境的话就无法运行,为了便于部署,就出现了一些工具,将脚本源码编译成可执行文件,编译后的文件就可以脱离特定的环境运行了,在这里首先介绍三个打包程序,知道它的过程后,更有利于理解打包后的文件结构。

python封装工具-Pyinstaller

直接使用Python开发的软件时有许多不方便的地方,如需要安装特定的Python环境,需要安装依赖库。为了便于部署,需要将Python源代码编译成可执行文件,编译后的可执行文件就能脱离python环境运行了。可以通过Pyinstaller来对文件进行封装。

最简单的使用方式是运行pyinstaller hello.py来生成可执行文件,其中hello.py是需要编译成可执行文件的源代码,通过这种方式生成的可执行文件默认位于当前文件夹的dist目录下,dist目录位于pyinstaller所在的myscript目录中。

1.png

通过这种方式同时还会生成build文件夹,这个文件夹存放的是编译过程中的生成的临时文件,可以删除。在dist文件夹下,除了有exe文件外,还有若干个其他文件,这些文件都是运行时必须的。

2.png

这给我们发布软件带来了不便,如果希望编译出的exe文件不依赖其他文件,可以添加-F选项:

pyinstaller –F hello.py,这时候再看,文件夹里面只有一个exe文件。

3.png

下面对其常用的参数进行说明:

参数 说明
-w

–windowed

–noconsole

使用windows子系统执行,当程序启动的时候,不会打开命令行。
-d

–debug

产生debug版本的可执行文件
-c

–console

–nowindowed

使用控制台子系统执行(默认)(只对Windows有效)
–distpach DIR 设置产生的应用程序的存放位置,默认是./dist
–workpath WORKPATH 设置临时文件的存放目录,默认为./build
–specpath DIR 设置spec文件的存放目录,默认在当前文件夹下
-n NAME

–name NAME

设置生成的应用程序和spec文件的名称
-p DIR

–paths DIR

设置导入路径(和使用PYTHONPATH效果相似).可以用路径分割符(Windows使用分号,Linux使用冒号)分割,指定多个目录.也可以使用多个-p参数来设置多个导入路径
–key KEY 使用指定的key加密python代码
-i FILE.ico or FILE.exe or FILE.icns

–icon FILE.ICO or FILE.exe or FILE.icns

指定生成的应用程序的图标
–uac-admin 指定生成的应用程序需要管理员权限运行

Ruby封装工具-exerb

目前将Ruby代码打包成exe可执行文件主要有3种方式:

1.rubyscript2exe,年久失修,打包出来的文件太大,不对源文件进行加密,运行时将源码释放到一个临时目录后执行;

2.exerb,已经支持Ruby1.8.7和1.9,可以设置程序的版本信息,图标等,打包后的可执行文件可以用UPX压缩,功能很强大,执行时不释放源文件出来,对程序加密较好,但是对waitr这种需要调用DLL的gem支持不是很好,无法进行打包处理;

3.ocra,原理和 rubyscript2exe差不多,可定制性不强,但是对 Ruby1.8.7和1.9以及 waitr都提供很好的支持,而且打包的时候会对文件进行压缩,打包后程序的大小可以接受,程序图标和版本信息暂时不能定制,但是默认图标比 rubyscript2exe要好看,如果对源码保护要求不是很强,用exerb又无法成功打包的时候,可以采用这个。

这里以比较强大的exerb为例进行说明。先执行mkexy hello.rb,会自动生成一个hello.exy的配置文件,打开此配置文件,加入下面的代码:

这些代码用来配置生成的exe文件的一些信息,如图标、版本等;

然后执行exerb main.exy,生成最终的可执行文件,该可执行文件比较大,可以使用UPX进行压缩,压缩率可以达到70%以上。

ASP源码封装工具NetBox

NetBox是一个使用脚本语言进行应用软件开发与发布的开发环境和运行平台,使用 NetBox,可以完全使用脚本语言(比如 VBScript,Javascript) 创建出稳定高效的应用软件,并且可以平滑移植到从 Windows 98 到 Windows .NET Server 的全部操作系统上。适用范围对于 WEB 应用,可以迅速将已有的 iis+asp 的应用平滑移植到NetBox应用中,除极少数高级编程外,代码不需要任何修改,同时NetBox还提供大量扩展部件,使得 WEB 应用更加方便。由于NetBox可以将全部代码最终发布成为应用程序,保护了开发人员的利益和代码的完整性。同时,NetBox还可以方便地编写更多的桌面应用、系统服务器应用、定制网络应用等等。

简单的形容就是把ASP文件打包成一个EXE文件,并且不需要在调试的机器上安装IIS即可正常调试。下面通过一个简单的实例来认识NetBox的使用。

  1. 第一步肯定是要下载安装NetBox。此步略过

  2. 创建一个空的目录在任意位置,再在其中创建一个名为“main.box”的文件,将下面的代码内容复制到文件中:

注:Set host = httpd.AddHost(“”, “wwwroot”) 中的wwwroot就是放网站程序的目录。也就是一定要与第3步将建立的目录名称相同!

3.复制ASP应用:上文我们提到网站主目录为wwwroot目录,则我们需要在第2步我们建立的目录下建立一个wwwroot目录,为了方便测试,我们编写一个简单的asp文件,编辑内容如下:只是在网页中输出HelloWorld。

4.调试运行asp程序:双击我们第2步创建的box文件,这时候就出现了一个红色的.b的托盘图标

1.png

然后再在浏览器中输入127.0.01,如果页面中出现了“HelloWorld”,就说明我们以上的配置非常成功。

2.png

5.编译:我们可以将ASP程序打包成.exe程序,就需要执行exe (netbox deployment wizard就是部署向导),然后点击“Select Folder”按钮,找到第二步建立的目录再点击“Brower”按钮,输入要生成的执行文件的目录和名称,选择好之后直接点击“Build”开始编译。

3.png

6.找到生成的exe文件,双击运行,然后在浏览器中输入0.0.1,同样可以看到网页中的HelloWorld字样。

原文:http://blog.nsfocus.net/malicious-sample-analysis-manual-file-encapsulation/


发表评论

(必填)

(必填)

(以便回访)