直接内核对象操作(DirectKernel Object Manipulation, DKOM),通过直接内核对象操作可以在不安装钩子的情况下隐藏进程和驱动程序。
在更改内核对象之前需要明确以下问题:
1. 需要明确所要修改的对象是怎样的,包括结构的成员是什么
2. 需要深入理解如何使用对象
3. 要考虑不同操作系统的版本以及同一版本不同服务补丁之间的差异
4. 注意如何使用对象,因为特定内存区域和特定函数在不同的中断请求级别(Interrupt Request level, IRQL)上是不可用的。
5. DKOM的另外一个限制是它无法实现rootkit的所有目标,只能对内存中用于记账的内核对象进行操作。操作系统保存了系统上全部运行进程的列表,可以通过操作这些对象来隐藏进程。在内存中没有对象能够表示文件系统上的所有文件,这种情况无法使用DKOM来隐藏文件。这种情况需要使用钩子或分成文件过滤驱动程序来隐藏文件。
6. DKOM能够完成隐藏进程,隐藏设备驱动程序,隐藏端口,提升线程的权限级别,干扰取证分析技术
准备工作:
1. 确定操作系统的版本
使用Win32 API可用于接收操作系统的信息,该信息的结构为OSVERSIONINFO 或OSVERSIONINFOEX,包含关于操作系统的主要和次要版本信息。利用API函数GetVersionEx 可以得到这个结构。
示例代码如下:
OSVERSIONINFOEX osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if(GetVersionEx((OSVERSIONINFO *) &osvi)) { CString strtemp; strtemp.Format("MajorVersion:%d, MinorVersion:%d, BuildNumber:%d, PlatformId:%d", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, osvi.dwPlatformId); MessageBox(strtemp); } |
内核也提供了一个可以访问版本信息的API,PsGetVersion(),Windows XP和Windows 2003 支持API函数RtlGetVersion(). 也可以通过注册表来查询操作系统的版本
键值如下所示:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion] "SubVersionNumber"="" "CurrentBuild"="1.511.1 () (Obsolete data - do not use)" "InstallDate"=dword:4eaab173 "ProductName"="Microsoft Windows XP" "RegDone"="" "RegisteredOrganization"="WwW.YlmF.CoM" "RegisteredOwner"="YlmF" "SoftwareType"="SYSTEM" "CurrentVersion"="5.1" "CurrentBuildNumber"="2600" "BuildLab"="2600.xpsp_sp3_gdr.101209-1647" "CurrentType"="Uniprocessor Free" "CSDVersion"="Service Pack 3" "SystemRoot"="C:\\WINDOWS" "SourcePath"="G:\\I386" "PathName"="C:\\WINDOWS" "ProductId"="76481-640-8834005-23475" |
接下来要完成用户空间与设备驱动程序的通信,主要通过使用I/O控制码(I/O Control Code, IOCTL)完成,这些控制码包含在代码为IRP_MJ_DEVICE_CONTROL或IRP_MJ_INTERNAL_DEVICE_CONTROL的I/O请求报文(I/Orequest packet, IRP)中。它们使用称为METHOD_BUFFERED 的I/O 传递方法,I/O管理器通过这种方法将数据从用户堆栈复制到内核堆栈中。
来看DKOM是如何实现隐藏进程的:
Windows NT 操作系统具有描述进程和线程的可执行对象,Taskmgr.exe和其他报告工具引用这些对象,列出运行的所有进程,内核例程ZwQuerySystemInformation也使用这些对象列出运行的进程,通过理解并修改这些对象,可以隐藏进程,提升进程权限等级以及执行其他改动。
可以通过遍历在每个进程的EPROCESS结构中引用得一个双向链表,来获得Windows操作系统的活动进程列表,进程的EPROCESS结构包含了一个具有指针成员FLINK和BLINK的LIST)ENTRY结构,这两个指针分别指向当前进程描述符的前方和后方进程。
首先要在内存中找到EPROCESS结构,通过PsGetCurrentProcess函数始终能够找到当前运行进程的指针,从而找到它的EPROCESS。通过进程标示符(Process Identifier,PID)寻找进程。PID位于EPROCESS块中的某个偏移量,该偏移量与操作系统的版本有关,确定操作系统版本在这里发挥作用。