rootkit逃过杀软检测

作者:Trojan [ESST]
信息来源: 噩靈戰隊[Evil-Soul Security Team] http://bbs.x-xox-x.com/
2009年写的
有一个时期,杀毒软件的内核部分常常是用PsSetCreateProcessNotify为基础,进行安全检查.比如有一个进程诞生的时候,检查是否是已知的病毒进程,所以在加载dll的时候检查里面有没有病毒码.刚才提到的PsSetCreateProcessNotify这个函数原型如下:

NTSTATUS
PsSetCreateProcessNotifyRoutine(
      IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
      IN BOLLEAN   Remove
);

其中NotifyRoutine是一个回调函数.我们假设Remove为FLASE,则执行这个函数的结果是把NofifyRountine注册了一个回调函数.原型如下:

VOID
(*PCREATE_PROCESS_NOTIFY_ROUTINE)(
      IN HANDLE ParentId,
      IN HANDLE ProcessId,
      IN BOOLEAN   Create
);

这个函数被回调的时候,ParentId是父进程Id,而ProcessId则是系统要通知我们的进程ID,这个进程被创建或者被注销的时候,这个函数被调用.
大家可能会问,只得到进程ID,如何检查这个进程,比如EXE文件路径怎么获得?命令行参数怎么获得?在WDK之前,这些都可以通过一些非公开的技术手段来获得.但在WDK之后,如果使用PsSetCreateProcessNotifyRoutineEx,可以比较容易得到这些参数.
PsSetCreateProcessNotifyRoutineEx的不同之处在与回调函数的参数发生了改变:

VOID
CreateProcessNotifyEx (
    __inout   PEPROCESS Process,
    __in HANDLE   ProcessId,
    __in_opt   PPS_CREATE_NOTIFY_INFO CreateInfo
);

当CreateInfor不为空的时候,这些信息被提供在CreateInfo中.结构如下:

typedef struct   _PS_CREATE_NOTIFY_INFO {
   __in   SIZE_T   Size;
   union {
    __in ULONG Flags;
    struct {
       __in   ULONG FileOpenNameAvailable   :   1;
       __in   ULONG Reserved   :   31;
    };
};
__in HANDLE ParentProcessId;
__in CLIENT_ID   CreatingThreadId;
__inout struct   _FILE_OBJECT *FileObject;
__in   PCUNICODE_STRING   ImageFileName;
__in_opt   PCUNICODE_STRING   CommandLine;
__out   NTSTATUS CreationStatus;
} PS_CREATE_NOTIFY_INFO, *PPS_CREATE-NOTIFY_INFO;

既然如此,作为杀软的开发者,就可以在进程加载的时候,检查ImageFileName,或者直接得到FileObject来扫描其中是否含有病毒特征码.
此外进程加载的每个DLL也需要检查.这有另一个函数提供

NTSTATUS
       PsSetLoadImageNotifyRoutine(
            IN   PLOAD_IMAGE_NOTIFY_ROUTINE   NotifyRountine
       );

这个函数也追加一个回调函数,当有dll模块被进程加载的时候,这个回调函数会被系统调用.这样dll加载的时候.杀软的开发者可以从FullImageName中得到dll文件的名字,可以预先对这个文件进行扫描.
如果rootkit打算防止杀软用以上的方法扫描一些隐秘的进程或者模块文件.Hook上面两个函数是一个可行的途径.但是呢,很多杀软都会配备HIPS都会关注被HOOK的内核调用.那么就不能HOOK拉.下面我用winDbg跟踪到vista32位版本中PsSetCteateProcessNotifyRoutine的实现过程.

kd> u PsSetCreateProcessNotifyRoutine
nt!PsSetCreateProcessNotifyRoutine;
81a1c9f3 8bff                 mov    edi,edi
81a1c9f5   55                push    ebp
81a1c9f6   8bec             mov    ebp,esp
81a1c9f8   5d                pop        ebp
81a1c9f9   eb0a                 jmp
nt!PspSetCreateProcessNotifyRoutine   (81a1ca05)
81a1c9fb   cc                int       3
81a1c9fc   cc                int       3
81a1c9fd   cc                int       3

很明显,这个PsSetCreateProcessNotifyRoutine不是要领.因为直接跳转PspSetCreateProcessNotifyRoutine去了.在看看PspSetCreateProcessNotifyRoutine的跟踪;

nt!PspSetCreateProcessNotifyRoutine:
81a1ca05   8bff       mov     edi,edi
81a1ca07   55          push ebp
81a1ca08   8bec       mov     ebp,esp
81a1ca0a   51          push ecx

;这里研究下[ebp+0ch]到底是哪几个参数
;回忆下函数原型
NTSTATUS
;PsSetCreateProcessNotifyRoutine(
;       IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
;       IN BOLLEAN   Remove
;先压入的是remove然后压入NotifyRoutine,最后压入返回地址.然后跳转到
;PsSetCreateProcessNotifyRoutine此时remove实际上是esp+8h.
;进入PsSetCreateProcessNotifyRoutine后连续Push和pop刚好平衡.esp
;没有变在跳转PspSetCreateProcessNotifyRoutine此时出现push ebp,
;remove应该是[ebp+8h+4h]也就是[ebp+0ch].所以[ebp+08h]是第一个
;参数
81a1ca0b   807d0c00           cmp     byte   prt   [ebp+0ch],0
81a1ca0f 53                   push ebx
81a1ca10   56                   push esi
81a1ca11   57                   push edi
;如果remove为false跳转,否则继续
81a1ca12   7474                 je
nt!PspSetCreateProcessNotifyRoutine+0x83 (81a1ca88)
;这里开始移除回调函数
;;省略部分
;最后判断PspNotifyEnableMask的第二位是否为0.如果不为0则跳转
;返回成功

上面省略了一大部分,其实当你研究完这个函数构成就可以把别人的注册的回调函数去掉.就是如果知道别人的注册过的回调函数指针.就可以去掉他.对于rootkit,如果remove掉了这些回调函数.杀毒软件可以被悄无声息的禁用掉.还不会出错.很基本的文章.本人刚接触内核.参考了很多东西.写了本文.有什么错误,欢迎大家指证.

没有评论 »

还没有评论呢。

这篇文章上的评论的 RSS feed TrackBack URI

留下评论

If you want to leave a feedback to this post or to some other user´s comment, simply fill out the form below.

(必填)

(必填)



Verify Code   If you cannot see the CheckCode image,please refresh the page again!