第 1 章 反病毒软件入门

第 1 章 反病毒软件入门

反病毒软件通过监测手段保护计算机免受恶意软件感染,并适时移除恶意软件,使计算机脱离感染状态。在本书中,恶意软件(malicious software或malware)也称为“样本”,它有许多种类,包括木马病毒、感染型病毒、Rootkit、下载者病毒、蠕虫病毒等。

本章将阐述反病毒(antivirus,AV)软件的定义及其工作原理。同时,还将介绍反病毒软件的简史,并简单分析反病毒软件的演进。

1.1 何谓反病毒软件

反病毒软件是旨在为原生操作系统(如Windows、Mac OS X)提供更好安全防护的特殊软件。在多数时候,它被用作预防性安全方案。一旦防护失效,反病毒软件就成了从操作系统中彻底清除恶意软件、使计算机摆脱感染的解决方案。

反病毒软件使用多种技术来侦测潜藏在操作系统深处且带有自我保护功能的恶意软件。高级恶意软件可能会使用未公开的系统功能和混淆技术来躲避侦测并持续潜伏在计算机中。如今,用户面临着来自四面八方的安全威胁,反病毒软件的使命就是处理出自可信以及不可信来源的恶意文件。反病毒软件要处理的恶意文件来源有:网络数据包、邮件附件、浏览器漏洞攻击利用程序、文档阅读器,以及运行在操作系统上的可执行程序。

1.2 反病毒软件的历史与现状

最早的反病毒产品在严格意义上只能算作扫描器,因为它们仅是在可执行程序中侦测恶意代码的命令行扫描程序。不过,在此之后,反病毒软件经历了天翻地覆的变化。比如,反病毒软件已不再含有命令行式的扫描器了。如今,大多数反病毒产品有了图形用户界面(graphical user interface,GUI),会检查操作系统或用户程序产生、修改或访问的每一个文件。它们还配备了防火墙功能,来侦测通过网络感染计算机的恶意文件;安装了浏览器插件,来侦测基于Web的漏洞利用攻击;为网络支付创造了安全隔离环境;从系统驱动底层,实现了自我防护和安全沙盒功能等。

在DOS和其他古老的操作系统时期,软件产品只需要跟随系统更新而更新。但在此之后,随着数量惊人的恶意软件产生,反病毒软件也不断提高了更新的频率。20世纪90年代,反病毒企业在一周内只会收到几个关于恶意程序的报告,而且往往都是文件感染型病毒;而如今,它每天都会收到成千上万完全不同的恶意文件样本(这里的“不同”是指类似MD5、SHA-1文件散列值不同)。这迫使反病毒企业致力于开发自动化侦测方案,类似启发式引擎(heuristics),通过动态和静态两种手段来侦测未知病毒。第3章和第4章将会深入探讨反病毒软件的工作原理。

金钱是驱使恶意软件和反病毒软件产品频繁升级对抗的根本原因。早期,病毒制作者(virus creator或vxer)往往只是因为想博人眼球或挑战自我而编写一些采取新破坏手段的文件感染型病毒。如今,恶意软件开发已经成了敲诈计算机用户的暴利产业。无论是偷取用户在诸如eBay、Amazon、Gmail等网站的账户登录凭证,还是入侵用户在支付平台(如Paypal)的账号,其最终目的是一致的:不择手段地获取尽可能多的钱财。

恶意软件制作者可以通过病毒窃取你的Yahoo邮箱或Gmail登录凭证,然后以你的名义向别的用户大量扩散垃圾邮件或传播恶意软件。他们还可以使用窃取到的信用卡信息将你账户内的资金转移到恶意账户上去,或是通过“钱骡”洗钱。因此,他们的犯罪活动正变得越来越难以追踪。

另一种日益典型的恶意软件主要用以监听民众的通信,其幕后推手是权利机构、灰色组织,或是向权利机构出售间谍软件的黑客公司。也有一些恶意软件开发是为了破坏他国的基础设施。

恶意软件也可以为了监视政府机构、公司或个人而开发。监视软件的两个典型案例是FinFisher和Hacking Team。政府、执法部门和安全部门采购商业版的FinFisher和Hacking Team来监视罪犯和嫌疑人。

