加壳器综述(第14课)

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

 

六、图示脱壳过程

图示脱壳过程
图示脱壳过程

 

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

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

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

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

 

七、加壳程序的标识

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

  • 程序中导入函数很少,导入函数仅有LoadLibrary和GetProcAddress时,应该引起特别注意。
  • 当使用IDA Pro打开程序时,通过自动分析,只有少量代码被识别。

 

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

 

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

 

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

 

八、加壳后的文件特征

 

1、压缩壳

 

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压缩可以大大的减少可执行文件的大小,如下图所示:

UPX压缩前的大小

UPX压缩前的大小

 

UPX压缩后的大小

UPX压缩后的大小

 

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

UPX压缩前的节信息

UPX压缩前的节信息

 

UPX压缩后的节信息

UPX压缩后的节信息

 

ASPack

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

 

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

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

 

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

ASPack加壳

 

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

经过ASPack加壳的可执行文件

经过ASPack加壳的可执行文件

 

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

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

 

PECompact

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

 

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

 

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

原始节信息

原始节信息

 

经过PECompact压缩的节信息

经过PECompact压缩的节信息

 

FSG

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

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

 

节的数量也变少了:fsg压缩字节

2、加密壳

 

Themida

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

 

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

 

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

 

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

 

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

 

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

Themida

 

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

Themida节信息

 

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

IDA加载加壳

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,实现加密程序内外结合。

 

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

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

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

ASProtect加壳后节的大小和数量

 

VMProtect

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

 

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

 

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

 

经过VMProtect加壳的文件

 

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

 

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

头像
Python数据分析与机器学习实战
  • ¥ 398.0元
  • 市场价:498.0元
iOS应用开发指南第10季:数据持久化
  • ¥ 59.0元
  • 市场价:99.0元
【uni-app实战教程】系列全套
  • ¥ 1980.0元
  • 市场价:2980.0元
iOS应用开发指南第15季:性能优化视频课程
  • ¥ 99.0元
  • 市场价:159.0元

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: