网络安全 频道

检测隐藏进程

除此之外,我们来看看从ntoskrnl.pdb中得到的HANDLE_TABLE结构:

Code:

struct _HANDLE_TABLE {
// static data ------------------------------------
// non-static data --------------------------------
/*<thisrel this+0x0>*/ /*|0x4|*/ unsigned long Flags;
/*<thisrel this+0x4>*/ /*|0x4|*/ long HandleCount;
/*<thisrel this+0x8>*/ /*|0x4|*/ struct _HANDLE_TABLE_ENTRY*** Table;
/*<thisrel this+0xc>*/ /*|0x4|*/ struct _EPROCESS* QuotaProcess;
/*<thisrel this+0x10>*/ /*|0x4|*/ void* UniqueProcessId;
/*<thisrel this+0x14>*/ /*|0x4|*/ long FirstFreeTableEntry;
/*<thisrel this+0x18>*/ /*|0x4|*/ long NextIndexNeedingPool;
/*<thisrel this+0x1c>*/ /*|0x38|*/ struct _ERESOURCE HandleTableLock;
/*<thisrel this+0x54>*/ /*|0x8|*/ struct _LIST_ENTRY HandleTableList;
/*<thisrel this+0x5C>*/ /*|0x10|*/ struct _KEVENT HandleContentionEvent;
}; // <size 0x6c>

根据这些数据我们用C语言还原这个结构:

Code:

typedef struct _WIN2K_HANDLE_TABLE
{
ULONG Flags;
LONG HandleCount;
PHANDLE_TABLE_ENTRY **Table;
PEPROCESS QuotaProcess;
HANDLE UniqueProcessId;
LONG FirstFreeTableEntry;
LONG NextIndexNeedingPool;
ERESOURCE HandleTableLock;
LIST_ENTRY HandleTableList;
KEVENT HandleContentionEvent;
} WIN2K_HANDLE_TABLE , *PWIN2K_HANDLE_TABLE ;

显而易见,句柄表由对象表的三个层次的索引组成。现在我们再来看看ExLookhandleTableEntry函数:

Code:

PAGE:00492E2B ExLockHandleTableEntry proc near
PAGE:00492E2B
PAGE:00492E2B
PAGE:00492E2B var_8 = dword ptr -8
PAGE:00492E2B var_4 = dword ptr -4
PAGE:00492E2B HandleTable = dword ptr 8
PAGE:00492E2B Entry = dword ptr 0Ch
PAGE:00492E2B
PAGE:00492E2B push ebp
PAGE:00492E2C mov ebp, esp
PAGE:00492E2E push ecx
PAGE:00492E2F push ecx
PAGE:00492E30 push ebx
PAGE:00492E31 push esi
PAGE:00492E32 xor ebx, ebx
PAGE:00492E34 loc_492E34:
PAGE:00492E34 mov eax, [ebp+Entry]
PAGE:00492E37 mov esi, [eax]
PAGE:00492E39 test esi, esi
PAGE:00492E3B mov [ebp+var_8], esi
PAGE:00492E3E jz short loc_492E89
PAGE:00492E40 jle short loc_492E64
PAGE:00492E42 mov eax, esi
PAGE:00492E44 or eax, 80000000h // set WIN2K_TABLE_ENTRY_LOCK_BIT
PAGE:00492E49 mov [ebp+var_4], eax
PAGE:00492E4C mov eax, [ebp+var_8]
PAGE:00492E4F mov ecx, [ebp+Entry]
PAGE:00492E52 mov edx, [ebp+var_4]
PAGE:00492E55 cmpxchg [ecx], edx
PAGE:00492E58 cmp eax, esi
PAGE:00492E5A jnz short loc_492E64
PAGE:00492E5C mov al, 1
PAGE:00492E5E loc_492E5E:
PAGE:00492E5E pop esi
PAGE:00492E5F pop ebx
PAGE:00492E60 leave
PAGE:00492E61 retn 8
PAGE:00492E64 loc_492E64:
PAGE:00492E64 mov eax, ebx
PAGE:00492E66 inc ebx
PAGE:00492E67 cmp eax, 1
PAGE:00492E6A jb loc_4BC234
PAGE:00492E70 mov eax, [ebp+HandleTable]
PAGE:00492E73 push offset unk_46D240 ; Timeout
PAGE:00492E78 push 0 ; Alertable
PAGE:00492E7A push 0 ; WaitMode
PAGE:00492E7C add eax, 5Ch
PAGE:00492E7F push 0 ; WaitReason
PAGE:00492E81 push eax ; Object
PAGE:00492E82 call KeWaitForSingleObject
PAGE:00492E87 jmp short loc_492E34
PAGE:00492E89 loc_492E89:
PAGE:00492E89 xor al, al
PAGE:00492E8B jmp short loc_492E5E
PAGE:00492E8B ExLockHandleTableEntry endp

这段代码检查了HANDLE_TABLE_ENTRY结构的Object成员的第31位,设置该位,如果该位被设置,意味着等待HANDLE_TABLE的

HandleContentionEvent。对我们来说设置TABLE_ENTRY_LOCK_BIT才是最重要的,因为它是目标地址的一部分,如果标志位没有设置,我们就会

得到无效句柄。现在我们明白了句柄表的格式,可以写代码来遍历这个表了:

Code:

