diff --git a/kutils.hpp b/kutils.hpp new file mode 100644 index 0000000..0da8a93 --- /dev/null +++ b/kutils.hpp @@ -0,0 +1,865 @@ +/* + * HEADER ONLY KERNEL UTIL LIBRARY - NO IMPORTS - NO STRINGS + */ + +#pragma once +#include +#include + +using u64 = unsigned long long; +using u32 = unsigned long; +using u16 = unsigned short; +using u8 = unsigned char; + +namespace hashstr { +template +struct idx_list_t {}; +template +struct append_t; +template +struct append_t, right> { + typedef idx_list_t result_t; +}; + +template +struct constr_idx_list { + typedef typename append_t::result_t, + N - 1>::result_t result_t; +}; + +template <> +struct constr_idx_list<0> { + typedef idx_list_t<> result_t; +}; + +template +consteval T add(T first) { + return first; +} + +template +consteval T add(T first, Args... args) { + return first + add(args...); +} + +template +consteval T mul(T first) { + return first; +} + +template +consteval T mul(T first, Args... args) { + return first * mul(args...); +} + +template +class hashstr_t; +template +struct hashstr_t > { + consteval hashstr_t(const char (&str)[sizeof...(idx) + 1]) + : _hash((mul(hashchar(str[idx], idx)...) + + add(hashchar(str[idx], idx)...)) ^ + 0xCBF29CE484222325) {} + + unsigned _hash; + consteval unsigned hashchar(const char c, unsigned idx) { + return (c + 1) * 0x100000001B3 * (idx + 1 + c); + } + + unsigned hash() { return _hash; } +}; + +// runtime equivelent of the compile time hash... +inline unsigned hash(const char* str) { + unsigned add_res = 0u, mul_res = 1u; + for (auto idx = 0u; str[idx]; ++idx) { + add_res += (str[idx] + 1) * 0x100000001B3 * (idx + 1 + str[idx]); + mul_res *= (str[idx] + 1) * 0x100000001B3 * (idx + 1 + str[idx]); + } + return (add_res + mul_res) ^ 0xCBF29CE484222325; +} +} // namespace hashstr + +#define HSTRING(str) \ + (hashstr::hashstr_t::result_t>( \ + str) \ + .hash()) + +#define DYN_MOD(x) KUtils::Driver::GetDriverBaseByHash(HSTRING(#x)) + +#define DYN_NT_SYM(x) \ + ((decltype(&x))KUtils::Driver::GetDriverExportByHash( \ + KUtils::Driver::GetKernelBase(), HSTRING(#x))) + +#define DYN_MOD_SYM(mod, exp) \ + ((decltype(&y))KUtils::Driver::GetDriverExportByHash(HSTRING(#mod), \ + HSTRING(#exp))) + +#define DBG_PRINT(...) \ + DYN_NT_SYM(DbgPrintEx) \ + (DPFLTR_SYSTEM_ID, DPFLTR_ERROR_LEVEL, "[KUTILS]" __VA_ARGS__); + +// Export Directory +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 +// Import Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 +// Resource Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 +// Exception Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 +// Security Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 +// Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 +// Debug Directory +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 +// Description String +#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 +// Machine Value (MIPS GP) +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 +// TLS Directory +#define IMAGE_DIRECTORY_ENTRY_TLS 9 +// Load Configuration Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 + +#define DOS_HEADER_MAGIC 0x5A4D +#define PE_HEADER_MAGIC 0x4550 + +namespace KUtils { +typedef struct _IMAGE_DOS_HEADER { + USHORT e_magic; + USHORT e_cblp; + USHORT e_cp; + USHORT e_crlc; + USHORT e_cparhdr; + USHORT e_minalloc; + USHORT e_maxalloc; + USHORT e_ss; + USHORT e_sp; + USHORT e_csum; + USHORT e_ip; + USHORT e_cs; + USHORT e_lfarlc; + USHORT e_ovno; + USHORT e_res[4]; + USHORT e_oemid; + USHORT e_oeminfo; + USHORT e_res2[10]; + LONG e_lfanew; +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +typedef struct _IMAGE_FILE_HEADER { + short Machine; + short NumberOfSections; + unsigned TimeDateStamp; + unsigned PointerToSymbolTable; + unsigned NumberOfSymbols; + short SizeOfOptionalHeader; + short Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +typedef struct _IMAGE_DATA_DIRECTORY { + unsigned VirtualAddress; + unsigned Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +typedef struct _IMAGE_OPTIONAL_HEADER64 { + short Magic; + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + unsigned SizeOfCode; + unsigned SizeOfInitializedData; + unsigned SizeOfUninitializedData; + unsigned AddressOfEntryPoint; + unsigned BaseOfCode; + ULONGLONG ImageBase; + unsigned SectionAlignment; + unsigned FileAlignment; + short MajorOperatingSystemVersion; + short MinorOperatingSystemVersion; + short MajorImageVersion; + short MinorImageVersion; + short MajorSubsystemVersion; + short MinorSubsystemVersion; + unsigned Win32VersionValue; + unsigned SizeOfImage; + unsigned SizeOfHeaders; + unsigned CheckSum; + short Subsystem; + short DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + unsigned LoaderFlags; + unsigned NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + +typedef struct _IMAGE_NT_HEADERS64 { + unsigned Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; + +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + unsigned long Characteristics; // 0 for terminating null import descriptor + unsigned long + OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) + } DUMMYUNIONNAME; + unsigned long + TimeDateStamp; // 0 if not bound, + // -1 if bound, and real date\time stamp + // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + // O.W. date/time stamp of DLL bound to (Old BIND) + + unsigned long ForwarderChain; // -1 if no forwarders + unsigned long Name; + unsigned long + FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) +} IMAGE_IMPORT_DESCRIPTOR; +typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED* PIMAGE_IMPORT_DESCRIPTOR; + +typedef struct _IMAGE_IMPORT_BY_NAME { + unsigned long Hint; + CHAR Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +typedef struct _IMAGE_THUNK_DATA64 { + union { + ULONGLONG ForwarderString; // PBYTE + ULONGLONG Function; // PDWORD + ULONGLONG Ordinal; + ULONGLONG AddressOfData; // PIMAGE_IMPORT_BY_NAME + } u1; +} IMAGE_THUNK_DATA64, *PIMAGE_THUNK_DATA64; +typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; + +typedef struct _LDR_DATA_TABLE_ENTRY { + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + LIST_ENTRY InInitializationOrderLinks; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + unsigned short LoadCount; + unsigned short TlsIndex; + union { + LIST_ENTRY HashLinks; + struct { + PVOID SectionPointer; + ULONG CheckSum; + }; + }; + union { + ULONG TimeDateStamp; + PVOID LoadedImports; + }; + PVOID EntryPointActivationContext; + PVOID PatchInformation; + LIST_ENTRY ForwarderLinks; + LIST_ENTRY ServiceTagLinks; + LIST_ENTRY StaticLinks; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + +typedef struct _PEB_LDR_DATA { + ULONG Length; + UCHAR Initialized; + PVOID SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + +typedef struct _PEB { + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + BOOLEAN Spare; + HANDLE Mutant; + PVOID ImageBaseAddress; + PPEB_LDR_DATA LoaderData; + PVOID ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PVOID FastPebLockRoutine; + PVOID FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID KernelCallbackTable; + PVOID EventLogSection; + PVOID EventLog; + PVOID FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[0x2]; + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID* ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + unsigned char Spare2[0x4]; + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID** ProcessHeaps; + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubSystem; + ULONG ImageSubSystemMajorVersion; + ULONG ImageSubSystemMinorVersion; + ULONG GdiHandleBuffer[0x22]; + ULONG PostProcessInitRoutine; + ULONG TlsExpansionBitmap; + unsigned char TlsExpansionBitmapBits[0x80]; + ULONG SessionId; +} PEB, *PPEB; + +typedef struct _SYSTEM_THREAD { + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + KPRIORITY Priority; + LONG BasePriority; + ULONG ContextSwitchCount; + ULONG State; + KWAIT_REASON WaitReason; +} SYSTEM_THREAD, *PSYSTEM_THREAD; + +typedef struct _SYSTEM_PROCESS_INFORMATION { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER Reserved[3]; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + HANDLE ProcessId; + HANDLE InheritedFromProcessId; + ULONG HandleCount; + ULONG Reserved2[2]; + ULONG PrivatePageCount; + VM_COUNTERS VirtualMemoryCounters; + IO_COUNTERS IoCounters; + SYSTEM_THREAD Threads[0]; + +} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; + +typedef struct _RTL_PROCESS_MODULE_INFORMATION { + HANDLE Section; + PVOID MappedBase; + PVOID ImageBase; + ULONG ImageSize; + ULONG Flags; + USHORT LoadOrderIndex; + USHORT InitOrderIndex; + USHORT LoadCount; + USHORT OffsetToFileName; + UCHAR FullPathName[256]; +} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION; + +typedef struct _RTL_PROCESS_MODULES { + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[1]; +} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; + +typedef struct _OBJECT_DIRECTORY_ENTRY { + struct _OBJECT_DIRECTORY_ENTRY* ChainLink; + PVOID Object; + ULONG HashValue; +} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY; + +typedef struct _OBJECT_DIRECTORY { + POBJECT_DIRECTORY_ENTRY HashBuckets[37]; + EX_PUSH_LOCK Lock; + struct _DEVICE_MAP* DeviceMap; + ULONG SessionId; + PVOID NamespaceEntry; + ULONG Flags; +} OBJECT_DIRECTORY, *POBJECT_DIRECTORY; + +typedef struct _DEVICE_MAP { + POBJECT_DIRECTORY DosDevicesDirectory; + POBJECT_DIRECTORY GlobalDosDevicesDirectory; + ULONG ReferenceCount; + ULONG DriveMap; + UCHAR DriveType[32]; +} DEVICE_MAP, *PDEVICE_MAP; + +typedef struct _IMAGE_EXPORT_DIRECTORY { + ULONG Characteristics; + ULONG TimeDateStamp; + USHORT MajorVersion; + USHORT MinorVersion; + ULONG Name; + ULONG Base; + ULONG NumberOfFunctions; + ULONG NumberOfNames; + ULONG AddressOfFunctions; + ULONG AddressOfNames; + ULONG AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +#pragma pack(push, 1) +typedef struct _IDTR { + USHORT Size; + ULONG64 Address; +} IDTR, PIDTR; +#pragma pack(pop) + +typedef union _KIDTENTRY64 { + union { + struct { + /* 0x0000 */ unsigned short OffsetLow; + /* 0x0002 */ unsigned short Selector; + struct /* bitfield */ + { + /* 0x0004 */ unsigned short IstIndex : 3; /* bit position: 0 */ + /* 0x0004 */ unsigned short Reserved0 : 5; /* bit position: 3 */ + /* 0x0004 */ unsigned short Type : 5; /* bit position: 8 */ + /* 0x0004 */ unsigned short Dpl : 2; /* bit position: 13 */ + /* 0x0004 */ unsigned short Present : 1; /* bit position: 15 */ + }; /* bitfield */ + /* 0x0006 */ unsigned short OffsetMiddle; + /* 0x0008 */ unsigned long OffsetHigh; + /* 0x000c */ unsigned long Reserved1; + }; /* size: 0x0010 */ + /* 0x0000 */ unsigned __int64 Alignment; + }; /* size: 0x0010 */ +} KIDTENTRY64, *PKIDTENTRY64; /* size: 0x0010 */ + +typedef union _IDT_ADDR_T { + ULONG64 Addr; + struct { + ULONG64 OffsetLow : 16; + ULONG64 OffsetMiddle : 16; + ULONG64 OffsetHigh : 32; + }; +} IDT_ADDR_T, PIDT_ADDR_T; + +typedef enum _SYSTEM_INFORMATION_CLASS { + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemNextEventIdInformation, + SystemEventIdsInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemPlugPlayBusInformation, + SystemDockInformation +} SYSTEM_INFORMATION_CLASS, + *PSYSTEM_INFORMATION_CLASS; + +extern "C" PVOID PsGetProcessSectionBaseAddress(__in PEPROCESS Process); +extern "C" PPEB PsGetProcessPeb(PEPROCESS Process); +extern "C" NTSTATUS ZwQuerySystemInformation( + SYSTEM_INFORMATION_CLASS SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); + +namespace Driver { +FORCEINLINE PVOID GetDriverExportByHash(_In_ PVOID lpDriverBase, + _In_ ULONG nStrHash) { + PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)lpDriverBase; + PIMAGE_NT_HEADERS64 lpNtHeader = + (PIMAGE_NT_HEADERS64)(lpDosHeader->e_lfanew + (ULONG64)lpDriverBase); + + PIMAGE_EXPORT_DIRECTORY lpExportDir = + (PIMAGE_EXPORT_DIRECTORY)((ULONG64)lpDriverBase + + lpNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] + .VirtualAddress); + + ULONG32* lpNameArr = + (ULONG32*)(lpExportDir->AddressOfNames + (ULONG64)lpDriverBase); + + ULONG32* lpFuncs = + (ULONG32*)(lpExportDir->AddressOfFunctions + (ULONG64)lpDriverBase); + + USHORT* lpOrdinals = + (USHORT*)(lpExportDir->AddressOfNameOrdinals + (ULONG64)lpDriverBase); + + for (auto nIdx = 0u; nIdx < lpExportDir->NumberOfFunctions; ++nIdx) { + if (!lpNameArr[nIdx] || !lpOrdinals[nIdx]) + continue; + + if (hashstr::hash((PCHAR)((ULONG64)lpDriverBase + lpNameArr[nIdx])) == + nStrHash) + return (PVOID)((ULONG64)lpDriverBase + lpFuncs[lpOrdinals[nIdx]]); + } + return NULL; +} + +/// +/// Gets ntoskrnl.exe module base address by reading the interrupt descriptor +/// table. It reads the first IDT entry which is just div 0 handler. it then +/// loops backwards page by page looking for valid DOS/NT headers and ensures +/// that the size of the image is legit... +/// +/// returns the kernel base address... +FORCEINLINE PVOID GetKernelBase() { + IDTR stIdtr; + __sidt(&stIdtr); + + PKIDTENTRY64 lpDivZero = (PKIDTENTRY64)stIdtr.Address; + IDT_ADDR_T stHndlrAddr; + + stHndlrAddr.OffsetLow = lpDivZero->OffsetLow; + stHndlrAddr.OffsetMiddle = lpDivZero->OffsetMiddle; + stHndlrAddr.OffsetHigh = lpDivZero->OffsetHigh; + + // loop backwards until we find the kernels base address... + ULONG64 nStartPage = (ULONG64)PAGE_ALIGN(stHndlrAddr.Addr); + for (ULONG64 nPage = nStartPage;; nPage -= PAGE_SIZE) { + if (*(USHORT*)nPage == DOS_HEADER_MAGIC) { + PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)nPage; + PIMAGE_NT_HEADERS64 lpNtHeaders = + (PIMAGE_NT_HEADERS64)(lpDosHeader->e_lfanew + nPage); + + if (lpNtHeaders->Signature != PE_HEADER_MAGIC) + continue; + + if (lpNtHeaders->OptionalHeader.SizeOfImage < 0x1000000) + continue; + + return (PVOID)nPage; + } + } +} + +/// +/// Gets driver base address by the hash of the file name of the driver... +/// +/// hash of the drivers file name... +/// +FORCEINLINE PVOID GetDriverBaseByHash(_In_ CONST ULONG dwHash) { + ULONG dwAllocSize{}; + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemModuleInformation, NULL, dwAllocSize, &dwAllocSize); + + PRTL_PROCESS_MODULES moduleInfo = (PRTL_PROCESS_MODULES)DYN_NT_SYM( + ExAllocatePool)(NonPagedPool, dwAllocSize); + + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemModuleInformation, moduleInfo, dwAllocSize, &dwAllocSize); + + for (INT nIdx = 0u; nIdx < moduleInfo->NumberOfModules; ++nIdx) { + PCHAR pszModuleName = (PCHAR)moduleInfo->Modules[nIdx].FullPathName + + moduleInfo->Modules[nIdx].OffsetToFileName; + + if (hashstr::hash(pszModuleName) == dwHash) { + PVOID lpModuleBase = moduleInfo->Modules[nIdx].ImageBase; + DYN_NT_SYM(ExFreePool)(moduleInfo); + return lpModuleBase; + } + } + + DYN_NT_SYM(ExFreePool)(moduleInfo); + return NULL; +} + +/// +/// Get driver base given the module name of the driver... This function calls +/// GetDriverBaseByHash internally... +/// +/// file name of the driver, this is not case +/// dependant... returns a void pointer to the drivers +/// base... +FORCEINLINE PVOID GetDriverBase(_In_ CONST CHAR* pszDriverName) { + return GetDriverBaseByHash(hashstr::hash(pszDriverName)); +} + +/// +/// GetDriverExport via driver name and export routine name... this function +/// calls GetDriverExportByHash internally... +/// +/// null terminated c-string given the module name +/// of the driver... example: "win32k.sys" the c-string name of the export... +/// returns a linear virtual address to the export... +FORCEINLINE PVOID GetDriverExport(_In_ CONST CHAR* pszDriverName, + _In_ CONST CHAR* pszRoutineName) { + PVOID lpDriverBase = GetDriverBase(pszDriverName); + return lpDriverBase ? GetDriverExportByHash(lpDriverBase, + hashstr::hash(pszRoutineName)) + : NULL; +} + +FORCEINLINE PDRIVER_OBJECT GetDriverObject(_In_ CONST PWCHAR pwszDriverName) { + HANDLE handle{}; + OBJECT_ATTRIBUTES attr{}; + UNICODE_STRING dirName{}; + PVOID dir{}; + BOOLEAN success = FALSE; + + DYN_NT_SYM(RtlInitUnicodeString)(&dirName, L"\\Driver"); + InitializeObjectAttributes(&attr, &dirName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + // open OBJECT_DIRECTORY for \\Driver + NTSTATUS status = + DYN_NT_SYM(ZwOpenDirectoryObject)(&handle, DIRECTORY_ALL_ACCESS, &attr); + + if (!NT_SUCCESS(status)) { + DYN_NT_SYM(ZwClose)(handle); + return NULL; + } + + // Get OBJECT_DIRECTORY pointer from HANDLE + status = DYN_NT_SYM(ObReferenceObjectByHandle)( + handle, DIRECTORY_ALL_ACCESS, nullptr, KernelMode, &dir, nullptr); + + if (!NT_SUCCESS(status)) { + DYN_NT_SYM(ZwClose)(handle); + return NULL; + } + + const auto directory_object = POBJECT_DIRECTORY(dir); + DYN_NT_SYM(ExAcquirePushLockExclusiveEx)(&directory_object->Lock, 0); + + for (auto entry : directory_object->HashBuckets) { + if (!entry) + continue; + + while (entry && entry->Object) { + PDRIVER_OBJECT driver = (PDRIVER_OBJECT)entry->Object; + if (!driver) + continue; + + if (!DYN_NT_SYM(wcscmp)(driver->DriverExtension->ServiceKeyName.Buffer, + pwszDriverName)) { + DYN_NT_SYM(ExReleasePushLockExclusiveEx)(&directory_object->Lock, 0); + DYN_NT_SYM(ObfDereferenceObject)(dir); + DYN_NT_SYM(ZwClose)(handle); + return driver; + } + + entry = entry->ChainLink; + } + } + + DYN_NT_SYM(ExReleasePushLockExclusiveEx)(&directory_object->Lock, 0); + DYN_NT_SYM(ObfDereferenceObject)(dir); + DYN_NT_SYM(ZwClose)(handle); + return NULL; +} +} // namespace Driver + +namespace Process { +FORCEINLINE HANDLE GetPid(_In_ CONST WCHAR* pwszProcessName) { + u32 allocSize{}; + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemProcessInformation, NULL, allocSize, &allocSize); + + PSYSTEM_PROCESS_INFORMATION procInfo = + (PSYSTEM_PROCESS_INFORMATION)DYN_NT_SYM(ExAllocatePool)(NonPagedPool, + allocSize); + + const auto origPtr = procInfo; + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemProcessInformation, procInfo, allocSize, &allocSize); + + while (true) { + if (procInfo->ImageName.Buffer) { + if (!DYN_NT_SYM(_wcsicmp)(procInfo->ImageName.Buffer, pwszProcessName)) { + auto result = procInfo->ProcessId; + DYN_NT_SYM(ExFreePool)(origPtr); + return result; + } + } + + if (!procInfo->NextEntryOffset) + break; + + procInfo = reinterpret_cast( + reinterpret_cast(procInfo) + procInfo->NextEntryOffset); + } + + DYN_NT_SYM(ExFreePool)(origPtr); + return NULL; +} + +FORCEINLINE PVOID GetProcessBase(_In_ HANDLE pid) { + PEPROCESS lpProc; + if (NT_SUCCESS(DYN_NT_SYM(PsLookupProcessByProcessId)(pid, &lpProc))) { + PVOID lpBaseAddr = DYN_NT_SYM(PsGetProcessSectionBaseAddress)(lpProc); + DYN_NT_SYM(ObfDereferenceObject)(lpProc); + return lpBaseAddr; + } + return NULL; +} + +VOID TdCallbackExample(CONST SYSTEM_THREAD& ThreadInfo); +VOID PsCallbackExample(CONST SYSTEM_PROCESS_INFORMATION& PsInfo); + +using TdCallbackPtr = decltype(&TdCallbackExample); +using PsCallbackPtr = decltype(&PsCallbackExample); + +FORCEINLINE VOID ForEachProcess(_In_ PsCallbackPtr callback) { + u32 allocSize{}; + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemProcessInformation, NULL, allocSize, &allocSize); + + auto procInfo = reinterpret_cast( + DYN_NT_SYM(ExAllocatePool)(NonPagedPool, allocSize)); + + const auto origPtr = procInfo; + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemProcessInformation, procInfo, allocSize, &allocSize); + + while (true) { + for (auto idx = 0u; idx < procInfo->NumberOfThreads; ++idx) + callback(*procInfo); + + if (!procInfo->NextEntryOffset) + break; + + procInfo = reinterpret_cast( + reinterpret_cast(procInfo) + procInfo->NextEntryOffset); + } + DYN_NT_SYM(ExFreePool)(origPtr); +} + +FORCEINLINE VOID ForEachThread(_In_ HANDLE hPid, _In_ TdCallbackPtr lpCallback) { + ULONG nAllocSize{}; + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemProcessInformation, NULL, nAllocSize, &nAllocSize); + + PSYSTEM_PROCESS_INFORMATION lpstProcInfo = + (PSYSTEM_PROCESS_INFORMATION)DYN_NT_SYM(ExAllocatePool)(NonPagedPool, + nAllocSize); + + CONST PSYSTEM_PROCESS_INFORMATION lpstOrigPtr = lpstProcInfo; + DYN_NT_SYM(ZwQuerySystemInformation) + (SystemProcessInformation, lpstProcInfo, nAllocSize, &nAllocSize); + + while (true) { + if (lpstProcInfo->ProcessId == hPid) + for (UINT idx = 0u; idx < lpstProcInfo->NumberOfThreads; ++idx) + lpCallback(lpstProcInfo->Threads[idx]); + + if (!lpstProcInfo->NextEntryOffset) + break; + + lpstProcInfo = + (PSYSTEM_PROCESS_INFORMATION)((ULONG64)lpstProcInfo+ lpstProcInfo->NextEntryOffset)); + } + DYN_NT_SYM(ExFreePool)(lpstOrigPtr); +} + +FORCEINLINE PVOID GetModuleBase(_In_ HANDLE hPid, + _In_ CONST PWCHAR lpwszModuleName) { + PEPROCESS lpProc; + KAPC_STATE stApcState; + if (NT_SUCCESS(DYN_NT_SYM(PsLookupProcessByProcessId)(hPid, &lpProc))) { + DYN_NT_SYM(KeStackAttachProcess)(lpProc, &stApcState); + { + const auto ldrData = reinterpret_cast( + DYN_NT_SYM(PsGetProcessPeb)(lpProc)->LoaderData); + + auto currentEntry = ldrData->InMemoryOrderModuleList.Flink; + while (currentEntry != &ldrData->InMemoryOrderModuleList) { + const auto currentEntryData = reinterpret_cast( + reinterpret_cast(currentEntry) - sizeof LIST_ENTRY); + + const auto entryModuleName = currentEntryData->BaseDllName.Buffer; + if (!DYN_NT_SYM(_wcsicmp)(entryModuleName, lpwszModuleName)) { + DYN_NT_SYM(ObfDereferenceObject)(lpProc); + auto moduleBase = currentEntryData->DllBase; + + DYN_NT_SYM(KeUnstackDetachProcess)(&stApcState); + return moduleBase; + } + currentEntry = currentEntry->Flink; + } + } + DYN_NT_SYM(KeUnstackDetachProcess)(&stApcState); + DYN_NT_SYM(ObfDereferenceObject)(lpProc); + } + return NULL; +} +} // namespace Process + +namespace Signature { +inline auto Scan(void* base, u32 size, const char* pattern, const char* mask) + -> void* { + static const auto check_mask = [&](const char* base, const char* pattern, + const char* mask) -> bool { + for (; *mask; ++base, ++pattern, ++mask) + if (*mask == 'x' && *base != *pattern) + return false; + return true; + }; + + static const auto _strlen = [&](const char* str) -> unsigned { + const char* s; + for (s = str; *s; ++s) + ; + return (s - str); + }; + + size -= _strlen(mask); + for (auto i = 0; i <= size; ++i) { + void* addr = (void*)&(((char*)base)[i]); + if (check_mask((char*)addr, pattern, mask)) + return addr; + } + return nullptr; +} +} // namespace Signature +} // namespace KUtils