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:
1 parent
1f5477cf66
commit
b7fcfce6f7
140 files changed
+7649
-3943
No files matched your search
+54
-54
@@ -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, ®isteredBase);
|
||||
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.
|
||||
|
||||
Reference in new issue
Block a user