Stuxnet蠕虫驱动分析


这里只是分析文字, 贴图影响速度, 就不贴了, 具体看附件pdf文档, 难免有错误之处, 欢迎指正!

一. Stuxnet蠕虫(超级工厂病毒)简单说明

能够利用对windows系统和西门子SIMATIC WinCC系统的7个漏洞进行攻击,被称为是新时代网络战争开始的标志,
也有人宣称是"政府发动的网路战争、带有圣经讯息、最高机密等",呵呵,有点雷人!

windows下最主要的传播途径是攻击快捷方式自动执行漏洞(MS10-046), WindowsServer服务的远程溢出漏洞
(MS08-067)以及打印后台程序服务中的远程代码执行漏洞(MS10-061)。

病毒成功攻击了伊朗核电站,造成伊朗核电站推迟发电.由于能够对西门子公司的SIMATIC WinCC监控与数据采集 
(SCADA) 系统进行攻击,因此也能攻击我国的钢铁、电力、能源、化工等重要行业,

Stuxnet超级工厂病毒直到2010-09-25,才在传入国内网络.我是在近两个月前才收到的,当时只需要简单分析用户态的部分样本,因此没有对驱动进行分析.后来闲着没事时,就分析了驱动部分.不过,此病毒强大之处大部分都在用户态实现.


二.Stuxnet蠕虫(超级工厂病毒)驱动(mrxnet.sys)分析

从Stuxnet蠕虫病毒样本中提取出了两个驱动文件,mrxnet.sys(17k),mrxcls.sys(26k),其中驱动mrxnet.sys在蠕
虫通过u盘驱动器传播时被用来隐藏特定文件,这个驱动是一个文件系统过滤驱动,支持三种文件系统ntfs,
fastfat和cdfs文件系统.驱动文件mrxcls.sys则被用于向用户空间中注入代码,被注入的模块被放在一个配
置文件中,这应该就是最初让卡巴斯基头痛的"父进程注入"技术,轻松地绕过卡巴.这里单就只分析驱动mrxnet.sys.

入口处开始分析:

1.此驱动首先创建一个设备类型为FILE_DEVICE_DISK_FILE_SYSTEM,设备特征为FILE_DEVICE_SECURE_OPEN,
设备扩展为8字节的无名设备对象.这个驱动没有控制设备,因此不会跟用户态交换信息.

其中设备扩展的类似如下定义:
DeviceExtension
{
PDEVICE_OBJECT LowerDevice;
PDEVICE_OBJECT RealDevice;
}
其中LowerDevice为本驱动的下层驱动,RealDevice为VPB中的RealDevice设备,其实也就是文件系统的卷设备.

2.接下来注册MajorFunction:

IRP_MJ_FILE_SYSTEM_CONTROL
IRP_MJ_DIRECTORY_CONTROL

这两个派遣例程,这个驱动主要就处理这两例程,其他的用一个例程处理,其实是直接pass了,不做任何处理.
两个例程分别是FileSystemControl,DirControl.是本驱动核心功能的实现,留到最后阐述.

3.接着就是填充FastIoRoutines,驱动并没填充所有的FastIoRoutines,这里填充了如下:
FastIoCheckIfPossible;
FastIoRead;
FastIoWrite;
FastIoQueryBasicInfo;
FastIoQueryStandardInfo;
FastIoLock;
FastIoUnlockSingle;
FastIoUnlockAll;
FastIoUnlockAllByKey;
FastIoDeviceControl;
FastIoDetachDevice;
FastIoQueryNetworkOpenInfo;
MdlRead;
MdlReadComplete;
PrepareMdlWrite;
MdlWriteComplete;
FastIoReadCompressed;
FastIoWriteCompressed;
MdlReadCompleteCompressed;
MdlWriteCompleteCompressed;
FastIoQueryOpen;
这些FastIoRoutines没有做什么实质性的工作,只是把简单判断一下,然后调用下层驱动.

4.然后就是attach到文件系统了,函数:AttatchTargetDrivers.
先获取通过MmGetSystemRoutineAddress动态获取ObReferenceObjectByName函数的地址,将其地址作为参数去
获取文件的驱动对象,文件系统名为:
\\FileSystem\\ntfs
\\FileSystem\\fastfat
\\FileSystem\\cdfs
支持的文件系统有ntfs,fastfat,cdfs.
这三个文件系统名的地址被放在一个指针数组中,这个指针数组以后会被通过ObReferenceObjectByName获取的
驱动对象覆盖;

这里有个循环,循环3次,分别去attach这三种文件系统.
这个attach的函数是GetTargetDriverAndAttach(),函数有两个参数,第一个参数是函数ObReferenceObjectBy
Name的地址,第二个参数是文件系统文件名指针,这个参数即用来传入文件系统名地址,也用于获取所得的驱动
对象指针.进入这个函数内部,函数先获取文件系统驱动对象,然后遍历驱动对象的每个设备对象进行attach,
attach 每个设备对象的函数是TryToAttachDevice()

