该病毒是一个可以结束大多数杀毒软件的恶意程序,病毒通过微软一个漏洞来加载驱动程序,该漏洞是内核的函数发生栈溢出导致,使得R3程序可以在0环执行任意代码,驱动加载后结束反病毒软件,并通过向Atapi发送IRP感染userinit.exe实现自启动,下载并执行其它恶意程序。
病毒主体执行后会在系统目录Program FilesMSDN目录下生成文件000000000,qwegier.exe,LHL13.sys,PciDisk.sys,在C盘根目录下生成sysLoad文件,解密自身带的一部分数据并拷贝到申请的一块内存中,然后在这里生成一个新的线程,停止PciDevice的服务,加载PciDisk.sys驱动,并打开PciDisk创建的符号链接.PciFtDisk,并通过DeviceIoControl发送两个Io控制码0x2200180和0x22001C。
WINDOWS系统的内核函数RtlQueryRegistryValues存在栈溢出漏洞,病毒利用自己构造的一串数据写入注册表SYSTEM\CurrentControlSet\Control\TimeZoneInformation的ActiveTimeBias键值下,当设置系统时间时,内核会调用RtlQueryRegistryValues去读这个值,导致发生栈溢出,若读取的数据放在栈里面,会覆盖调用RtlQueryRegistryValues的函数的返回地址,触发漏洞。正常情况下,ActiveTimeBias是一个DWORD类型的键值,病毒执行时,会改成REG_BINARY类型,并写入自己构造的数据。
经验证,WinXP,VISTA以及Win7上都存在该漏洞。
病毒运行时,动态解密一块数据,拷贝到申请的内存中,然后在这里创建线程,文件threaddata为DUMP出来的代码,线程入口位于A61DD0,主要任务是完成SHELLCODE调用的内核函数的动态定位,修改注册表,准备漏洞发的必要条件,启动CMD进程,把SHELLCODE拷贝到CMD进程空间中去触发漏洞,主要流程是:
+0:00000000
+4:00000000
+8:00000000
+C:在CMD进程中申请的地址,也就是SHELLCODE所在的地址(XP系统)
+10:在CMD进程中申请的地址,也就是SHELLCODE所在的地址(VISTA,Win7系统)
到这里,触发漏洞的条件已经具备了,把挂起的CMD主线程恢复运行,然后等待CMD进程结束后删除ActiveTimeBias键值。
CMD进程运行之后,会设置时间,漏洞触发,其函数调用关系如下图:
漏洞在CMD进程空间中被触发, ShellCode也在CMD进程空间得到执行,文件Shellcode中是DUMP出来的代码,入口点是150000,主要工作是解析PE文件,把驱动加载到内核地址空间中,流程如下 :
在XP系统上,漏洞触发时,内核中函数调用的流程是:
NtSetSystemTime -> ExpSetSystemTime -> ExpRefreshTimeZoneInformation -> RtlSetActiveTimeBias -> RtlQueryRegistryValues -> RtlpCallQueryRegistryRoutine -> RtlpQueryRegistryDirect
在RtlSetActiveTimeBias中会调用RtlQueryRegistryValues去读注册表键值ActiveTimeBias,RtlSetActiveTimeBias函数的栈分布情况及调用RtlQueryRegistryValues的代码如下:
其中Context位于[ebp-8],其地址被放在一个结构中传给RtlQueryRegistryValues,这个地址经过RtlpCallQueryRegistryRoutine最终被传给RtlpQueryRegistryDirect,RtlpQueryRegistryDirect函数是真正把栈中RtlSetActiveTimeBias的返回地址给覆盖的函数。
进入RtlSetActiveTimeBias时的栈分布如下:
最终有漏洞的函数把从注册表中读出的0x14个字节写入从Context开始的位置,XP系统上偏移+0C的位置正好覆盖到RtlSetActiveTimeBias的返回地址(Vista系统上Context在[ebp-0c]的位置,所以写到注册表中的Shellcode的地址为偏移+10)。
返回地址被覆盖时的栈如图:
此时RtlSetActiveTimeBias的返回地址已经被覆盖,值为在CMD进程中的SHELLCODE的地址150000。
先列出调用关系:
NtSetSystemTime -> ExpSetSystemTime -> ExpRefreshTimeZoneInformation -> RtlSetActiveTimeBias -> RtlQueryRegistryValues -> RtlpCallQueryRegistryRoutine -> RtlpQueryRegistryDirect
RtlSetActiveTimeBias返回时,就回到病毒的SHELLCODE中,此时的ESP指向上图中最上边的那个位置,EBP = 0,RtlSetActiveTimeBias的返回地址由于已经被覆盖,所以只能通过ESP得到RtlSetActiveTimeBias的上层函数ExpRefreshTimeZoneInformation的返回地址,这个地址在函数ExpSetSystemTime中,取出这个地址,它的前四字节就是调用的相对偏移量,加上本身的地址,又得到函数ExpRefreshTimeZoneInformation的地址,在从这个地址搜索得到RtlSetActiveTimeBias原来的返回时的地址,设置返回值EAX为成功,然后转到这里去执行,如图:
第8行中的add ebp, 0FCh,FC是ExpRefreshTimeZoneInformation局部变量的大小加上在栈中保存的三个寄存器所占的空间,现在EBP指向的是ExpRefreshTimeZoneInformation函数的栈帧。
取出[ebp+4]是ExpRefreshTimeZoneInformation的返回地址,在函数ExpSetSystemTime中,函数find_return_addr如下图:
从ExpSetSystemTime函数中调用ExpRefreshTimeZoneInformation函数的地方,加上相对调用的偏移,也就是图中add
ecx,
[eax-4],取得函数ExpRefreshTimeZoneInformation的地址,然后在里面暴搜RtlSetActiveTimeBias正常情况下的返回地址。
然后由上页图中的push eax; ret转过去,此时这次的调用返回正常的执行流程。
PciDisk驱动主要通过向atapi.sys驱动程序发送IRP来感染userinit.exe文件。
驱动入口处创建一个设备DevicePciFtDisk和一个符号链接DosDevicesPciFtDisk。
从磁盘打开atapi.sys文件,并从INIT节搜索到IRP_MJ_DEVICE_CONTROL和IRP_MJ_SCSI处理例程的地址。
从系统目录打开文件userinit.exe并读入数据,由FileHandle得到FileObject,进一步通过FileObject与与之关联的Vpb得到文件系统所创建的卷设备对象,就是userinit.exe文件所在的卷设备对象,然后构造一个主功能号为IRP_MJ_FILE_SYSTEM_CONTROL的IRP,IoControlCode为FSCTL_GET_RETRIEVAL_POINTERS,发往文件系统的卷设备对象,如下图:
等IRP完成后,得到文件userinit.exe的VCN和LCN对应关系表。
然后取得atapi驱动类型为FILE_DISK类型的设备,得到DR0设备对象。
当驱动收到应用层发过来的DeviceIoControl请求时,会把传入的数据通过写入磁盘,完成对文件的Hook操作,这里主要是自己构造SRB请求包,向Atapi发送IRP_MJ_SCSI类型的IRP实现的。
如图:
别处,代码中还有对atapi.sys分发例程的挂钩恢复操作以及反调试代码,若发现在存在ntice.sys和syser.sys驱动,会向当前线程ETHREAD写入一块垃圾数据。
该驱动主要实现SSDT的恢复,杀掉大部分的安全软件。
驱动入口取得内核模块的基址和大小,并暴搜找到函数PspTerminateThreadByPointer的地址。
若搜不到,则从寻出表找到PsTerminateSystemThread函数的地址,并从该地址向后搜索取到PspTerminateThreadByPointer的地址,然后恢复该函数的前8个字节,然后通过ZwQuerySystemInformation遍历系统中的进程表,并杀掉病毒中定义的进程,包括:
这里杀进程的主要流程是:通过枚举得到的进程ID,得到进程对象EPROCESS,对进程对象中的链表头ThreadListHead遍历找到的每一个线程调用PspTerminateThreadByPointer。
然后分两种情况对SSDT进行恢复:
若系统中不存在江民软件,取出系统中SSDT表的位置,换算并取到在磁盘文件中的偏移,从磁盘文件中读取原始的SSDT数据后进行重定位并恢复。
若系统中存在江民软件,先读取原始SSDT数据,同上步,然后申请两块内存,先把当前正在使用的SSDT表拷贝过去,把原始SSDT也拷贝到紧后面,参数个数表同理,然后给SSDT结构赋值指向新的函数地址表和个数表,并把函数个数乘以2放入Count。
这样构造的SSDT,原来的函数地址(Hook的或是没Hook的)没有改变,而后半部分新加入的都是被恢复的函数地址。
然后病毒通过wrmsr改变MSR的IA32_SYSENTER_EIP,指向自己的代码,在这段代码中,把系统服务调用号加中原来的SSDT函数数量放入EAX后就调用原来的系统服务入口。这样,系统服务函数的地址就被重定向到了SSDT的后半部分。
最后,病毒开一个系统线程,循环调用杀进程的函数来结束杀软。
本文由安全客原创发布
转载自安全客
打赏我,让我更有动力~
© 2016 - 2024 掌控者 All Rights Reserved.