implement user mode catchable exceptions, refactor system status codes to use NTLSTATUS_ prefix, update build scripts to use shared literal macros for linker arguments, update named queue lifetime cleanup to include KeNamedQueueUnpublishHandle.

This commit is contained in:
maksw committed 2026-06-27 20:38:43 +02:00
1 parent 1f5477cf66
commit b7fcfce6f7
140 files changed
+7649 -3943

No files matched your search

+54 -54
View File
@@ -97,7 +97,7 @@ static size_t KiAlignPeSize(size_t value) {
// Implements the compute Required Image Size operation.
static KSTATUS KiComputeRequiredImageSize(const PE_HEADER* pe, size_t fileSize, size_t* outSize) {
if (!pe || !outSize) return STATUS_INVALID_PARAMETER;
if (!pe || !outSize) return NTLSTATUS_INVALID_PARAMETER;
const OPT_HEADER64* opt = &pe->OptionalHeader;
size_t required = KiAlignPeSize(opt->SizeOfImage);
@@ -113,19 +113,19 @@ static KSTATUS KiComputeRequiredImageSize(const PE_HEADER* pe, size_t fileSize,
if (raw > span) span = raw;
if (!span) continue;
if (va > (size_t)-1 - span) return STATUS_NO_MEMORY;
if (va > (size_t)-1 - span) return NTLSTATUS_NO_MEMORY;
size_t end = KiAlignPeSize(va + span);
if (end > required) required = end;
if (raw) {
size_t rawBase = (size_t)sec[i].PointerToRawData;
if (rawBase > fileSize || raw > fileSize - rawBase) return STATUS_FAILURE;
if (rawBase > fileSize || raw > fileSize - rawBase) return NTLSTATUS_FAILURE;
}
}
if (!required) return STATUS_FAILURE;
if (!required) return NTLSTATUS_FAILURE;
*outSize = required;
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
typedef struct {
@@ -178,7 +178,7 @@ static uint32_t gModuleCount = 0;
// Ensures a user image page is privately writable before the kernel patches it.
static KSTATUS KiEnsureUserImageWrite(PROCESS* process, bool user, uintptr_t address, size_t size) {
if (!user) return STATUS_SUCCESS;
if (!user) return NTLSTATUS_SUCCESS;
return MmVadMakeImageRangePrivate(process, (void*)address, size);
}
@@ -395,27 +395,27 @@ static uint64_t KiSectionPageProtection(const SECTION_HEADER* section, bool user
// Applies final page protections to a mapped PE image.
KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool user) {
if (!imageBase) return STATUS_INVALID_PARAMETER;
if (user && !process) return STATUS_INVALID_PARAMETER;
if (!imageBase) return NTLSTATUS_INVALID_PARAMETER;
if (user && !process) return NTLSTATUS_INVALID_PARAMETER;
size_t mappedSize = user ? LdrGetMappedImageSize(process, imageBase) : LdrGetImageSize(imageBase);
if (!mappedSize) return STATUS_FAILURE;
if (!mappedSize) return NTLSTATUS_FAILURE;
uint32_t peOffset = *(uint32_t *)(imageBase + 0x3C);
if ((size_t)peOffset > mappedSize || mappedSize - (size_t)peOffset < sizeof(uint32_t) + 20)
return STATUS_FAILURE;
return NTLSTATUS_FAILURE;
PE_HEADER* pe = (PE_HEADER *)(imageBase + peOffset);
if (pe->Signature != PE_SIGNATURE) return STATUS_FAILURE;
if (pe->Signature != PE_SIGNATURE) return NTLSTATUS_FAILURE;
size_t sectionTableOffset = (size_t)peOffset + 24u + (size_t)pe->SizeOfOptionalHeader;
size_t sectionTableSize = (size_t)pe->NumberOfSections * sizeof(SECTION_HEADER);
if (sectionTableOffset > mappedSize || sectionTableSize > mappedSize - sectionTableOffset)
return STATUS_FAILURE;
return NTLSTATUS_FAILURE;
size_t pageCount = (mappedSize + PAGE_SIZE - 1) / PAGE_SIZE;
uint64_t* pageProt = (uint64_t*)MmAllocatePoolTag(pageCount * sizeof(uint64_t), MM_POOL_TAG('i', 'p', 'r', 't'));
if (!pageProt) return STATUS_NO_MEMORY;
if (!pageProt) return NTLSTATUS_NO_MEMORY;
uint64_t headerProt = PAGE_PRESENT | (user ? PAGE_USER : 0) | PAGE_NX;
for (size_t i = 0; i < pageCount; ++i)
@@ -438,7 +438,7 @@ KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool us
}
if (secEnd < secBase) {
MmFreePool(pageProt);
return STATUS_NO_MEMORY;
return NTLSTATUS_NO_MEMORY;
}
if (secEnd > mapEnd) {
LdrDbg("LDR: protect clamping section %d end=%016llx to mapEnd=%016llx\n",
@@ -460,7 +460,7 @@ KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool us
}
size_t runStart = 0;
KSTATUS s = STATUS_SUCCESS;
KSTATUS s = NTLSTATUS_SUCCESS;
while (runStart < pageCount) {
uint64_t prot = pageProt[runStart];
size_t runEnd = runStart + 1;
@@ -501,10 +501,10 @@ static KSTATUS LdrApplyRelocationsForProcess(PROCESS* process, uintptr_t base, u
PE_HEADER* pe = (PE_HEADER *)(base + peOffset);
OPT_HEADER64* opt = &pe->OptionalHeader;
if (opt->NumberOfRvaAndSizes < 6) return STATUS_SUCCESS;
if (opt->NumberOfRvaAndSizes < 6) return NTLSTATUS_SUCCESS;
uint32_t relocRva = opt->DataDirectory[5].VirtualAddress;
uint32_t relocSize = opt->DataDirectory[5].Size;
if (!relocRva || !relocSize) return STATUS_SUCCESS;
if (!relocRva || !relocSize) return NTLSTATUS_SUCCESS;
BASE_RELOC* block = (BASE_RELOC *)(base + relocRva);
uintptr_t end = (uintptr_t)block + relocSize;
@@ -527,7 +527,7 @@ static KSTATUS LdrApplyRelocationsForProcess(PROCESS* process, uintptr_t base, u
}
block = (BASE_RELOC *)((uint8_t *)block + block->SizeOfBlock);
}
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Import resolution.
@@ -555,11 +555,11 @@ static KSTATUS LdrResolveImportsCommon(
OPT_HEADER64* opt = &pe->OptionalHeader;
if (opt->NumberOfRvaAndSizes < 2)
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
uint32_t impRva = opt->DataDirectory[1].VirtualAddress;
if (!impRva)
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
IMPORT_DESC* imp = (IMPORT_DESC *)(imageBase + impRva);
@@ -606,7 +606,7 @@ static KSTATUS LdrResolveImportsCommon(
"LdrResolveImports: Ordinal imports not supported! (%s)\n",
dllName
);
return STATUS_NOT_SUPPORTED;
return NTLSTATUS_NOT_SUPPORTED;
}
const char* funcName =
@@ -621,7 +621,7 @@ static KSTATUS LdrResolveImportsCommon(
dllName,
funcName
);
return STATUS_NOT_FOUND;
return NTLSTATUS_NOT_FOUND;
}
KSTATUS ws = KiEnsureUserImageWrite(process, process != (PROCESS*)0, (uintptr_t)thunk, sizeof(*thunk));
@@ -635,7 +635,7 @@ static KSTATUS LdrResolveImportsCommon(
imp++;
}
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Implements the ldr Resolve Imports operation.
@@ -661,7 +661,7 @@ KSTATUS LdrResolveImportsForProcess(PROCESS* process, uintptr_t imageBase) {
// Loads a user image from an open file through the image-section object model.
KSTATUS LdrLoadImageFileForProcess(PROCESS* process, FILE_OBJECT* file, uintptr_t* baseOut) {
if (!process || !file || !baseOut)
return STATUS_INVALID_PARAMETER;
return NTLSTATUS_INVALID_PARAMETER;
*baseOut = 0;
IMAGE_SECTION_OBJECT* section = (IMAGE_SECTION_OBJECT*)0;
@@ -690,7 +690,7 @@ KSTATUS LdrLoadImageFileForProcess(PROCESS* process, FILE_OBJECT* file, uintptr_
LdrDereferenceImageSection(section);
*baseOut = imageBase;
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Converts a process module entry into the public module ABI.
@@ -743,7 +743,7 @@ static PROCESS_MODULE* KiFindProcessModuleByBaseLocked(PROCESS* process, uintptr
// Registers a mapped process module or records a reference to an existing one.
static KSTATUS LdrRegisterProcessModule(PROCESS* process, const char* name, uintptr_t base, uint32_t loadFlags, uintptr_t* registeredBaseOut) {
if (!process || !name || !base || !loadFlags) return STATUS_INVALID_PARAMETER;
if (!process || !name || !base || !loadFlags) return NTLSTATUS_INVALID_PARAMETER;
if (registeredBaseOut) *registeredBaseOut = 0;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
@@ -752,12 +752,12 @@ static KSTATUS LdrRegisterProcessModule(PROCESS* process, const char* name, uint
KiReferenceProcessModule(existing, loadFlags);
if (registeredBaseOut) *registeredBaseOut = existing->Base;
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_ALREADY_EXISTS;
return NTLSTATUS_ALREADY_EXISTS;
}
if (process->ModuleCount >= PROCESS_MODULE_MAX) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_NO_MEMORY;
return NTLSTATUS_NO_MEMORY;
}
PROCESS_MODULE* mod = &process->Modules[process->ModuleCount++];
@@ -770,12 +770,12 @@ static KSTATUS LdrRegisterProcessModule(PROCESS* process, const char* name, uint
KiReferenceProcessModule(mod, loadFlags);
if (registeredBaseOut) *registeredBaseOut = mod->Base;
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Loads a DLL-like user module into a process and records the requested reference.
KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uint32_t loadFlags, uintptr_t* baseOut) {
if (!process || !filename || !loadFlags) return STATUS_INVALID_PARAMETER;
if (!process || !filename || !loadFlags) return NTLSTATUS_INVALID_PARAMETER;
filename = KiCanonicalModuleName(filename);
@@ -785,7 +785,7 @@ KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uint32_t
KiReferenceProcessModule(existing, loadFlags);
if (baseOut) *baseOut = existing->Base;
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
KeReleaseSpinlock(&process->ModuleLock, flags);
@@ -795,7 +795,7 @@ KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uint32_t
char relative[260];
size_t nameLen = strnlen(filename, sizeof(relative) - 8);
if (nameLen + 8 >= sizeof(relative))
return STATUS_BUFFER_TOO_SMALL;
return NTLSTATUS_BUFFER_TOO_SMALL;
memcpy(relative, "system/", 7);
memcpy(relative + 7, filename, nameLen);
relative[7 + nameLen] = '\0';
@@ -834,10 +834,10 @@ KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uint32_t
uintptr_t registeredBase = 0;
s = LdrRegisterProcessModule(process, filename, imageBase, loadFlags, &registeredBase);
if (s == STATUS_ALREADY_EXISTS) {
if (s == NTLSTATUS_ALREADY_EXISTS) {
KiFreeLoadedImageForProcess(process, imageBase, true);
imageBase = registeredBase;
s = STATUS_SUCCESS;
s = NTLSTATUS_SUCCESS;
}
if (!KSUCCESS(s)) {
KiFreeLoadedImageForProcess(process, imageBase, true);
@@ -847,12 +847,12 @@ KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uint32_t
LdrDbg("LDR: module registered pid=%u name=%s base=%016llx modules=%u\n",
process->ProcessId, filename, (unsigned long long)imageBase, process->ModuleCount);
if (baseOut) *baseOut = imageBase;
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Releases one public module load reference and unmaps the image when no references remain.
KSTATUS LdrUnloadModuleForProcess(PROCESS* process, uintptr_t imageBase) {
if (!process || !imageBase) return STATUS_INVALID_PARAMETER;
if (!process || !imageBase) return NTLSTATUS_INVALID_PARAMETER;
char name[PROCESS_MODULE_NAME_MAX];
uintptr_t base = 0;
@@ -862,11 +862,11 @@ KSTATUS LdrUnloadModuleForProcess(PROCESS* process, uintptr_t imageBase) {
PROCESS_MODULE* mod = KiFindProcessModuleByBaseLocked(process, imageBase);
if (!mod) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_NOT_FOUND;
return NTLSTATUS_NOT_FOUND;
}
if (mod->PublicRefCount == 0) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_INVALID_PARAMETER;
return NTLSTATUS_INVALID_PARAMETER;
}
mod->PublicRefCount--;
@@ -891,27 +891,27 @@ KSTATUS LdrUnloadModuleForProcess(PROCESS* process, uintptr_t imageBase) {
KiFreeLoadedImageForProcess(process, base, true);
}
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Queries one loaded process module by image base.
KSTATUS LdrQueryModuleForProcess(PROCESS* process, uintptr_t imageBase, SYS_MODULE_INFO* infoOut) {
if (!process || !imageBase || !infoOut) return STATUS_INVALID_PARAMETER;
if (!process || !imageBase || !infoOut) return NTLSTATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
PROCESS_MODULE* mod = KiFindProcessModuleByBaseLocked(process, imageBase);
if (!mod) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_NOT_FOUND;
return NTLSTATUS_NOT_FOUND;
}
KiFillProcessModuleInfo(mod, infoOut);
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Copies a bounded snapshot of the process module table.
KSTATUS LdrCopyProcessModuleInfo(PROCESS* process, SYS_MODULE_INFO* infoOut, size_t maxCount, size_t* countOut) {
if (!process || !countOut) return STATUS_INVALID_PARAMETER;
if (!process || !countOut) return NTLSTATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&process->ModuleLock);
size_t count = process->ModuleCount;
@@ -920,44 +920,44 @@ KSTATUS LdrCopyProcessModuleInfo(PROCESS* process, SYS_MODULE_INFO* infoOut, siz
if (toCopy > maxCount) toCopy = maxCount;
if (toCopy && !infoOut) {
KeReleaseSpinlock(&process->ModuleLock, flags);
return STATUS_INVALID_PARAMETER;
return NTLSTATUS_INVALID_PARAMETER;
}
for (size_t i = 0; i < toCopy; i++)
KiFillProcessModuleInfo(&process->Modules[i], &infoOut[i]);
KeReleaseSpinlock(&process->ModuleLock, flags);
return (maxCount < count) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
return (maxCount < count) ? NTLSTATUS_BUFFER_TOO_SMALL : NTLSTATUS_SUCCESS;
}
// Loads a boot/kernel PE image from a raw memory buffer into kernel space.
static KSTATUS KiLdrLoadKernelImageFromBuffer(const void* buffer, size_t size, uintptr_t* baseOut) {
if (!buffer || !size || !baseOut) return STATUS_INVALID_PARAMETER;
if (size < 0x40) return STATUS_FAILURE;
if (!buffer || !size || !baseOut) return NTLSTATUS_INVALID_PARAMETER;
if (size < 0x40) return NTLSTATUS_FAILURE;
const uint8_t* bytes = (const uint8_t*)buffer;
uint32_t peOffset = *(const uint32_t *)(bytes + 0x3C);
if ((size_t)peOffset > size || size - (size_t)peOffset < 24) return STATUS_FAILURE;
if ((size_t)peOffset > size || size - (size_t)peOffset < 24) return NTLSTATUS_FAILURE;
uint32_t signature = *(const uint32_t *)(bytes + peOffset);
if (signature != PE_SIGNATURE) return STATUS_FAILURE;
if (signature != PE_SIGNATURE) return NTLSTATUS_FAILURE;
uint16_t machine = *(const uint16_t *)(bytes + peOffset + 4);
uint16_t optionalSize = *(const uint16_t *)(bytes + peOffset + 20);
if (optionalSize < sizeof(OPT_HEADER64) ||
(size_t)peOffset + 24 + optionalSize > size) {
return STATUS_FAILURE;
return NTLSTATUS_FAILURE;
}
uint16_t optionalMagic = *(const uint16_t *)(bytes + peOffset + 24);
if (machine == IMAGE_FILE_MACHINE_I386 || optionalMagic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
DbgPrint("LdrLoadKernelImage: hard error: 32-bit PE images are not supported (machine=0x%X magic=0x%X)\n",
machine, optionalMagic);
return STATUS_NOT_SUPPORTED;
return NTLSTATUS_NOT_SUPPORTED;
}
if (machine != IMAGE_FILE_MACHINE_AMD64 || optionalMagic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
DbgPrint("LdrLoadKernelImage: unsupported PE image (machine=0x%X magic=0x%X)\n",
machine, optionalMagic);
return STATUS_NOT_SUPPORTED;
return NTLSTATUS_NOT_SUPPORTED;
}
PE_HEADER* pe = (PE_HEADER *)(bytes + peOffset);
@@ -976,7 +976,7 @@ static KSTATUS KiLdrLoadKernelImageFromBuffer(const void* buffer, size_t size, u
if (!mem) {
DbgPrint("LDR: kernel image allocation failed required=%llx\n",
(unsigned long long)imageSize);
return STATUS_NO_MEMORY;
return NTLSTATUS_NO_MEMORY;
}
memset(mem, 0, imageSize);
@@ -1018,7 +1018,7 @@ static KSTATUS KiLdrLoadKernelImageFromBuffer(const void* buffer, size_t size, u
}
*baseOut = (uintptr_t)mem;
return STATUS_SUCCESS;
return NTLSTATUS_SUCCESS;
}
// Loads a kernel image from a bootloader or driver raw buffer.