TryToAttachDevice()
这个函数有两个参数,第一个是设备对象(既是文件系统的设备对象),第二个是BOOLEAN型(这里调用时传入的为
true),用于判定这个文件系统是被注册(激活),还是卸下.如是被注册,则调用函数CreateFilterDeviceAndAtta
ch()否则Detach本驱动在文件系统设备栈中的设备.

CreateFilterDeviceAndAttach()这个设备有一个参数,参数为文件系统的设备.
这个函数只attach 设备类型为磁盘文件类设备,CD_ROM文件类设备,网络文件类设备.
FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_CD_ROM_FILE_SYSTEM
FILE_DEVICE_NETWORK_FILE_SYSTEM
先判断设备类型满足以上条件,如果这个文件系统设备还没有被attach,则创建一个本驱动的设备attach到文
件系统设备栈中,Attach是通过函数
AttachToFsDevie来实现的,这个函数很简单,只是把attach设备后,把下层设备保存于设备扩展中.

这样就完成了attach工作.


5.调用函数IoRegisterFsRegistrationChange注册文件系统变动回调例程.这个例程也就是4讲到的
TryToAttachDevice()函数,用于完成对动态激活的文件系统进行attach.



IRP_MJ_FILE_SYSTEM_CONTROL和IRP_MJ_DIRECTORY_CONTROL的派遣例程处理,这两个例程都只处理
IRP_MN_MOUNT_VOLUME类型的次功能码,主要是为了能在新的文件系统被激活时,做相应的处理.其他的
直接pass,不做处理.

1.FileSystemControlRoutine例程
首先获取MinorFunction,判断是否是IRP_MN_MOUNT_VOLUME,是则调用MnMountVolumeForFSC,否则pass;

2.MnMountVolumeForFSC()
函数先创建了一个设备对象,然后初始化设备扩展,在设备扩展的第二成员里保存VPB中realDevice.然后是
自己实现了将当前设备的Stack Location拷贝到下层设备的Stack Location处,并且设置好完成例程,
Context和控制域.完成例程名为
CompleteRoutineForFSC.

3.完成例程CompleteRoutineForFSC.
完成例程的context参数传进来是我们创建的过滤设备对象,通过这个设备对象得到原先保存的vpb->RealDevice,
再根据这个设备得到vpb然后在获得VPB->DeviceObject,这个设备则是文件系统的卷设备,为什么要这么做,
因为在mount之前我们创建的设备的VPB可能在mount完成后就不同了,而完成后的VPB才是有效的.故这里
先将文件系统的卷设备保存在设备扩展中,后在完成例程里重新获取.得到文件系统的卷设备对象后就可以
进行attach了.attach完成例程函数的主要工作也就算是完成了.

1.DirControlRoutine
其实重头戏在函数DirControlRoutine中,这个函数主要实现文件隐藏功能.
同样也只处理IRP_MN_MOUNT_VOLUME,判断后直接调用函数MnQueryDirectory.

2.MnQueryDirectory
这个函数先获取查询目录(文件)名,
如果文件名存在并且文件名长度76,且文件名前19个字符全是'{'的话,就放过(这里有点不解,为什么要设置这个例外呢.
),否则复制当前栈道下层栈,并设置完成例程IoCompleteRoutineForQueryDir,将irp直接下发,这里栈的COPY和完
成例程的设置前面一样,是自己实现的.

3完成例程IoCompleteRoutineForQueryDir
这个函数比较大,主要是做文件过滤隐藏的.
先判断IRP->IoStatus.Status是否成功,如果不成功则释放相关资源并退出,然后就是获取一些文件相关的
偏移,从函数GetFileInforOffset中获取EndOfFile Offset,FileName Offset,FileNameLength Offset.因为
这里会因为文件信息类FileInformationClass的不同而会有不同的偏移.

得到偏移后就可以这里涉及的文件信息类有
FileBothDirectoryInformation
FileDirectoryInformation
FileFullDirectoryInformation
FileIdBothDirectoryInformation
FileIdFullDirectoryInformation
FileNamesInformation

接着就是得到查询信息的缓冲,然后调用HideFile来隐藏文件.

4.隐藏文件函数HideFile
此函数中,从前面获取的几个偏移从缓冲中定位文件名地址,文件长度,文件结束位置.
然后就是调用两个函数文件名过滤函数(CheckPostfix,CheckNameInvlidForTMP)来筛选病毒关心的文件.
在函数CheckPostfix中判断文件名是否是一".LNK"后缀的文件名,如是则符合隐藏规则,在函数CheckNameInvlid中,
如果文件大小在0x1000~ 0x800000,文件名长度为12,文件后缀名为".TMP",文件名第一个字符为"~",
并且文件名从第5个字节到第8个字节为数字,并且这些数字之和必须等于10,便符合规则.
符合以上两种规则的文件实施隐藏,隐藏处理是,如果条件符合,这把后面文件记录向前移动一个文件记录,
也就是覆盖病毒关心的文件记录.

上传的附件 Stuxnet蠕虫驱动分析.pdf