windows内核驱动开发实用函数
//https://git.back.engineering/_xeroxz/kutils/src/branch/main/kutils.hpp
/*
* HEADER ONLY KERNEL UTIL LIBRARY - NO IMPORTS - NO STRINGS
*/
#pragma once
#include <intrin.h>
#include <ntifs.h>
using u64 = unsigned long long;
using u32 = unsigned long;
using u16 = unsigned short;
using u8 = unsigned char;
namespace hashstr {
template <unsigned... pack>
struct idx_list_t {};
template <typename idx_list_t, unsigned right>
struct append_t;
template <unsigned... left, unsigned right>
struct append_t<idx_list_t<left...>, right> {
typedef idx_list_t<left..., right> result_t;
};
template <unsigned N>
struct constr_idx_list {
typedef typename append_t<typename constr_idx_list<N - 1>::result_t,
N - 1>::result_t result_t;
};
template <>
struct constr_idx_list<0> {
typedef idx_list_t<> result_t;
};
template <typename T>
consteval T add(T first) {
return first;
}
template <typename T, typename... Args>
consteval T add(T first, Args... args) {
return first + add(args...);
}
template <typename T>
consteval T mul(T first) {
return first;
}
template <typename T, typename... Args>
consteval T mul(T first, Args... args) {
return first * mul(args...);
}
template <typename idx_list_t>
class hashstr_t;
template <int... idx>
struct hashstr_t<idx_list_t<idx...> > {
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<hashstr::constr_idx_list<sizeof(str) - 1>::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_SECTION_HEADER {
unsigned char Name[8];
union {
unsigned PhysicalAddress;
unsigned VirtualSize;
} Misc;
unsigned VirtualAddress;
unsigned SizeOfRawData;
unsigned PointerToRawData;
unsigned PointerToRelocations;
unsigned PointerToLinenumbers;
unsigned short NumberOfRelocations;
unsigned short NumberOfLinenumbers;
unsigned Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
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 {
/// <summary>
/// walk export directory of a module given its base and the hash of the export
/// string.
/// </summary>
/// <param name="lpDriverBase"></param>
/// <param name="nStrHash"></param>
/// <returns></returns>
FORCEINLINE PVOID GetDriverExportByHash(_In_ PVOID ModuleBase,
_In_ ULONG nStrHash) {
PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)ModuleBase;
PIMAGE_NT_HEADERS64 lpNtHeader =
(PIMAGE_NT_HEADERS64)(lpDosHeader->e_lfanew + (ULONG64)ModuleBase);
PIMAGE_EXPORT_DIRECTORY lpExportDir =
(PIMAGE_EXPORT_DIRECTORY)((ULONG64)ModuleBase +
lpNtHeader->OptionalHeader
.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
.VirtualAddress);
ULONG32* lpNameArr =
(ULONG32*)(lpExportDir->AddressOfNames + (ULONG64)ModuleBase);
ULONG32* lpFuncs =
(ULONG32*)(lpExportDir->AddressOfFunctions + (ULONG64)ModuleBase);
USHORT* lpOrdinals =
(USHORT*)(lpExportDir->AddressOfNameOrdinals + (ULONG64)ModuleBase);
for (auto nIdx = 0u; nIdx < lpExportDir->NumberOfFunctions; ++nIdx) {
if (!lpNameArr[nIdx] || !lpOrdinals[nIdx])
continue;
if (hashstr::hash((PCHAR)((ULONG64)ModuleBase + lpNameArr[nIdx])) ==
nStrHash)
return (PVOID)((ULONG64)ModuleBase + lpFuncs[lpOrdinals[nIdx]]);
}
return NULL;
}
/// <summary>
/// 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...
/// </summary>
/// <returns>returns the kernel base address...</returns>
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 (!GetDriverExportByHash((PVOID)nPage,
HSTRING("ExAllocatePoolWithTag")))
continue;
return (PVOID)nPage;
}
}
}
/// <summary>
/// Gets driver base address by the hash of the file name of the driver...
/// </summary>
/// <param name="dwHash">hash of the drivers file name...</param>
/// <returns></returns>
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;
}
/// <summary>
/// Get driver base given the module name of the driver... This function calls
/// GetDriverBaseByHash internally...
/// </summary>
/// <param name="pszDriverName">file name of the driver, this is not case
/// dependant...</param> <returns>returns a void pointer to the drivers
/// base...</returns>
FORCEINLINE PVOID GetDriverBase(_In_ CONST CHAR* pszDriverName) {
return GetDriverBaseByHash(hashstr::hash(pszDriverName));
}
/// <summary>
/// GetDriverExport via driver name and export routine name... this function
/// calls GetDriverExportByHash internally...
/// </summary>
/// <param name="pszDriverName">null terminated c-string given the module name
/// of the driver... example: "win32k.sys"</param> <param
/// name="pszRoutineName">the c-string name of the export...</param>
/// <returns>returns a linear virtual address to the export...</returns>
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 WCHAR* 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<PSYSTEM_PROCESS_INFORMATION>(
reinterpret_cast<u64>(procInfo) + procInfo->NextEntryOffset);
}
DYN_NT_SYM(ExFreePool)(origPtr);
return NULL;
}
FORCEINLINE PVOID GetProcessBase(_In_ HANDLE hPid) {
PEPROCESS lpProc;
if (NT_SUCCESS(DYN_NT_SYM(PsLookupProcessByProcessId)(hPid, &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 lpCallback) {
ULONG nAllocSize{};
DYN_NT_SYM(ZwQuerySystemInformation)
(SystemProcessInformation, NULL, nAllocSize, &nAllocSize);
auto procInfo = reinterpret_cast<PSYSTEM_PROCESS_INFORMATION>(
DYN_NT_SYM(ExAllocatePool)(NonPagedPool, nAllocSize));
const auto origPtr = procInfo;
DYN_NT_SYM(ZwQuerySystemInformation)
(SystemProcessInformation, procInfo, nAllocSize, &nAllocSize);
while (true) {
for (auto idx = 0u; idx < procInfo->NumberOfThreads; ++idx)
lpCallback(*procInfo);
if (!procInfo->NextEntryOffset)
break;
procInfo = reinterpret_cast<PSYSTEM_PROCESS_INFORMATION>(
reinterpret_cast<u64>(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 (INT 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 WCHAR* pwszModuleName) {
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<PPEB_LDR_DATA>(
DYN_NT_SYM(PsGetProcessPeb)(lpProc)->LoaderData);
auto currentEntry = ldrData->InMemoryOrderModuleList.Flink;
while (currentEntry != &ldrData->InMemoryOrderModuleList) {
const auto currentEntryData = reinterpret_cast<PLDR_DATA_TABLE_ENTRY>(
reinterpret_cast<u64>(currentEntry) - sizeof LIST_ENTRY);
const auto entryModuleName = currentEntryData->BaseDllName.Buffer;
if (!DYN_NT_SYM(_wcsicmp)(entryModuleName, pwszModuleName)) {
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