简单实现隐藏SSDT HOOK

原理:通过Hook KiFastCallEntyr来替换函数地址,达到隐藏SSDT HOOK,可怜的是二级跳转也不能过XueTr对KiFastCallEntyr的检测

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
/************************************/
//简单实现隐藏SSDT HOOK By ZzAge
/************************************/

#include <ntddk.h>

#define BYTE unsigned char

#define MEM_TAG 'ZMEM'

NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);

VOID Unload(
IN PDRIVER_OBJECT DriverObject
);

typedef NTSTATUS (*NTOPENPROCESS)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK AccessMask,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId
);

NTSTATUS PsLookupProcessByProcessId(
IN HANDLE ProcessId,
OUT PEPROCESS *Process
);

PUCHAR PsGetProcessImageFileName(
IN PEPROCESS Process
);

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, Unload)
#endif

NTOPENPROCESS OldNtOpenProcess;

BYTE JmpCode[5]={0xE9,0x00,0x00,0x00,0x00};
BYTE OrgCode[5]={0x8B,0x3F,0x8B,0x1C,0x87};
BYTE PushRetCode[6]={0x68,0x00,0x00,0x00,0x00,0xc3};

ULONG uKiFastCallEntryAddr=0;
ULONG HookAddr=0;
ULONG JMPRet=0;
ULONG PushRetMem=0;

//NtOpenProcess代理函数
NTSTATUS MyNtOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK AccessMase,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId
)
{
PEPROCESS lpPEPROCESS;
NTSTATUS status;
char *ProcessName;

//取要打开目标进程的PEPROCESS
status=PsLookupProcessByProcessId(ClientId->UniqueProcess,&lpPEPROCESS);

if (NT_SUCCESS(status))
{
if (KeGetCurrentIrql()==PASSIVE_LEVEL)
{
ProcessName=_strupr(PsGetProcessImageFileName(lpPEPROCESS));
if (strcmp(ProcessName,"NOTEPAD.EXE")==0) //判断打开的进程是否为NOTEPAD.EXE
{
return STATUS_ACCESS_DENIED;
}
}

}
return OldNtOpenProcess(ProcessHandle,AccessMase,ObjectAttributes,ClientId);
}

//HOOK KiFastCallEntry过滤函数
__declspec(naked)void OverFuck()
{
_asm
{
pushfd
pushad
mov edi,dword ptr [edi]
mov ebx,dword ptr [edi+eax*4]
cmp OldNtOpenProcess,ebx; //比较是否为NtOpenProcess
je Label1
popad
popfd
mov edi,dword ptr [edi]
mov ebx,dword ptr [edi+eax*4]
jmp [JMPRet];
Label1:
popad
popfd
mov ebx,MyNtOpenProcess //修改NtOpenProcess为我们的代理函数
jmp [JMPRet];

}

}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldIrql;
UNICODE_STRING ustrFunctionName;

DbgPrint("[HideSSDT] DriverEntry!\n");
//卸载例程
DriverObject->DriverUnload = Unload;

//获取NtOpenProcess地址
RtlInitUnicodeString(&ustrFunctionName, L"NtOpenProcess" );
OldNtOpenProcess=(NTOPENPROCESS)MmGetSystemRoutineAddress( &ustrFunctionName);

DbgPrint("NtOpenProcess=0x%08X",OldNtOpenProcess);

//系统调用管理器的地址保存在MSR寄存器里面,标识ID为0x176是SYSENTER_EIP_MSR寄存器,存放着KiFastCallEntry地址!所以在这里用rdmsr读取KiFastCallEntry地址;
__asm
{
pushfd
pushad
mov ecx,0x176
rdmsr
mov uKiFastCallEntryAddr,eax //获取KiFastCallEntry地址
xor ecx,ecx
Label1:
cmp ecx,0x100
je Label3
mov edx,DWORD ptr [eax]
cmp edx,0x1C8B3F8B //搜索特征码,获取要Hook的位置
je Label2
inc eax
inc ecx
jmp Label1
Label2:
mov HookAddr,eax
Label3:
popad
popfd
}

if (HookAddr==0)
{
return status;
}
//申请分配二级跳转内存
PushRetMem=(ULONG)ExAllocatePoolWithTag(NonPagedPool,6,MEM_TAG);

if ((PVOID)PushRetMem==NULL)
{
return status;
}

DbgPrint("PushRetMem=0x%08X",PushRetMem);

//一级跳转地址
*(ULONG*)&JmpCode[1]=(ULONG)(PushRetMem)-(HookAddr+5);
//二级跳转地址
*(ULONG*)&PushRetCode[1]=(ULONG)OverFuck;
//HOOK返回地址
JMPRet=HookAddr+5;

//提升中断请求级
oldIrql = KeRaiseIrqlToDpcLevel();

//关闭中断
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
//进行HOOK操作
RtlCopyMemory((PVOID)PushRetMem,PushRetCode,6);
RtlCopyMemory((PVOID)HookAddr,JmpCode,5);

//开启中断
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
//恢复先前中断请求级
KeLowerIrql(oldIrql);
DbgPrint("KiFastCallEntry=0x%08X",uKiFastCallEntryAddr);
DbgPrint("HookAddr=0x%08X",HookAddr);
//添加代码

return status;
}

VOID Unload( IN PDRIVER_OBJECT DriverObject)
{
if (HookAddr!=0)
{
KIRQL oldIrql;
//提升中断请求级
oldIrql = KeRaiseIrqlToDpcLevel();
//关闭中断
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
//进行还原HOOK操作
RtlCopyMemory((PVOID)HookAddr,OrgCode,5);
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
//恢复先前中断请求级
KeLowerIrql(oldIrql);
// 释放内存
ExFreePool((PVOID)PushRetMem);
}
DbgPrint("[HideSSDT] Unloaded\n");
}