本帖最后由 zhoudaniel 于 2011-10-15 21:48 编辑
序言: 当写到关于ZeroAccessrootkit的文章时, 这让我们想起当这个rootkit在互联网被发现的时间必须得追溯到2009年。那个时候,MBR rootkit 和TDL2 rootkit肆虐横行, 其中第二个主要的版本是当时互联网中最先进的内核级rootkit——直到安全研究人员偶然发现一种新的未知的rootkit,它能够很快地杀死大多数设法扫描系统中特定的文件夹的安全软件。ZeroAccess创建一个新的内核设备对象称为__max+>,这就是这个rootkit迅速在安全领域中被熟知,并被称为MAX ++ rootkit的原因,当然还因为在ZeroAccess内核驱动程序代码中发现了一个字符串,指向名为ZeroAccess的原始项目文件夹 (f:\VC5\release\ZeroAccess.pdb)。 这个rootkit把它的代码存在两个备用数据流win32k.sys:1 和win32k.sys:2中。为了避免被检测到,这个rootkit能够杀死每一个试图扫描备用数据流的安全软件。它在系统文件夹中创建一些假的交接点(注:NTFS交接点,是NTFS文件系统的特性,允许一个文件夹被链接到另一个本地的文件夹,这样目标文件夹就有了一个别名)指向之前写的假的rootkit设备。当安全软件试图扫描那些存储备用数据流的特定文件夹时,这个rootkit的自我保护机制在安全进程中安排一个工作队列立刻杀死安全软件。至此,扫描系统而不被rootkit杀死成为一项艰巨的任务。 从那时起,ZeroAccess rootkit就开始不断进化,不断改变它感染系统的方式,变得更为先进和更为危险。在本文中,我们要分析这一威胁,以及它如何演变到目前的版本。
木马释放着分析 这个rootkit通过木马释放者安装,木马释放者通过破解,warez网站以及漏洞利用传播。这些都是常见的感染载体。木马释放者实现了一系列经典的反调试技术,能够有效地减慢代码分析的进度。解压后的第一个阶段,程序试图获取以下特权:SeDebugPrivilege,SeTakeOwnershipPrivilege, SeRestorePrivilege, SeSystemtimePrivilege,SeSecurityPrivilege。然后他才开始加载感染. 在分析更详细的感染流程之前,有必要简要介绍ZeroAccess是如何感染系统的。木马释放者在systemroot \ System32\ Drivers文件夹中随机选择一个驱动程序,覆盖原来的代码– 目的是保存它作为备份。然后,加载后,rootkit的驱动程序设置一个新的磁盘设备对象,这将作为rootkit本身创建的用于存储文件和数据驱动器的隐藏卷。 这是一种有效的技术,类似于TDL3的rootkit感染。ZeroAccess在系统的文件系统设置了一种新的加密隐藏卷方法,TDL3在系统的文件系统外,硬盘驱动的最后分区创建一个全新的加密文件系统的方法。在这些新的加密卷内存储他们的文件,使它们完全让操作系统无法访问。这两个rootkit的感染随机的驱动程序,但同时ZeroAccess完全覆盖驱动的内容,TDL3 rootkit劫持驱动程序的入口点,在驱动程序的资源部分覆写小于1KB的字节。其他方面的差异是在于磁盘的I / O过滤引擎的不同,ZeroAccess不如TDL3 rootkit强大。 让我们深入分析在ZeroAccess rootkit如何感染驱动的日常工作以及它如何选择正确的驱动程序感染。 ü 这个rootkit计算一个特定的值用来检查驱动的映像大小。我们在分析样本的时候发现该值是0x7410(29712字 节),这是rootkit的内核驱动程序的大小。显然,目标驱动程序应该比那个更大; ü 这个rootkit开始通过SystemModuleInformation类调用ZwQuerySystemInformation函数枚举所有的系统驱动程 序; ü 目标驱动程序必须位于classpnp.sys驱动和WIN32K.SYS驱动之间,所有其他驱动程序将被丢弃; ü 所有位于classpnp.sys和WIN32K.SYS之间的驱动有一个比0x7410小映像大小都被丢弃; ü 随后分析的所有的驱动比这个值大。检查以下参数: 1. 驱动程序文件的名称必须以“SYS”扩展名结尾。 2.启动驱动程序的注册表项的值必须大于零(驱动程序不应该在系统启动时启动); 3.驱动的PE导出表的大小必须是零(驱动程序不应该导出任何东西) ü 如果满足上面的条件,驱动程序被标记为“潜在的感染对象”,并设定SYSTEM_MODULE> ID结构的值为1; ü 分析循环会一直进行,直到所有的驱动都被进行了分析和标记; 第一个循环利用rootkit在系统中找出所有潜在的目标驱动。然后,循环结束, 开始第二个循环,直到哪一个被选中被感染。 ü 这个rootkit通过调用Win32 API函数GetTickCount和RtlRandom的计算一个随机数; ü 通过一次运算(RandomValue % NumberOfPotentialTargetsFound)初始化计数器的值; ü 这个rootkit又开始一个循环来分析所有的系统驱动程序,每次减少一个潜在的目标驱动程 (SYSTEM_MODULE-> ID =1); 当计数器等于零,这个rootkit已经找到的目标驱动程序就会被感染。rootkit将会创建一个新的分区,称为\.<将被感染的驱动程序名字>(如\.NdProxy),它暂时储存一个干净的驱动副本。然后rootkit在HKLM\SYSTEM\CurrentControlSet\Services\创建一个新的注册表服务项值。<将被感染的驱动程序名字>(例如.NdProxy)。在这个注册表项里,ImagePath的值设为\ *。这是一个模糊的欺骗处理,避免在rootkit在加载过程中遭到安全软件的干扰,而通过传递值\ *来欺骗安全软件,因为它显然不指向任何实际的文件。然而事实上Rootkit通过调用ZwCreateSymbolicLinkObject 函数设置了一个的新的符号链接,指向\ *真实的文件。 木马释放者通过完全覆写了自内核驱动程序的代码来感染目标驱动程序,然后通过调用ZwLoadDriver加载它。覆盖驱动之前,木马释放者会确保通过暂停所有与sfc_os.dll模块有关的线程来中断System File Checker (SFC)线程。这些线程在感染完成后会被恢复。 在执行真正的有效感染之前,木马释放者检查是否在WOW64模拟环境中运行。如果是,这个进程立即终止。目前,该rootkit不会感染基于x64的Windows操作系统。此外,木马释放者通过调用ZwOpenFile尝试打开该rootkit设备检查该rootkit是否已经在系统内运行。如果系统已经被感染,该rootkit设备将返回一个NTSTATUS错误:STATUS_VALIDATE_CONTINUE。 该rootkit的驱动程序加载后,该rootkit设备\\?\ ACPI#PNP0303#2&da1a3ff&0(该样本是这样显示的,当然它可能因版本不同而不同)可以通过用户模式被访问,木马释放者可以使用NTFS文件系统格式化新卷。为了做到这一点,它加载fmifs.dll模块 - 可安装文件系统模块的格式化管理器,导入FormatEx这个API。
现在新的隐藏卷准备存储原来被覆盖的驱动程序的干净副本。木马释放者不使用真实的文件名,但它会根据以下步骤生成一个随机文件名: ü rootkit通过KeyBasicInformation参数调用ZwQueryKey来查询以下注册表项:HKLM \ SYSTEM \ CurrentControlSet\Control\ AGP; ü rootkit之后会查询_KEY_BASIC_INFORMATION> LastWriteTime参数; ü 它会生成两个特定的种子(seed)值:先是将LastWriteTime参数中的LowPart和HighPart异或(LastWriteTime.LowPart HighPart^LastWriteTime.HighPart);然后将之前生成的种子(seed)的值加上原始的LowPart值,接着再增加1; ü 将得到的随机字符用作一个起始字符串并组成新的文件名。该字符串是:eaoimnqazwsxedcrfvtgbyhnujmikolp; ü 需要组成的文件名是8个字符长,所以开始围绕以下步骤进行循环: 种子(seed)值是从0x0D与到0x1F(起始字符串的长度),返回值是字符串中字符的索引,在新的文件名将被用到; 种子(seed)值通过用一个64位的右移函数右移5位,此函数由NTDLL.DLL导出(_allshr());
循环继续,直到形成一个八个字符的字符串 .然后该文件被存储在以下路径: \??\ACPI#PNP0303#2&da1a3ff&0\L\Snifer67,Snifer67被刚刚生成的名称取代。
文件名生成过程的汇编代码
C代码大致可以翻译成:
ASM代码翻译成C代码
当文件名被生成时,新的文件在rootkit设备里被创建并且存储一份干净的驱动副本。
内核模式rootkit感染 在本段中,我们将对ZeroAccess rootkit释放的内核驱动进行更加深入的分析揭示它的工作原理. 正如之前段落中所说,rootkit设置一个新的设备对象命名ACPI#PNP0303#2 da1a3ff0,这就是访问该rootkit隐藏设备的窍门。然后它通过劫持Disk.sys与底层的端口设备的连接来拦截Windows的磁盘I / O。如果试图读取或写入受感染的驱动程序的操作被拦截,该rootkit将会返回原始的未受感染的驱动副本。 当驱动程序启动时,rootkit通过检查注册表启动项来确认它是否是第一次在系统上运行。如果它有DRIVERNAME(例如.NdProxy)在服务注册表项,那么它是第一次运行并且rootkit接着将会删除那个键值 — 它已不再被需要。 然后rootkit读取被感染的驱动的路径接着通过调用RtlHashUnicodeString函数计算驱动的路径和文件名的哈希值。这个哈希值将被rootkit用来检查是否有人在磁盘上试图访问的被感染的驱动。之后被感染的驱动程序将被存储在内存中,并且被指向一个特定的MDL。 现在rootkit准备好自己的代码,然后调用IoCreateDriver这个原生的API,并设置自己的驱动程序对象,将它从DriverSection中隐藏并且将其所有的派遣函数指向一个特定的rootkit派遣例程,。为了隐藏新生成的驱动程序对象,rootkit生成一个干净的Disk.sys驱动对象的副本,以欺骗安全软件。
伪造的的和最初的磁盘驱动器对象 在上图中,我们可以看到伪造的和最初的Disk.sys的驱动程序对象。第一个是假的,是通过rootkit复制而成的,下一个是最初的Disk.sys备份。它们是相同的,除派遣函数和设备对象,rootkit的驱动程序对象指向它自己的对象。 rootkit驱动对象创建了两个不同的设备对象,第一个是用于拦截Disk.sys的I / O,而第二个是一个我们在上面段落的开始时候谈到过。 为了拦截Disk.sys中的I /O程序,rootkit通过交换其设备扩展结构劫持\驱动\磁盘的DR0设备对象。设备DR0_Device_Object-> DevExtension - > LowerDeviceObject指针被修改指向该rootkit设备。然后rootkit在Disk.sys处理之后拦截IRP,之前如果需要的话,它可以访问端口设备驱动程序(eg. atapi.sys)并且分析和过滤它。 该rootkit分析是否将IRP发往伪造的设备ACPI#PNP0303#2&da1a3ff&0,如果发送,它就调用其自己的派遣程序来处理请求。作为一个伪造的隐藏的卷,它可以处理所有的IOCTL请求。比如 IOCTL_DISK_CHECK_VERIFY, IOCTL_DISK_GET_DRIVE_GEOMETRY, IOCTL_DISK_IS_WRITABLE, IOCTL_STORAGE_CHECK_VERIFY, IOCTL_STORAGE_GET_DEVICE_NUMBER,IOCTL_DISK_GET_DRIVE_LAYOUT_EX, IOCTL_DISK_GET_PARTITION_INFO_EX. 隐藏卷被加密,以及rootkit的读/写程序能够在联机情况下对数据进行编码和解码。伪造的卷被存储在systemroot \ SYSTEM32 \ CONFIG \<随机的文件名>,随机文件名是通过相同的木马感染者生成,被用来存储被感染的驱动程序的副本。这个文件在硬盘驱动上总是被加密的。该rootkit的加密算法是RC4和一个128位的密钥,如下所示:
rootkit文件系统解密
如果IRP不是针对rootkit的设备,那么派遣例程就对请求的数据包进行分析,寻找磁盘上被感染的驱动文件的I/O请求。rootkit的过滤器IRP_MJ_INTERNAL_DEVICE_CONTROL的主要功能是寻找SCSI请求块结构。如果SRB指向的是SRB_FUNCTION_EXECUTE_SCSI,过滤例程就被触发。rootkit还检查是否是一个FileObject结构作为传入的IRP请求,如果是这样,计算FileObject指向的文件名的文件路径的哈希值。哈希值的计算方法是调用RtlHashUnicodeString函数,其结果是在rootkit启动时用rootkit驱动程序计算受感染的驱动程序的路径哈希值来检查。如果两个哈希值匹配,则是该rootkit伪造的IRP请求。 如果SCSI_REQUEST_BLOCK数据包操作是SCSIOP_READ,读请求被转发的底层端口设备,返回的是用rootkit伪造的CompletionRoutine;如果操作是SCSIOP_WRITE,缓冲区是被之前指向特定的MDL的被rootkit感染的驱动副本所覆盖。
该rootkit的一个工作队列能够与C&C的列表服务器通信。它工作在TDI网络层,能够绕过防火墙和安全软件,使得它们无法在这个网络层面监视网络活动。该rootkit的发送加密的请求给列表中的所有服务器,数据包始终被发送到远程的TCP端口13620。该rootkit允许攻击者在系统中通过下载和存储相关文件到隐藏的rootkit卷,释放木马以执行进一步的感染,然而这些行为对于安全软件是不可见的。这些文件是以内核模式驱动程序形式所释放的。这是因为rootkit主驱动程序可以通过直接调用IoCreateDriver()这个原生API从内核中加载。这些驱动程序在大部分的安全软件中是不可见的,导致安全软件无法实现先进的反rootkit的特性。 我们可以通过寻找可疑的系统关机通知例程所指向的一块未知的内存区域来找出该rootkit。 该rootkit通过调用IoRegisterShutdownNotification来创建它自己的系统关闭通知例程。
结论 ZeroAccess肯定是最新进的内核模式rootkit之一。虽然它不如TDL中的rootkit家族那么强大,但它实现了一些独特的功能,变得相当危险而且可以成为其他木马感染的一种潜在载体。创建和处理隐藏卷的方式允许ZeroAccess和其他种类的木马感染一起被分配,将它存储到rootkit的加密文件系统,并且在系统中享有所有的权限。 正如纸上所写,ZeroAccess在许多方面非常类似于TDL3:它们都是使用相同的方法在系统的文件系统外存储它们的代码,都是用RC4加密,被感染的驱动都是随机选择的,过滤SCSI_REQUEST_BLOCK数据包都是比disk.sys更为底层(尽管TDL3劫持最底层的微小端口驱动,而ZeroAccess通过劫持disk.sys的DR0设备来点击它,重定位过滤设备装置)。ZeroAccess执行的磁盘过滤引擎没有TDL3执行的过滤引擎那么先进,这就是为什么ZeroAccess比TDL3更为容易被检测和删除到。可悲的是,这只是一个小问题,它能够很容易地被ZeroAccess的作者改进,此外如果它还将与其他类型感染木马相结合,它将比以往任何时候都要完整而强大。 如果ZeroAccess将以和TDL3一样快的发展进度而发展,我们将可能看到在世界各地数目更为显著的电脑将受到感染。
原文链接:http://www.prevxresearch.com/zeroaccess_analysis.pdf
原文又有新的更新了
|