恶意软件的换代升级以及恶意软件市场大量的资本涌入,迫使反病毒工业在最近十年内发生了显著的改变和升级。遗憾的是,在攻防博弈中,反病毒软件一直处在被动局面。通常,反病毒软件厂商无法侦测未知病毒,尤其是那些在开发过程中采取了一些免杀手段的恶意软件。这其中的原因很简单:免杀是恶意软件开发的重要一环;对于攻击者来说,保证开发的恶意软件不被反病毒软件查杀,时间越长越好。无论是否合法,许多商业版本的恶意软件包都有一定的支持服务期限。在服务支持期间,恶意软件产品会根据反病毒软件或是操作系统的查杀情况适时作出更新。另外,恶意软件也会通过升级来应对和修补bug,添加新功能等。反病毒软件也可能成为攻击目标,比如有幕后支持的Mask病毒,就利用了卡巴斯基的一个零日漏洞。

1.3 反病毒扫描器、内核和产品

通常,计算机用户可能只会把反病毒软件简单地看成一个软件套装,但是攻击者必须要有从更深层次来分析反病毒软件的能力。

本章将详细阐释反病毒软件的各个组成部分:反病毒内核、命令行扫描器、GUI扫描器、守护进程或系统服务、文件系统防护驱动、网络防护驱动,以及反病毒软件的其他一些功能模块。

以ClamAV为例,它是一个扫描器,也是目前仅有的一款开源反病毒软件。它的工作方式是,根据特征扫描计算机内的恶意软件,每查杀到一个恶意软件,就生成一条警告消息。不过,ClamAV既没有使用基于文件行为的启发式查杀系统,也没有修复感染文件的能力。

换句话说,反病毒内核就是反病毒产品的核心。比方说,ClamAV的核心是libclam.so库。所有可执行文件脱壳程序、压缩程序、加密程序和保护程序等都由这个库实现。所有有关解包并遍历PDF文件中被压缩的数据流内容,或枚举并分析OLE2容器中内容(如Microsoft Word文档)的代码,同样包含在这个库中。使用该反病毒内核的包括一款叫作clamscan的扫描器,除此以外还有clamd实时防护程序,以及其他一些程序和库,比如一个叫作PyClamd的Python bindings API程序。

提示 反病毒软件常常会使用不止一个反病毒引擎或内核。例如,F-Secure除使用自家的反病毒引擎外,还融入了Bitdefender的授权引擎。

反病毒产品可能并不会向第三方开发者提供直接调用其内核的方法,但可能会提供调用命令行扫描器的接口。另外还有一些反病毒产品甚至连调用命令行扫描器的接口都不会提供,而是仅仅提供GUI扫描器或是GUI程序,用来配置实时防护或该产品中的其他模块,以侦测和修复恶意软件感染。反病毒套装还会提供一些其他的安全防护程序,如安全浏览器、浏览器安全工具栏、自我保护驱动、防火墙等。

可以看到,反病毒产品其实是软件公司提供给顾客的防护软件包。其中,扫描器用来扫描文件和目录,而包含核心功能的反病毒内核被用在了反病毒软件更高级别的组成部分中,比如GUI扫描器或命令行扫描器。

1.4 反病毒软件的典型误区

大多数反病毒软件用户深信,安全防护产品是坚不可摧的防弹墙,只要装上了反病毒软件,他们的电脑就安全了。这种观念是不正确的,但如果你去反病毒软件论坛的评论区去看看,却会发现这种观点十分常见,比如:“我感染了某某病毒。怎么会这样?我可是安装了某某某杀毒软件的啊!”

要解释安装了反病毒软件并不能获得百分之百保护的原因,让我们先来看看现代反病毒软件的基础功能:

  • 侦测程序中已知的恶意代码及其风险操作;

  • 侦测文档和网页中的已知恶意代码;

  • 侦测网络数据包中的已知恶意代码;

  • 基于先前的已知经验,修改并发现新的恶意行为和代码。

你可能已经注意到,上面提到的每一条功能中都有“已知”二字。因此,反病毒软件产品不是战胜恶意软件的终极方案,一款反病毒产品是无法识别未知恶意代码的。很多反病毒软件的营销信息可能会让用户误以为,只要安装了他们的反病毒软件就可以高枕无忧了;但是这与实际情况大相径庭。无论反病毒产品的广告是如何宣传的,反病毒软件目前只能基于已知的恶意软件特征进行防护。除非基于之前的已知模式(动态或静态),否则反病毒软件是无法识别新型未知风险的。

