当前位置:
文档之家› WindowsRootkit进程隐藏与检测技术
WindowsRootkit进程隐藏与检测技术
EPROCESS 结构中的域 Active process link 域是一个 LIST_ENTRY 结构,它将所有进程的 EPROCESS 结构连接成 了一个双向链表。ZwQuerySystemImformation 函数通过遍历 这个链表来获取需要查询的信息。只要把需要隐藏进程的 EPROCESS 结构从链表中剥离出去,该进程就会从系统的视 线中消失。
无论在用户模式还是内核模式,仅依靠一种技术已经不 足以将进程完美隐藏。高效的进程隐藏方案往往将 2 种模式 下的技术结合在一起,配合内核中多种数据结构,甚至利用 一些非 Rootkit 范畴的技术。例如 hook 内核 Shadow SSDT 结 构以及抹掉窗口标题等辅助隐藏手段,防止通过枚举窗口探 测进程。归根结底,进程隐藏就是要让进程隐匿在系统之中, 并在最大程度上给检测制造技术障碍。
由于线程的上下文切换都要用到 SwapContext 函数,因 此只要把守住该函数就能得到真实的进程列表,找出被隐藏 的进程。 3.2 另类检测方法
进程 Csrss.exe 是 Windows 子系统进程[4]。由于每个进程 在创建初期都会通知 Windows 子系统进程以便能够进一步完 成创建工作,因此 Csrss.exe 中包含了除 Idle, System, Smss.exe 和 Csrss.exe 之外所有进程的信息(前 2 个属于内核,SMSS 是 CSRSS 的父进程)。
利 用 PsGetCurrentProcess 函 数 定 位 到 System 进 程 EPROCESS 构成。然后,沿着 LIST_ENTRY 结构指向遍历整 个链表,通过 PID 等信息定位到需要隐藏的进程,将它的 EPROCESS 脱链。脱链之后,该进程的正常运行不会受到本 质的影响。但直接使用系统提供的服务已经不能够发现该进 程了。
函数 ZwQuerySystemInformation 的服务号是 0xAD。隐 藏进程时,Rootkit 在 SSDT 中找到服务号为 0xAD 的服务函 数地址,把它替换为 Rootkit 中可过滤进程信息函数的地址。 2.2.2 直接内核对象操作
基于钩子技术的隐藏技术通常容易被检测到,而直接内 核对象操作(DKOM)技术可以在不依赖钩子的前提下,实现 对进程的隐藏。在 NT 内核的 Windows 操作系统上,每一个 进程在内核中都由内核对象 EPROCESS 结构对其拥有的地 址空间、描述符、线程等信息进行描述[4]。
进程 Csrss.exe 的核心是动态链接库 csrsvr.dll,几乎所有 与初始化进程相关的工作都是在其中执行的。它包含很多不 被公开的未导出符号。其中,CsrRootProcess 是一个指向结 构体 CSR_PROCESS 的指针。CSR_PROCESS 这个结构体中 的 域 ClientId 包 含 了 进 程 PID 信 息 ; 而 域 ListLink 是 LIST_ENTRY 结构。包含不同进程信息的 CSR_PROCESS 结 构通过这个域连接起来形成链表。遍历整个链表,可以得到 一份包含几乎所有进程的列表。获取未导出的符号 CsrRootProcess 的 一 种 可 行 方 法 是 利 用 导 出 函 数 CsrLockProcessByClientId,这个函数在执行中会将其值存入 寄存器 ESI 中。导出函数的入口地址可以直接得到,在此基 础上加上相应的偏移量就能读出 CsrRootProcess 的地址。
Process Hiding and Detection Technique of Windows Rootkit
WANG Lei, LING Xiang
(National Defense Key Lab of Anti-Interference Communication Technology, University of Electronic Science and Technology of China, Chengdu 610054)
2.2 内核模式下的进程隐藏技术 Rootkit 进入内核后运行在权限最高的 Ring0 级上,拥有
同内核同等的地位,并能操作内核代码,为隐藏进程提供了 极大方便。 2.2.1 Hook SSDT
在 NT 系 统 中 , 大 多 数 系 统 服 务 都 是 在 内 核 进 程 Ntoskrnl.exe 中实现的。在 Ntoskrnl 初始化的过程中,会先为 它所提供的各种服务创建系统服务分派表(SSDT)[5]。表中的 第 1 项是系统服务的索引号,第 2 项是与索引号相对应的服 务函数在 Ntoskrnl.exe 进程空间中的地址。进程通过服务号 查找需要使用的系统服务函数。
—140—
条件跳转指令。它克服了 IAT 钩子在动态链接库显式加载时 会失效的缺陷,适应能力更强。
通 常 情 况 ,用 户 态 进 程 使 用 CreateToolhelp32Snapshot 等 API 获取进程列表。Rootkit 针对这些函数设置 API 钩子, 在钩子函数中删除原始 API 返回结果中特定进程的信息实现 进程隐藏。
系统中的每个线程上下文的切换由内核进程中的 SwapContext 函数来实现。该函数执行时,寄存器 EDI 中存 放的是指向即将被换入的线程的指针;而寄存器 ESI 中存放 的是将被换出的当前线程的指针。利用此特点,使用内联钩 子钩住该函数,在钩子函数中验证寄存器 EDI 所指向的即将 被换入的线程的 KTHREAD[1]是否指向一个位于正常双向链 表中的 EPROCESS 结构。如果不是,则说明该进程是一个被 DKOM 隐藏的进程。
受运行权限的限制,用户模式实现进程隐藏主要依赖的 是钩子(hook)技术[2]。Rootkit 通过设置钩子,钩住进程监控 软件所调用的某些函数,并篡改这些函数的返回结果,特定 进程的信息将不被察觉。
按 照 实 现 方 式 钩 子 可 分 为 导 入 地 址 表 (IAT) 钩 子 和 内 联 钩子(Inline Hook)2 类。IAT 钩子通过注入目标进程空间的代 码对内存中目标进程 PE 格式[3]进行分析,找到并替换 IAT 中目标 API 函数的地址为钩子函数的地址。而内联钩子通常 直接把目标函数的前 5 个字节改写为一个转向钩子函数的无
1 概述
Rootkit 是 20 世纪 90 年代出现的一种新兴的计算机技术 技术。它是长期可靠地潜行于计算机上的一组难于检测的程 序或代码[1]。进程隐藏是 Rootkit 技术中典型的一种。它利用 代码及编程手段令特定进程的信息无法为其他进程获取。对 杀毒软件、防火墙等安全软件而言,隐藏关键进程可以排除 恶意软件的干扰,使安全防护效果更佳。同时隐藏进程也可 为计算机取证等工作带来便利。但是隐藏的进程极具危险性, 它意味着代码可以在完全不被察觉的状态下悄然运行。这样, 恶意程序可以在目标主机中长期潜伏,窃取信息而不被发现, 造成极大危害。因此,能够检测出被 Rootkit 隐藏的进程更显 得十分重要。
3.1 常规检测方法 在用户态可以通过枚举进程窗口、分析进程打开的句柄
表等方法得到进程列表;而内核态列举进程有直接遍历 EPROCSS 双向链表、检查 SSDT 是否被挂钩等方法。下面 2 种是常规方案中强度较高的。 3.1.1 用户态的直接内核函数调用
如前文所述,用户态 Rootkit 通过干扰的 API 函数或者 stub 函数使得程序不能得到正确的信息。只要不通过系统在 用户态提供的函数来发送系统服务请求就能不受干扰。所谓 的用户态直接调用内核函数是指不通过 NTDLL 的帮助直接 进入内核。
第 36 卷 第 5 期 Vol.36 No.5
计算机工程 Computer Engineering
2010 年 3 月 March 2010
·安全技术·
文章编号:1000—3428(2010)05—0140—03 文献标识码:A
中图分类号:TP316
பைடு நூலகம்
Windows Rootkit 进程隐藏与检测技术
图 1 显示了用户态的内核服务请求在 NTDLL 中由 int 2E 或 sysenter 指令传入内核。根据 stub 函数的工作原理,仿造 一个发起系统调用请求的函数,当需要使用系统内核服务函 数枚举进程的时候在本进程中直接使用仿造的 stub 函数发起 内核服务请求,如图 1 中虚线所示。该方法可以无视用户态 的一切 hook 得到一个完整的进程列表,对所有用户态隐藏都 有效,但只能应对少数内核态隐藏。 3.1.2 挂钩 SwapContext 函数
Win32 子系统
OS/2子系统
OS2.exe
Kernel32.dll
ntdll.dll int 0x2E (sysenter)
用户模式 内核模式
KisystemService ntoskrnl.exe
hal.dll
图 1 API 调用过程
作者简介:王 雷(1983-),男,硕士研究生,主研方向:计算机信 息安全;凌 翔,副教授 收稿日期:2009-10-15 E-mail:l_go@
3 隐藏进程检测
在隐藏进程的检测中,一种简单而有效的思想就是做对 比:用可能被修改过的进程列表同正确的列表做对比;如果 结果不一样,那么不同之处就是存在隐藏的地方。有的文献 称这种方法为 cross-view。一般而言,用户态 API 函数得到 的进程列表可能不含部分进程。要利用对比法得出结论,最 关键的是得到正确的进程列表。
如图 1 所示,从 API 的调用过程来看,挂钩动态连接库 ntdll.dll 中的 stub 函数比挂钩 API 更好。stub 函数和内核中 相对应的 Native API 的名字完全相同,调用的 stub 函数能实 现对同名内核函数的调用[3-4]。如图 1 中实线箭头所示,Win32 程序的调用一般会被转向到 Windows 子系统库 Kernel32.dll 中的相应函数,再被转换到 Ntdll.dll 中的 stub 的函数中,由 int 2E 或 sysenter 指令使调用陷入到内核。