北京物流信息联盟

从具体实现的角度谈谈启发式引擎

安全初心 2021-01-11 13:44:30

启发式引擎的目标是自动化地区分正常程序与非正常程序,因此就要“尽一切可能”利用两者的不同点,哪怕这不同点很无赖,但是只要它是有效的,就是正确的。

早期的启发式引擎主要是用来针对感染文件的病毒,不过这和熊猫烧香之辈有天壤之别。首先以前的文件感染病毒一般都是用汇编写的(听说熊猫烧香是用Delphi写的?)。其次,感染方法上,以前的文件感染病毒是把自己插入感染目标作为其一部分,而不像熊猫烧香那样把感染目标捆绑为自己的一部分。针对以前的文件感染病毒,启发式引擎一般采用查找重定位指令、反EPO(对抗入口点模糊)、虚拟机(对抗多态)等方法,不过谈这个未免太枯燥,大家有兴趣自己查查吧,更何况现在真正意义上的文件感染病毒少之又少。

到最近,恶意程序发生的最大变化就是,它们一般都是用高级语言(VC++、VB、Delphi...)写成的,而且一般都是独立一个文件(不再插入别人感染),以往的启发式引擎面临变革。

我这里打算稍微介绍一些概念,如果你没兴趣的话也可以跳过。 API(ApplicationProgrammingInterface),微软提供给编程者的接口,给编程者提供了极大的方便。举个例子,我要写一个读硬盘文件的程序,如果我要直接操作硬盘,那么意味着我要了解硬盘的基本架构、我要了解不同的分区方式,以及FAT、FAT32、NTFS...,一个小小的程序足以把我累死,而且万一我的程序出问题了,整个硬盘数据可能就报销了。有了API以后,我只要调用ReadFile等API函数,剩余的工作就可以交给Windows做了,而Windows的代码一般可以确保其高效性和可靠性。换句话说,探知程序调用了哪些API就可以大致了解它要干什么了。 PE(PortableExecutables)的格式,这里我只介绍和启发式有关的一小部分。我们的每个EXE文件都有自己的格式,并不是从第一个字节开始就是代码。先介绍一下引入表,其中告诉系统这个EXE要调用哪些API。当系统加载EXE的时候,会根据引入表中的信息,把正确的API函数的位置填入引入表,这样EXE就能正常调用API了。除了用于存放代码的代码段,EXE文件中还有用于存放字符串等数据的数据段。对于更复杂、体积更大的数据,比如图像、运行中要释放的子文件、窗口的布局等则会作为资源存放。

现代的启发式引擎主要面对的是:木马、间谍程序、下载者、已知恶意程序的变种等。现在,启发式引擎很少去分析代码,因为这些东西一般都是由高级语言的编译器做成的,从代码风格上和正常程序没有太多区别(高级语言编译器一般以代码最优化为目标,而病毒的代码则一般以混淆分析者为目标)。即便代码风格异常,也有可能是加壳所致(壳一般是由汇编写成的)。相反的,刚才提到的引入表、数据段中的字符串、资源,成了重要的判断依据。

以下载者为例,下载者一般是一个体积小巧的程序,用来下载一个体积更大、功能更完善的木马。针对这一特点,启发式引擎可以定义如下规则: 1、本身体积很小。 2、引入表中引入了UrlDownloadToFile。这是一个下载者普遍用来下载程序的API,但在正常程序中却很罕见。 3、数据段中存在形如“http://*/.exe”的字符串。 4、引入表中不存在CreateWindow等用于创建窗口,和用户交互的API。

而针对一些进程插入式木马,则可以定义这些规则: 1、引入表中存在CreateRemoteThread,这是进程插入木马普遍采用的API,但在正常程序中很罕见。 2、资源中存在一个DLL文件。可以认为是运行中将要释放的,并进一步检查这个DLL。如果这个DLL符合其他特征就加重可疑度。 3、引入表中不存在CreateWindow等用于创建窗口,和用户交互的API。

可以看到,这些规则都是非常经验化的,并不是说满足这些规则就一定是恶意程序,只是很有可能。实际实现起来当然没有上面说得那么简单,比如,API的调用除了静态调用外还可以动态加载。而且还要考虑误报的问题。比如,可以计算“可疑API数目/总API数目”,避免一定的误报。

关于“加壳”:在我看来,加壳倒也未必是启发式最大的障碍。因为本来就不分析代码,加壳带来的最大影响是一些保护壳会对引入表加密。对于启发式引擎,一定要把它解密。对于多层加壳,启发式引擎可以认为两层以上的多层加壳为病毒,正常程序很少会这么做。这样的话就可以理解为什么有杀软把所有加了北斗壳的文件都认为是病毒,因为除了在中国,用北斗加壳的正常程序几乎看不到~~

关于“沙盒”:似乎已经由杀软把沙盒技术融入与杀毒软件中,KAV7的启发式引擎也用到了“Emulator”,应该跟沙盒指的是一个东西。沙盒应该算作虚拟机的一个发展,传统的虚拟机只是虚拟一个CPU。沙盒除了要虚拟一个CPU以外,还要虚拟操作系统的一些数据结构等,要尽可能和操作系统做到一样。在沙盒中,启发式引擎可以像HIPS一样分析可疑文件的动作,并给出结论。相比HIPS,这应该是更安全的做法。 然而,模拟操作系统的复杂度远胜于模拟CPU。模拟了XP,那么要不要模拟Vista?模拟了用户态,要不要模拟内核态?而内核态的复杂度就更高了... 此外,和虚拟机一样,它也可能遇到“反沙盒”的病毒。虚拟机发展之初,还不很完善,有些多态病毒(一种自我加密、变形的病毒,可以做到每一份病毒副本,特征都不一样)为了防止自己在虚拟机中执行,使用了许多反虚拟机方法,可以用一些不正确的但是在真实系统却可以执行的代码引起虚拟机错误,也可以计算执行特定代码的时间,在虚拟机中运行的时间一般和真实系统不一样。总而言之,就是比较并区分虚拟的环境和真实的环境的区别,沙盒是否会面对类似挑战,还很难说。 另外,沙盒还遇到了性能方面的挑战,不可能每个程序都放到沙盒中跑一跑,这样的话,用户体验会相当糟糕,启发式引擎应当先扫描一下这个文件,然后决定是否有必要放到沙盒中。

当然,我上面说的这些是一些真正有用的启发式技术,并不是一些打着启发式幌子的杂牌引擎,有些启发式引擎只要资源中有可执行文件就报病毒,误报是非常可怕的。不过,需要承认的是,虽然启发式引擎有很多好处,前景也很不错,但是它还是要结合快速的病毒响应速度,想要完全靠启发式还是有点不太现实。