1.5 反病毒软件功能

所有反病毒产品都有一系列相同的功能特性,因此,了解一款产品有助于触类旁通,从而了解其他的产品系统。下面是反病毒产品共有的功能:

  • 能够扫描压缩文件和加壳的可执行文件;

  • 能够按需或实时扫描可执行文件或目录;

  • 拥有防止恶意软件攻击反病毒软件进程的保护驱动程序;

  • 拥有防火墙和网络流量监控功能;

  • 拥有命令行和图形界面工具集;

  • 拥有守护进程或服务;

  • 拥有管理控制台。

接下来,我们将简要地讨论一些反病毒产品中都会有的功能特性,以及一些只有在特定反病毒产品中才会有的高级功能。

1.5.1 基础功能

为了保证可用性,一款反病毒产品应该拥有满足日常需求的基础功能。例如,最基本的要求是,反病毒扫描器和引擎工作起来应该快速,且内存消耗非常小。

  1. 使用本机语言

    大多数反病毒引擎(除了旧版本的Malwarebytes,它不是一个完整的反病毒产品)都是采用非托管语言/本机语言编写的,比如C、C++或是两者的结合。反病毒引擎必须在不影响系统性能的情况下,运行得足够快。本机语言就很好地满足了这点需求,因为当代码编译之后,就能在目标主机的CPU中全速运行。对于托管式软件来说,已编译的代码会被映射成字节码格式。这往往需要额外的层结构来提供运行环境:一个内置在反病毒内核中的、知道如何执行字节码的虚拟机解析程序。

    举例来说,Android DEX文件、Java以及.NET编写的代码都需要虚拟机来运行已编译的字节代码。正是因为不需要额外的层结构来提供运行环境,就使得类似C、C++的本机语言的性能优于前面提到的托管式语言。不过,使用本机语言编写程序也有不少缺陷。采用本机语言编写程序难度更大,也更容易造成内存及系统资源泄漏,引发内存崩溃(堆溢出、use-after-free、double-free)问题,或写出造成严重系统安全问题的bug。相较于托管式编程语言(如.NET、Python和Lua),无论是C还是C++都没有针对内存崩溃问题的防护机制。本书第3章将会详述解析器中的漏洞,同时揭秘为什么这是反病毒软件出现bug的重灾区。

  2. 扫描器

    反病毒产品的另一个共有功能是扫描器。在大多数情况下,它们可能只是有用户图形界面或命令行的手动扫描器。当用户想要检测某些文件、目录或系统内存的安全性时,这类工具就有了用武之地。另外,还有一种后台实时扫描器,我们一般称之为实时防护或者反病毒常驻防护进程。这类扫描器会实时监测分析操作系统或其他程序(比如浏览器)的每一个读取、创建、修改操作,来防止系统内文档和程序被病毒感染,阻止已知恶意文件执行。

    反病毒软件的实时防护模块是所有攻击面中最有意思的一个部分。比方说,Microsoft Word文档中分析模块的一个bug可能会在用户下载了一个恶意的Microsoft Word文档以后,使实时防护模块被利用而执行任意代码,即便用户并没有打开这个恶意文档。无独有偶,反病毒软件邮件防护模块中的一个安全漏洞,也可能会在用户接收了一封带有恶意附件的邮件以后,当反病毒软件相关模块试着去分析邮件客户端创建的临时文件安全性时,触发恶意代码。当这类可以造成拒绝服务的bug被触发以后,除非用户手动重启相关防护功能,否则反病毒软件将会陷入持久的崩溃和死循环中。

  3. 特征码

    反病毒产品的扫描器借助特征码库,侦测并发现恶意文件或文件包。同时,每一种特征码都有对应的恶意软件名称。这里所说的特征码,也就是已知恶意文件独一无二的文件“指纹”。一些典型且基础的特征码扫描功能基于简单的“指纹”匹配技术(比方说,匹配发现特定的字符串,如EICAR字符串)、CRC校验码或文件MD5散列值。如果仅依靠类似MD5值的密散列特征码的匹配技术,只能有针对性地检出特征码对应的单个文件(散列值只能标识特定的文件)。如果基于模糊逻辑的特征码技术,将特定的数据区块作为CRC校验算法的匹配特征,就可以识别检测到相对多的恶意文件(与标识整个文件正好相反)。

    正如第8章所述,不同的反病毒产品所使用的特征码技术也会有所不同。特征码技术有的基于CRC校验技术,也有的基于PE文件头特征、可执行文件入口代码复杂性,以及整个或部分可执行文件信息熵。有时,文件特征码识别技术也基于对进行可执行程序入口点代码分析时发现的基本块,除此以外还有其他一些特征码检测技术。

    每一种特征码检测方式都各有利弊。比如说,一些反病毒产品使用的特征码检测技术十分精准,不容易发生误报(将一个正常文件标记为恶意软件),另外一些则十分敏感,误杀率很高。举个例子,如果反病毒软件把以“MZ\x90”字节开头的Microsoft Word文档作为一条查杀特征,那么无论文档是否正常,都将被标记为恶意软件。因此,为了避免误报,在添加特征码的时候必须慎之又慎,否则就会造成图1-1中显示的误报或者漏报(恶意软件被误认为是正常文件)。

    图1-1 Comodo Internet Security针对反汇编软件IDA的误报

  4. 压缩包和归档文件

    反病毒内核的另一个关键部分是支持压缩和归档文件格式,其中包括ZIP、TGZ、7z、XAR和RAR等。反病毒软件需要能够解压缩并查杀该类文件内部子文件的安全性。除此以外,反病毒软件还需要支持检测类似PDF文件的数据流压缩文件格式。因为反病毒软件必须支持种类繁多的文件格式查杀,而在此过程中需要处理传入的大量数据,所以反病毒产品的代码在这块特别容易产生漏洞。

    本书将会探讨影响多款反病毒产品的此类漏洞。

  5. 脱壳程序

    脱壳程序通常是单个或一系列程序,用以去除保护或压缩可执行程序的文件壳。恶意可执行文件通常会使用通用的加壳程序或(通过合法或非法手段获得的)私有加壳程序来压缩打包,保护自己的内部代码结构。相较于之前提到的压缩和归档文件,反病毒引擎需要支持脱壳的种类更加纷繁复杂。而且,恶意软件为了隐藏内部逻辑,躲避反病毒软件的查杀,几乎每个月都有新的文件壳出现。

    一些加壳程序,比如UPX,只是简单地对可执行文件进行了压缩。因此,对加了UPX壳的文件进行脱壳操作,是一件十分容易的事情。但是,也有一些十分复杂的加壳程序,它们通过将恶意软件真实代码转化成字节码,然后随机抽取一段或多段代码载入虚拟机运行。因此,想要针对使用此类在虚拟层实现的程序进行脱壳处理,进而了解恶意软件内部的逻辑结构,是一件十分耗时而且困难的事情。

    通过使用反病毒引擎中的CPU模拟器,一些文件壳可以被脱除(详见稍后的内容);也有一些脱壳程序仅采用了静态方法。另外还有一些更为复杂的脱壳程序,融合了之前提到的这两种技术——先将程序在模拟器中运行,获取到某些关键数据(如加密数据大小、加密算法种类、加密密钥等),接着基于这些数据采用更快的静态技术脱壳处理。

    当你查找反病毒产品中的漏洞时,和处理压缩、归档文件的模块一样,脱壳模块也是经常能够发现漏洞的地方。反病毒产品支持脱壳的文件壳种类繁多,而且每年都在不断增长。其中有一些文件壳只被特定的恶意软件家族使用,所以与此相关的反病毒程序逻辑代码可能在第一次写完后,再也没有被验证或审计过。

  6. 模拟器

    除了ClamAV外,市面上其余的反病毒引擎都支持非常多的模拟器。反病毒引擎中使用最广泛的模拟器是Intel x86模拟器。一些高级的反病毒产品还支持AMD64或ARM模拟器。模拟器不仅限于常见的CPU种类,比如Intel x86、AMD64或ARM,也有一些为编程语言虚拟机开发的模拟器。比如有一些模拟器就被用来检查Java字节码、Android DEX字节码、JavaScript,甚至是VBScript和Adobe ActionScript的安全性。

    要识别或绕过反病毒产品采用的模拟和虚拟机技术十分容易,只要找到不一致的地方即可。比如,对Intel x86模拟器来说,反病毒引擎的开发人员不大可能会模拟所有可用的x86指令。对于使用了模拟器的反病毒软件的更高级组成部分,比如说针对ELF或PE文件的运行模拟环境,开发者就更不可能执行整个操作系统环境,或是操作系统提供的每一个API了。因此,想要找到欺骗和识别模拟器的方法其实十分容易。本书讨论了多种绕过和识别模拟机的技术。本书第三部分专门介绍了如何针对特定的反病毒引擎,编写漏洞利用程序。

  7. 错综复杂的文件格式

    开发反病毒引擎是一项十分复杂的工程。之前我们讨论了反病毒软件普遍带有的多个功能,可以想象要实现这些功能需要耗费多少时间和精力。更糟糕的是,为了检测出潜藏在各类格式文件中的漏洞利用攻击程序,反病毒引擎需要支持种类繁多的文件格式。这些文件格式(不包括压缩和归档文件)有:OLE2容器文件(Word或Excel文档);HTML页面、XML文档,以及PDF文件;CHM帮助文件和旧版本的Microsoft帮助文件格式;PE、ELF和MachO等可执行文件;JPG、PNG、GIF、TGA和TIFF等图像文件格式;ICO和CUR等图标文件;MP3、MP4、AVI、ASF和MOV等视频、音频文件;等等。

    每当出现针对新型文件格式的漏洞利用攻击程序,反病毒引擎就必须针对该类文件格式增加支持。有些文件格式太复杂了,以至于原开发者们处理起来都有问题,其中两个典型的案例是:微软的Office文件格式和Adobe的PDF文件格式。考虑到反病毒软件开发者没有针对此类文件格式的处理经验,而且又需要对此类文件做逆向操作,我们为何期待他们能比文件作者写出更好的程序,并能更好地处理此类文件呢?正如你所想到的,这正是反病毒软件最容易出现问题的地方,而且在很长一段时间内都将是这样。