void ScanWin2KHandleTable(PWIN2K_HANDLE_TABLE HandleTable)
{
int i, j, k;
PHANDLE_TABLE_ENTRY Entry;

for (i = 0; i < 0x100; i++)
{
if (HandleTable->Table)
{
for (j = 0; j < 0x100; j++)
{
if (HandleTable->Table[j])
{
for (k = 0; k < 0x100; k++)
{
Entry = &HandleTable->Table[j][k];

if (Entry->Object)
ProcessObject((PVOID)((ULONG)Entry->Object | WIN2K_TABLE_ENTRY_LOCK_BIT));
}
}
}
}
}
}

这段代码处理了所有表中的成员,并且为每一个成员调用了ProcessObject函数。ProcessObject函数检测成员类型并且恰当地处理了它们。这

个函数代码如下:

Code:

void ProcessObject(PVOID Object)
{
POBJECT_HEADER ObjectHeader = OBJECT_TO_OBJECT_HEADER(Object);

if (ObjectHeader->Type == *PsProcessType) CollectProcess(Object);

if (ObjectHeader->Type == *PsThreadType) ThreadCollect(Object);
}

我们已经了解了
Windows 2000下的句柄表结构,现在开始分析Windows XP的表结构。从反汇编ExpLookupHandleTableEntry函数开始:

Code:

PAGE:0048D3C1 ExpLookupHandleTableEntry proc near
PAGE:0048D3C1
PAGE:0048D3C1
PAGE:0048D3C1 HandleTable = dword ptr 8
PAGE:0048D3C1 Handle = dword ptr 0Ch
PAGE:0048D3C1
PAGE:0048D3C1 mov edi, edi
PAGE:0048D3C3 push ebp
PAGE:0048D3C4 mov ebp, esp
PAGE:0048D3C6 and [ebp+Handle], 0FFFFFFFCh
PAGE:0048D3CA mov eax, [ebp+Handle]
PAGE:0048D3CD mov ecx, [ebp+HandleTable]
PAGE:0048D3D0 mov edx, [ebp+Handle]
PAGE:0048D3D3 shr eax, 2
PAGE:0048D3D6 cmp edx, [ecx+38h]
PAGE:0048D3D9 jnb loc_4958D6
PAGE:0048D3DF push esi
PAGE:0048D3E0 mov esi, [ecx]
PAGE:0048D3E2 mov ecx, esi
PAGE:0048D3E4 and ecx, 3 // ecx - table level
PAGE:0048D3E7 and esi, not 3 // esi - pointer to first table
PAGE:0048D3EA sub ecx, 0
PAGE:0048D3ED jnz loc_48DEA4
PAGE:0048D3F3 lea eax, [esi+eax*8]
PAGE:0048D3F6 loc_48D3F6:
PAGE:0048D3F6 pop esi
PAGE:0048D3F7 loc_48D3F7:
PAGE:0048D3F7 pop ebp
PAGE:0048D3F8 retn 8
PAGE:0048DEA4 loc_48DEA4:
PAGE:0048DEA4 dec ecx
PAGE:0048DEA5 mov ecx, eax
PAGE:0048DEA7 jnz loc_52F57A
PAGE:0048DEAD shr ecx, 9
PAGE:0048DEB0 mov ecx, [esi+ecx*4]
PAGE:0048DEB3 loc_48DEB3:
PAGE:0048DEB3 and eax, 1FFh
PAGE:0048DEB8 lea eax, [ecx+eax*8]
PAGE:0048DEBB jmp loc_48D3F6
PAGE:0052F57A loc_52F57A:
PAGE:0052F57A shr ecx, 13h
PAGE:0052F57D mov edx, ecx
PAGE:0052F57F mov ecx, [esi+ecx*4]
PAGE:0052F582 shl edx, 13h
PAGE:0052F585 sub eax, edx
PAGE:0052F587 mov edx, eax
PAGE:0052F589 shr edx, 9
PAGE:0052F58C mov ecx, [ecx+edx*4]
PAGE:0052F58F jmp loc_48DEB3

再来看看ntoskrnl.pdb中的HANDLE_TABLE:

Code:

struct _HANDLE_TABLE {
// static data ------------------------------------
// non-static data --------------------------------
/*<thisrel this+0x0>*/ /*|0x4|*/ unsigned long TableCode;
/*<thisrel this+0x4>*/ /*|0x4|*/ struct _EPROCESS* QuotaProcess;
/*<thisrel this+0x8>*/ /*|0x4|*/ void* UniqueProcessId;
/*<thisrel this+0xc>*/ /*|0x10|*/ struct _EX_PUSH_LOCK HandleTableLock[4];
/*<thisrel this+0x1c>*/ /*|0x8|*/ struct _LIST_ENTRY HandleTableList;
/*<thisrel this+0x24>*/ /*|0x4|*/ struct _EX_PUSH_LOCK HandleContentionEvent;
/*<thisrel this+0x28>*/ /*|0x4|*/ struct _HANDLE_TRACE_DEBUG_INFO* DebugInfo;
/*<thisrel this+0x2c>*/ /*|0x4|*/ long ExtraInfoPages;
/*<thisrel this+0x30>*/ /*|0x4|*/ unsigned long FirstFree;
/*<thisrel this+0x34>*/ /*|0x4|*/ unsigned long LastFree;
/*<thisrel this+0x38>*/ /*|0x4|*/ unsigned long NextHandleNeedingPool;
/*<thisrel this+0x3c>*/ /*|0x4|*/ long HandleCount;
/*<thisrel this+0x40>*/ /*|0x4|*/ unsigned long Flags;
/*<bitfield this+0x40>*/ /*|0x1|*/ unsigned char StrictFIF0:1;
}; // <size 0x44>


0
相关文章