├── .gitattributes ├── LICENSE.md ├── README.md └── src └── ColdKernel.c /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Rat431 inc 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ColdKernel_KUSER 2 | ColdKernel is a simple driver that runs in Kernel mode privilege. 3 | The main purpose of this driver is to give to the user the ability to hook a protected memory region structure called KUSER_SHARED_DATA, which is always located at the base 4 | address 0x7FFE0000. 5 | -------------------------------------------------------------------------------- /src/ColdKernel.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 Rat431 (https://github.com/Rat431). 3 | This software is under the MIT license, for more informations check the LICENSE file. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define KUSER_BASE_ADDRESS 0x7FFE0000 13 | #define KUSER_SIZE 0x1000 14 | #define KUSER_SIZE_DWORD (KUSER_SIZE / 4) 15 | 16 | struct KuserDataStruct 17 | { 18 | uintptr_t Address; 19 | BOOLEAN Hook; // Flag here 20 | char Data[4]; 21 | }; 22 | struct KeRestoreData 23 | { 24 | uintptr_t Address; 25 | char Data[4]; 26 | }; 27 | struct KuserDataStruct* kuserstruct = NULL; 28 | struct KeRestoreData* restorestruct = NULL; 29 | 30 | void KeStoreOriginalData(PVOID Address) 31 | { 32 | struct KeRestoreData* restore = restorestruct; 33 | struct KeRestoreData tempdata = { 0 }; 34 | for (int i = 0; i < KUSER_SIZE_DWORD; i++, restore++) 35 | { 36 | if (RtlCompareMemory(restore, &tempdata, sizeof(struct KeRestoreData)) == sizeof(struct KeRestoreData)) { 37 | restore->Address = (uintptr_t)Address; 38 | RtlCopyMemory(restore->Data, Address, 4); 39 | DbgPrint("Data stored!\n"); 40 | break; 41 | } 42 | if (restore->Address == (uintptr_t)Address) { 43 | DbgPrint("Original dword data at 0x%x cannot be saved.\n", restore->Address); 44 | break; 45 | } 46 | } 47 | } 48 | PVOID KeGetOriginalStoredData(PVOID Address) 49 | { 50 | struct KeRestoreData* restore = restorestruct; 51 | for (int i = 0; i < KUSER_SIZE_DWORD; i++, restore++) 52 | { 53 | if (restore->Address == (uintptr_t)Address) { 54 | return restore->Data; 55 | } 56 | } 57 | return NULL; 58 | } 59 | 60 | void HookKernel(PVOID Address, PVOID data, int size) 61 | { 62 | RtlCopyMemory(Address, data, size); 63 | } 64 | 65 | void HookKuser(struct KuserDataStruct* Configuration) 66 | { 67 | // Search what we should hook 68 | uintptr_t Starting = KUSER_BASE_ADDRESS; 69 | int size = KUSER_SIZE_DWORD; 70 | int loop = 0; 71 | for (;;) 72 | { 73 | if (loop < size) 74 | { 75 | // Hook here 76 | uintptr_t CurrentAddress = Starting; 77 | struct KuserDataStruct* Structure = Configuration; 78 | 79 | for (int i = 0; i < size; i++, Structure++) 80 | { 81 | if (CurrentAddress == Structure->Address) 82 | { 83 | if (Structure->Hook) 84 | { 85 | DbgPrint("The following address is being hooked: 0x%x\n", CurrentAddress); 86 | PMDL descriptor = IoAllocateMdl((PVOID)CurrentAddress, 4, 0, 0, 0); 87 | if (descriptor) 88 | { 89 | MmProbeAndLockPages(descriptor, KernelMode, IoReadAccess); 90 | PVOID datamap = MmMapLockedPagesSpecifyCache(descriptor, KernelMode, MmCached, NULL, 0, NormalPagePriority); 91 | if (datamap) 92 | { 93 | DbgPrint("All went ok, memory will be hooked in few seconds...\n"); 94 | KeStoreOriginalData(CurrentAddress); 95 | HookKernel(datamap, Structure->Data, 4); 96 | 97 | // Free everything 98 | MmUnmapLockedPages(datamap, descriptor); 99 | MmUnlockPages(descriptor); 100 | IoFreeMdl(descriptor); 101 | } 102 | else 103 | { 104 | DbgPrint("HOOK FALIED: MmMapLockedPagesSpecifyCache on address 0x%x falied.\n", CurrentAddress); 105 | MmUnlockPages(descriptor); 106 | IoFreeMdl(descriptor); 107 | } 108 | } 109 | else 110 | DbgPrint("HOOK FALIED: IoAllocateMdl on address 0x%x falied.\n", CurrentAddress); 111 | } 112 | break; 113 | } 114 | } 115 | loop++; 116 | Starting += 4; 117 | } 118 | else 119 | break; 120 | } 121 | } 122 | void UnHookKusser() 123 | { 124 | // Search what we should unhook 125 | uintptr_t Starting = KUSER_BASE_ADDRESS; 126 | int size = KUSER_SIZE_DWORD; 127 | int loop = 0; 128 | for (;;) 129 | { 130 | if (loop < size) 131 | { 132 | // Hook here 133 | uintptr_t CurrentAddress = Starting; 134 | struct KuserDataStruct* Structure = kuserstruct; 135 | 136 | for (int i = 0; i < size; i++, Structure++) 137 | { 138 | if (CurrentAddress == Structure->Address) 139 | { 140 | if (Structure->Hook) 141 | { 142 | DbgPrint("The following address is being restored: 0x%x\n", CurrentAddress); 143 | PMDL descriptor = IoAllocateMdl((PVOID)CurrentAddress, 4, 0, 0, 0); 144 | if (descriptor) 145 | { 146 | MmProbeAndLockPages(descriptor, KernelMode, IoReadAccess); 147 | PVOID datamap = MmMapLockedPagesSpecifyCache(descriptor, KernelMode, MmCached, NULL, 0, NormalPagePriority); 148 | if (datamap) 149 | { 150 | DbgPrint("All went ok, memory will be hooked in few seconds...\n"); 151 | PVOID RestoreData = KeGetOriginalStoredData(CurrentAddress); 152 | if (RestoreData) 153 | { 154 | HookKernel(datamap, RestoreData, 4); 155 | DbgPrint("Mem restored!\n"); 156 | } 157 | else 158 | DbgPrint("No restore data available!\n"); 159 | 160 | // Free everything 161 | MmUnmapLockedPages(datamap, descriptor); 162 | MmUnlockPages(descriptor); 163 | IoFreeMdl(descriptor); 164 | } 165 | else 166 | { 167 | DbgPrint("HOOK FALIED: MmMapLockedPagesSpecifyCache on address 0x%x falied.\n", CurrentAddress); 168 | MmUnlockPages(descriptor); 169 | IoFreeMdl(descriptor); 170 | } 171 | } 172 | else 173 | DbgPrint("HOOK FALIED: IoAllocateMdl on address 0x%x falied.\n", CurrentAddress); 174 | } 175 | break; 176 | } 177 | } 178 | loop++; 179 | Starting += 4; 180 | } 181 | else 182 | break; 183 | } 184 | } 185 | 186 | NTSTATUS DriverReadConfing(struct KuserDataStruct* Configuration) 187 | { 188 | DbgPrint("Reading configuration\n"); 189 | 190 | // Read from the file if present 191 | UNICODE_STRING name; 192 | OBJECT_ATTRIBUTES object; 193 | HANDLE hFile; 194 | NTSTATUS status; 195 | IO_STATUS_BLOCK statusblock; 196 | FILE_STANDARD_INFORMATION fileinfo; 197 | LARGE_INTEGER byteOffset; 198 | 199 | RtlInitUnicodeString(&name, L"\\SystemRoot\\ColdKernel.bin"); 200 | InitializeObjectAttributes(&object, &name, 201 | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 202 | NULL, NULL); 203 | 204 | // Check IRQL 205 | if (KeGetCurrentIrql() != PASSIVE_LEVEL) 206 | return STATUS_INVALID_DEVICE_STATE; 207 | 208 | status = ZwCreateFile( 209 | &hFile, GENERIC_READ, &object, &statusblock, NULL, FILE_ATTRIBUTE_NORMAL, 210 | 0, 211 | FILE_OPEN, 212 | FILE_SYNCHRONOUS_IO_NONALERT, 213 | NULL, 0); 214 | 215 | if (NT_SUCCESS(status)) 216 | { 217 | // Get File size 218 | status = ZwQueryInformationFile( 219 | hFile, 220 | &statusblock, 221 | &fileinfo, 222 | sizeof(FILE_STANDARD_INFORMATION), 223 | FileStandardInformation); 224 | if (NT_SUCCESS(status)) 225 | { 226 | if (fileinfo.EndOfFile.QuadPart >= (sizeof(struct KuserDataStruct) * KUSER_SIZE_DWORD)) 227 | { 228 | byteOffset.LowPart = byteOffset.HighPart = 0; 229 | status = ZwReadFile(hFile, NULL, NULL, NULL, &statusblock, 230 | Configuration, (sizeof(struct KuserDataStruct) * KUSER_SIZE_DWORD), &byteOffset, NULL); 231 | if (NT_SUCCESS(status)) { 232 | DbgPrint("Configuration has been read!\n"); 233 | } 234 | } 235 | else 236 | status = STATUS_ABANDONED; 237 | } 238 | ZwClose(hFile); 239 | } 240 | return status; 241 | } 242 | 243 | NTSTATUS DriverSystemInit() 244 | { 245 | // Read Configuration firstly 246 | SIZE_T kuserstructSize = sizeof(struct KuserDataStruct) * KUSER_SIZE_DWORD; 247 | SIZE_T kuserrestoreSize = sizeof(struct KeRestoreData) * KUSER_SIZE_DWORD; 248 | NTSTATUS status; 249 | 250 | _try 251 | { 252 | status = ZwAllocateVirtualMemory(NtCurrentProcess(), &kuserstruct, NULL, &kuserstructSize, MEM_COMMIT | MEM_RESERVE, 253 | PAGE_READWRITE); 254 | if (NT_SUCCESS(status)) 255 | { 256 | status = ZwAllocateVirtualMemory(NtCurrentProcess(), &restorestruct, NULL, &kuserrestoreSize, MEM_COMMIT | MEM_RESERVE, 257 | PAGE_READWRITE); 258 | if (NT_SUCCESS(status)) 259 | { 260 | status = DriverReadConfing(kuserstruct); 261 | if (NT_SUCCESS(status)) 262 | { 263 | HookKuser(kuserstruct); 264 | return STATUS_SUCCESS; 265 | } 266 | } 267 | else 268 | { 269 | SIZE_T RSize = NULL; 270 | ZwFreeVirtualMemory(NtCurrentProcess(), &kuserstruct, &RSize, MEM_RELEASE); 271 | } 272 | } 273 | } 274 | __except (EXCEPTION_EXECUTE_HANDLER) 275 | { 276 | return STATUS_ACCESS_DENIED; 277 | } 278 | return status; 279 | } 280 | NTSTATUS DriverSystemClose() 281 | { 282 | SIZE_T RSize; 283 | NTSTATUS status; 284 | 285 | _try 286 | { 287 | UnHookKusser(); 288 | 289 | RSize = NULL; 290 | status = ZwFreeVirtualMemory(NtCurrentProcess(), &kuserstruct, &RSize, MEM_RELEASE); 291 | if (NT_SUCCESS(status)) 292 | { 293 | RSize = NULL; 294 | status = ZwFreeVirtualMemory(NtCurrentProcess(), &restorestruct, &RSize, MEM_RELEASE); 295 | } 296 | } 297 | __except (EXCEPTION_EXECUTE_HANDLER) 298 | { 299 | return STATUS_ACCESS_DENIED; 300 | } 301 | return status; 302 | } 303 | 304 | NTSTATUS Unload(_In_ struct _DRIVER_OBJECT* DriverObject) 305 | { 306 | return DriverSystemClose(); 307 | } 308 | NTSTATUS DriverEntry(_In_ struct _DRIVER_OBJECT* DriverObject, _In_ PUNICODE_STRING RegistryPath) // Driver Entry 309 | { 310 | DbgPrint("DriverEntry called.\n"); 311 | 312 | // Set unload function 313 | DriverObject->DriverUnload = Unload; 314 | 315 | // Init system 316 | return DriverSystemInit(); 317 | } 318 | --------------------------------------------------------------------------------