1.5.2 高级功能

接下来将讨论一些反病毒产品广泛使用的高级技术。

  1. 流量监控和防火墙

    从20世纪90年代到2010年左右,一种名叫“蠕虫病毒”的新型恶意软件十分常见。这种病毒通常使用一个或多个远程漏洞来攻击计算机的软件。有时,蠕虫病毒会使用默认的用户名及密码组合,通过在Windows CIFS网络内以随机的文件名大量复制自身来感染整个网络。著名的案例有:“I love you”、Conficker、Melissa、Nimda、Slammer和Code Red。

    正是由于许多蠕虫病毒借助网络感染计算机,反病毒软件出现了筛查计算机的上传下载流量的功能。为了实现该目的,反病毒软件会在计算机内安装分析网络流量的驱动,防火墙会侦测并阻断已知的攻击。和之前提到的若干功能一样,蠕虫病毒肆虐的时代已经过去,但该部分仍然是反病毒软件bug的重要来源。反病毒软件的流量监控和防火墙功能已经很多年没有更新了,实际上该部分功能已经被遗弃了,因此目前它正遭受着大量漏洞的困扰。这也是第11章将讨论的反病毒软件的远程攻击点之一。

  2. 自我保护

    在反病毒软件保护用户免受恶意软件侵扰的同时,恶意软件也在不断变种升级,以躲避反病毒软件的查杀。有一些恶意软件通过某些技术,关闭或禁用反病毒软件的服务。因此,许多反病毒软件通过系统内核驱动实现自我保护功能,来对抗通过ZwTerminateProcess禁用反病毒软件防护的恶意操作。有些反病毒产品的自我保护技术通过阻断以某些参数调用OpenProcess来关闭反病毒软件进程,或拒绝外部进程通过调用WriteProcessMemory向反病毒防护进程注入代码。

    这类技术一般通过系统内核驱动实现,当然也有一部分保护功能仅在用户环境层实现。直到2000年,反病毒软件开发人员才意识到,仅在用户环境层实现功能毫无用处。但截至目前,仍有许多反病毒产品在犯这种错误。本书第三部分将会对此进行详细讨论。

  3. 反漏洞利用程序

    包括Windows、Mac OS X(现在称为macOS)以及Linux在内的操作系统,目前纷纷推出了对抗漏洞利用的功能,也称为“安全保护措施”,比如最近开发出来的随机地址空间分配技术(address space layout randomization,ASLR)和数据执行保护技术(data execution prevention,DEP)。这也是一些反病毒套装提供(或曾经提供)反漏洞利用程序解决方案的原因。一些反漏洞利用技术的原理是在每一个可执行程序的进程和动态链接库上应用ASLR和DEP技术。当然也有一些更加复杂的技术。例如,通过在用户和系统内核层hook特定进程的操作,通过筛查放行部分操作。

    遗憾的是,很多反病毒软件提供的反漏洞利用程序仅在用户环境层通过hook技术实现。Malwarebytes的反漏洞利用程序就是一个例子。随着微软EMET(Enhanced Mitigation Experience Toolkit)方案的出现,大多数带有反漏洞利用程序的反病毒软件相形见绌,显得十分不完善,而且很容易被绕过。

    对于反病毒软件来说,拥有反漏洞利用程序功能在某些情况下比没有还要糟糕。一个典型案例是采用了ASLR技术的Sophos栈溢出保护系统(buffer overflow protection system,BOPS)。来自谷歌的安全研究员Tavis Ormandy发现其中一个DLL文件没有启用ASLR保护。该DLL文件本意是,在类似Windows XP这样没有引入ASLR技术的操作系统内,实现类似ASLR的技术;但实现该功能的DLL文件本身却没有启用ASLR。结果,在支持ASLR的系统中(如Windows Vista),ASLR保护技术最终因为该DLL文件被禁用。

    更多关于反病毒软件工具功能实现过程中的问题,将在本书的第四部分讨论。

