Jul.2008
JOURNALOFBEIJINGPOLYTECHNICCOLLEGE北京工业职业技术学院学报
№13Vol.7
PE程序加壳中的反脱壳技术研究
张中华
1,2
苏志同
1
(1.北方工业大学,北京100041;2.北京工业职业技术学院,北京,100042)
摘 要:PE文件格式(PortableExecutableFileFormat)是32位Windows操作系统引入的可执行文件格式,首
先介绍了软件保护及用加壳的方式进行软件保护,然后详细的分析了加花指令、SEH(StructuredExceptionHandling)技术及IAT(ImportAddressTable)加密三种加壳保护手段,并给出了相关的原理介绍和主要的实现过程。
关键词:PE文件;加壳;花指令;SEH;IAT中图分类号:TP309.7 文献标识码:A 文章编号:1671-6558(2008)03-27-05
ResearchofAnti2unpackinginPEFileEncryptionShellProtection
ZhangZhonghua
1,2
SuZhitong
1
(1.NorthChinaUniversityofTechnology,Beijing100041,China;
2.BeijingPolytechnicCollege,Beijing100042,China)
Abstract:PortableExecutableFileFormatisakindofexecutablefileformatsofwin32operationsystem.Inthispa2perthesoftwareprotectionandthesoftwareprotectedbyencryptionshellisintroduced,thejunkinstruction,Struc2turedExceptionHandlingandTheencryptionofIATareanalyzedindetail,andtherelevantprinciplesoftheintro2ductionandthemainimplementationaregiven.
Keywords:PEfile;encryptionshellprotection;junkinstruction,SEH;IAT
1概述
随着计算机技术的不断发展,面向各应用领域或行业需求的软件不断地孕育而生。但无论哪种优秀的软件,其内部核心的技术往往是该软件的命脉,一旦被他人窃取或被非法复制,由此受到的经济损失是无法估计的。共享软件是软件业目前世界上比较热门的话题,国内更是如此。成千上万的中国程序员以极大的热情投入到这个领域来,都憧憬着用
辛勤的劳动来获得丰厚的回报,但实际并非如此,绝大多数的人都弑羽而归。其中最大的原因就是共享软件被破解了。
软件防破解一直是计算机安全领域的一个重要课题,软件加密技术是软件保护的重要手段,其中的许多加密措施能给非法拷贝或非法使用造成障碍,在某种程度上增加了破解的难度。目前的防破解技术主要有硬件加密和软件加密两种方式,硬件加密
收稿日期:2008-05-15
作者简介:张中华(1974-),男,北京邮电大学计算机科学与技术专业毕业,北方工业大学计算机技术专业在读工程硕士,助理工程师。
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
28第7卷 北京工业职业技术学院学报
懈地研究后都能找到手工脱壳的方法,对于一些加
壳工具还有专门的脱壳机来完成自动脱壳。因此如何有效的利用各种编程手段来反脱壳是本文研究的重点。3.1花指令
花指令是利用了反汇编时单纯根据机器指令字来决定反汇编结果的漏洞,把无用的数据放在代码段里,这些数据不会影响代码的正确执行,但用反汇编工具时会把这些数据也反汇编出来,使得反汇编出的代码也是错误的,因此无法拿来静态分析。花指令是现在非常流行而且几乎所有加密壳都得使用的技术,花指令大概分两种,一种是行为花指令,也就是某种意义上的代码变形,一种是空间花指令,也就是只占用代码空间,不会被执行到的,但是却可以让反编译引擎产生幻觉的东西。使用花指令对付IDA静态反汇编非常有效,对于Softice和OllyDBG等动态调试软件也有一定的效果。以下为一段简单的C++代码和附加了一些无用的数据,源程序中流程很清晰,程序可以正常执行,但从图1IDA反编译的结果和图2OllyDBG分析的结果来看,已经无法清晰读出程序的流程。
#include“stdafx.h”
intmain(intargc,char3argv[]){
依靠储存在硬件中的信息进行软件保护,这些硬件一般连接在计算机的并口、USB接口,通过软件特殊的指令进行读取和校验,无法轻易进行复制,保护性能较好,但存在造价较高的缺点,一般用于大型的商业软件;软件加密依靠各种复杂的加密算法来增加破解的难度,纯软件加密因经济方便而蓬勃发展,但是这使得程序员要把大量的精力放在与软件功能无关的反破解上,一般用于共享软件的保护。2加壳的定义与分类
加壳的全称应该是可执行程序压缩,是保护可执行文件的常用手段。加壳其实是利用特殊的算法,对EXE、DLL文件里的代码和资源进行压缩。类似WINZIP的效果,只不过这个压缩之后的文件,可以独立运行,解压过程完全隐蔽,都在内存中完成。解压原理是加壳工具在文件头里加了一段指令,告诉CPU,怎么才能解压自己。加壳虽然增加了CPU负担但是减少了硬盘读写时间,实际应用时加壳以后程序运行速度更快。
加壳过的程序可以直接运行,但是不能查看源代码,要经过脱壳才可以查看源代码。当被加壳的程序运行时,外壳程序先被执行,然后由这个外壳程序负责将用户原有的程序在内存中解压缩,并把控制权交还给脱壳后的真正程序。一切操作自动完成,用户不知道也无需知道壳程序是如何运行的。一般情况下,加壳程序和未加壳程序的运行结果是一样的。
加壳软件按照其加壳目的和作用,可分为两类:一是压缩(Packers),二是保护(Protectors)。压缩这类壳主要目的是减小程序体积,如ASPacK、UPX和PECompact等。另一类是保护程序,用上了各种反跟踪技术保护程序不被调试、脱壳等,其加壳后的体积大小不是其考虑的主要因素,如ASProtect、Arma2dillo、Themida等。随着加壳技术的发展,这两类软件之间的界线越来越模糊,很多加壳软件除具有较强的压缩性能,同时也有了较强的保护性能。
使用外壳的好处在于可以很好地防止静态分析、文件补丁。充分利用加壳软件,程序员可以将更多的精力放到程序设计编写中去。一些专用的外壳工具还加入了很强的反跟踪技术。加壳己经成为许多共享软件保护的第一道屏障。3加壳中的反脱壳技术
随着加壳技术的发展,脱壳技术发展也非常快,大部分加壳软件在经历了众多高手们在一段时间不
_asm {
leaeax,combojiangcombojiang:
addeax,0eh emit0xeb _emit0x05 _emit0xeb _emit0xf3 _emit0x83 _emit0x30 _emit0x57
jmpeax _emit0x75 _emit0x21 }
); printf(“HelloWorld!n” return0;
}
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
第3期 张中华,等:PE程序加壳中的反脱壳技术研究29
3.2SEH(StructuredExceptionHandling)的利用
SEH是Windows操作系统处理程序错误或异
常的技术,当Windows检测到异常时,执行线程立即被中断,处理从用户模式转向内核模式,控制权交给了异常调试程序,它负责查找处理异常的方法。程序发生异常时系统的处理顺序如下:
(1)因为有很多种异常,系统首先判断异常是否应发送给目标程序的异常处理例程,如果决定应
该发送,并且目标程序正处于被调试状态,则系统挂起程序并向调试器发送EXCEPTION_DEBUG_E2VENT消息,剩下的事情就由调试器全权负责,如果系统级调试器存在,对于INT1,INT3这样的异常在中断时一般是会选择处理的,因而如果异常处理程序由他们来进入,则不会得到执行,这正好可以用来探测调试器的存在。
(2)如果程序没有被调试或者调试器未能处理
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
30第7卷 北京工业职业技术学院学报
REGISTRATION结构如下所示:
—
EXCEPTIONREGISTRATIONstruc——
prevdd?;前一个EXCEPTIONREGISTRA2
——TION结构
handlerdd?;异常处理例程入口
EXCEPTIONREGISTRATIONends
——我们可以建立一个EXCEPTIONREGIS2
——TRATION结构然后将fs:[0]换成指向它的指针,最
异常,系统就会继续查找是否安装了线程相关的异
常处理例程,如果安装了线程相关的异常处理例程,系统就把异常发送给程序的线程相关的SEH处理例程,交由其处理。
(3)每个线程相关的异常处理例程可以处理或者不处理这个异常,如果它不处理并且安装了多个线程相关的异常处理例程,可交由链起来的其它例程处理。
(4)如果这些例程均选择不处理异常,如果程序处于被调试状态,操作系统仍会再次挂起程序通知调试程序。
(5)如果程序未处于被调试状态或者调试程序没有能够处理,并且程序调用SetUnhandledExcep2tionFilter安装了final型异常处理例程的话,系统转向对它的调用。
(6)如果没有安装最后异常处理例程或者它没有处理这个异常,系统会调用默认的系统处理程序,通常显示一个对话框,你可以选择关闭或者最后将其附加到调试器上的调试按钮,如果没有调试器能被附加于其上或者调试器也处理不了,系统就调用ExitProcess终结程序。(7)不过在终结之前,系统仍然对发生异常的线程异常处理句柄来一次展开,这是线程异常处理例程最后清理的机会。
有两种类型的异常处理句柄,一种是final型的,这是在异常未能得到线程相关处理例程处理,操作系统在即将关闭程序之前会回调的例程,这个例程是进程相关的而不是线程相关的,因此无论是哪个线程发生异常未能被处理,都会调用这个例程。另一种是线程相关的异常处理,通常每个线程初始化准备好运行时fs指向一个TIB结构(THREADINFORMATION2BLOCK),这个结构的第一个元素fs:[0]指向一个
—
EXCEPTIONREGISTRATION结构,EXCEPTION
——
常用的是堆栈,当然也可以用静态内存区。
因此,我们可以利用在程序中用INT3或除以0人为产生异常来执行我们的异常处理程序,在异常处理程序中可以改变DRx(调试寄存器)结合内存校验封杀了万能断点,可以检测是否有调试器存在。另一方面还可以通过SEH改变程序的流程,增加程序跟踪分析的难度。3.3IAT(ImportAddressTable)加密处理在Win32编程中经常遇到各种系统函数,这些系统函数被程序调用但其执行代码却不在程序中,实际上这些代码位于相关的DLL文件中,在调用程序中只保留相关的函数信息,如DLL文件名、函数名等。对于磁盘上的PE文件来说,它无法知道这些输入函数在内存中的地址,只有当PE文件被加载到内存时,Windows的PE装载器才将相关DLL装入,并将调用函数的指令和函数实际所处的地址联系起来,即动态链接。动态链接是通过PE文件的输入表(ImportTable,简称IT)来完成的,输入表中保存的是函数名和其驻留的DLL名等动态链接所需的信息。
在磁盘文件中,PE文件的输入表结构如图3所示:
图3 磁盘文件中的输入表
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
第3期 张中华,等:PE程序加壳中的反脱壳技术研究PE文件运行时,Windows系统加载器首先搜索Orig2inalFirstThunk,如果存在,装载程序迭代搜索数组中
THUNK
31
的每个指针,找到每个IMAGE
MPORTBYI
———
NAME结构所指向的输入函数的地址,然后用函数入口地址来替代由FirstThunk指向的IMAGE
—
DATA数组里的元素值(即用真实的函数—
地址填充到IAT里)。因当PE文件装载内存后准备执行时,图3已转换成图4这种情况了。
图4 PE文件装载内存后的输入表 此时输入表中其它部分就不重要了,程序依靠4结束语IAT提供的函数地址就可正常运行(图4圆圈部在反脱壳技术中,花指令、SEH的利用以及IAT分)。在加壳程序中,模仿Windows装载器的工作加密技术是编程中比较容易实现但反脱壳效果比较来填充IAT中相关的数据,此时内存中就一张IAT表,输入表的其他部分是不存的,这时程序可以正常运行,因为没有完整的IAT,所以无法完成脱壳,即使程序主体被复制也因为没有导入函数无法运行。
一种简单的IAT加密思路是将被加密程序的IAT数据保存于壳内,然后新建立一个IAT导入表,
好的技术,在实际加壳中应该综合应用多种方法来
增加反脱壳的难度。其它实现比较复杂的技术还有虚拟机技术、使用SDK混合编程以及使用驱动等,没有任何一种手段是绝对安全的,唯一能做的就是尽最大能力的拖延脱壳者的时间,让脱壳者那颗并没有无限大的忍耐度的心再也受不了为止,这也就达到了反脱壳的目的。
参考文献:
[1]段钢.加密与解密[M].北京:电子工业出版社,2003[2]RichterJ.Windows核心编程[M].王建华译.北京:机械
里面只导入壳需要使用到的函数,比如LoadLibrary和GetProcAddress两个函数,这样其他函数可以再通过这两个函数来动态定位。
另一种IAT加密方法和第一种加密方法基本上差不多,但是在最后填充函数地址的时候,也就是在壳加载了函数所在DLL和获得函数地址之后并不直接填充到IAT跳转描述表里面,而是保存起来,然后将跳转描述表里面相应位置填充为指向壳的一段代码,这段代码负责动态解密跳转到真正的函数地址。形成一个代理模式,增加修复的难度。
还有一种方法就是模拟了一些系统函数代码,也就是一些函数在壳里自己实现,比如LoadLibrary和GetProcAddress两个函数,使脱壳者难以找到恢复IAT的部分,来增加脱壳者修复的难度。
工业出版社,2006
[3]于淼,孙强.对加壳技术的改进:超粒度混杂技术[J].计
算机应用.2004,24(8)
[4]罗云彬.Windows环境下32位汇编语言程序设计[M].
北京:电子工业出版社,2003
[5]看 雪.软件加密技术内幕[M].北京:电子工业出版
社,2004
[6]张建平,林亚平.PE可执行文件通用加密工具的设计与
实现[J].计算机系统应用,2004,(8)
(责任编辑:王 佼)
© 1994-2010 China Academic Journal Electronic Publishing House. All rights reserved. http://www.cnki.net
因篇幅问题不能全部显示,请点此查看更多更全内容