1.6 总结

本章开篇介绍了反病毒产品的历史、各种类型的恶意软件,以及反病毒软件和恶意软件技术的演变。我们可以发现,在这场攻防斗争中,恶意软件似乎一直占据上风。在本章的后半部分,我们一起剖析了反病毒套装的各个组成部分,并对其中的基础和高级功能进行了简要的讨论。这也为后续章节中针对各个功能进行详细介绍做了铺垫。总而言之,本章可以归纳为以下内容。

  • 在过去,反病毒软件并不是很完善。由于只有命令行式扫描器以及一个特征码数据库,反病毒软件常被称为扫描器。随着恶意软件不断演进,反病毒软件也在不断升级。如今,反病毒软件已经有了启发式引擎,而且致力于保护浏览器、网络数据包、邮件附件以及文档文件。

  • 恶意软件类型有许多种,包括木马病毒、恶意软件、感染型病毒、Rootkit、蠕虫病毒、下载者病毒、漏洞利用程序、Shellcode,等等。

  • 受金钱、剽窃知识产权等利益的驱使,不少黑客走上了恶意软件制作之路。

  • 在恶意软件产业中,间谍和破坏类软件的开发背后也有政府机构的身影,其目的大多是维护自身的利益。

  • 反病毒软件在市场营销时会使用各种时髦的术语,这种营销方式很容易误导大众,使他们产生一种百分之百安全的错觉。

  • 反病毒软件是一个以反病毒内核作核心,辅以插件、系统服务、文件监控驱动以及反病毒内核模块等功能的综合系统。

  • 反病毒软件需要能够快速流畅地运行。使用类似C/C++等本机语言编写反病毒软件是最好的选择,因为它们运行时不需要解释器(类似虚拟机解释器),而是直接在本机编译运行。不过,反病毒软件的一些模块可以由托管式或解释型语言编写。

  • 反病毒软件的基础功能包括:反病毒内核、扫描引擎、特征库、解包程序、模拟器,以及针对各类格式文件的解包分析程序。另外,反病毒产品可能还会提供一些高级功能,比如流量监控功能、浏览器安全插件、自我保护和反漏洞利用程序功能。

在下一章,我们将开始讨论如何逆向反病毒软件的内核,研究自动化安全测试和模糊测试的方式。模糊测试是查找反病毒软件中安全缺陷的一种手段。

目录