build.bat can create the image if missing, split the shell into native, posix and win32, clean up the build by moving executables into directories, the bootloader is no longer responsible to resolve drivers, fix ResolvePath, every process gets a copy of a module (dll), the child always inherits the cwd, fix function exports in posix, add unlink and exit to posix, add path translator to win32, first bugcheck.
This commit is contained in:
1 parent
0c7f461c6d
commit
f80e66ecde
38 files changed
+1620
-462
No files matched your search
+252
-36
@@ -3,6 +3,8 @@
|
||||
#include <string.h>
|
||||
#include <ldr_image.h>
|
||||
#include <boot_info.h>
|
||||
#include <ke_process.h>
|
||||
#include <io_file.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ke_debug.h>
|
||||
|
||||
@@ -109,39 +111,72 @@ typedef struct {
|
||||
typedef struct {
|
||||
char Name[32];
|
||||
uintptr_t Base;
|
||||
size_t Size;
|
||||
} MODULE_ENTRY;
|
||||
|
||||
static MODULE_ENTRY gModules[MAX_MODULES];
|
||||
static int gModuleCount = 0;
|
||||
static uint32_t gModuleCount = 0;
|
||||
|
||||
static uintptr_t FindModuleBaseInTable(const MODULE_ENTRY* modules, uint32_t count, const char* name) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (_stricmp(modules[i].Name, name) == 0) return modules[i].Base;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void RegisterModuleEntry(MODULE_ENTRY* entry, const char* name, uintptr_t base, size_t size) {
|
||||
strncpy(entry->Name, name, 31);
|
||||
entry->Name[31] = '\0';
|
||||
entry->Base = base;
|
||||
entry->Size = size;
|
||||
}
|
||||
|
||||
void LdrRegisterModulesFromBootInfo(const BOOT_INFO* bootInfo) {
|
||||
for (uint32_t i = 0; i < bootInfo->ModuleCount && i < MAX_MODULES; i++) {
|
||||
strncpy(gModules[gModuleCount].Name, bootInfo->Modules[i].Name, 31);
|
||||
gModules[gModuleCount].Base = bootInfo->Modules[i].VirtBase;
|
||||
gModuleCount++;
|
||||
for (uint32_t i = 0; i < bootInfo->ModuleCount && gModuleCount < MAX_MODULES; i++) {
|
||||
// Only register modules that have a virtual base (Kernel, HAL)
|
||||
if (bootInfo->Modules[i].VirtBase != 0) {
|
||||
RegisterModuleEntry(&gModules[gModuleCount],
|
||||
bootInfo->Modules[i].Name,
|
||||
bootInfo->Modules[i].VirtBase,
|
||||
bootInfo->Modules[i].ImageSize);
|
||||
gModuleCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LdrRegisterModule(const char* name, uintptr_t base) {
|
||||
if (gModuleCount < MAX_MODULES) {
|
||||
strncpy(gModules[gModuleCount].Name, name, 31);
|
||||
gModules[gModuleCount].Base = base;
|
||||
RegisterModuleEntry(&gModules[gModuleCount], name, base, 0);
|
||||
gModuleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
static uintptr_t FindModuleBase(const char* name) {
|
||||
for (int i = 0; i < gModuleCount; i++) {
|
||||
if (_stricmp(gModules[i].Name, name) == 0) return gModules[i].Base;
|
||||
static uintptr_t FindGlobalModuleBase(const char* name) {
|
||||
return FindModuleBaseInTable(gModules, gModuleCount, name);
|
||||
}
|
||||
|
||||
static uintptr_t FindProcessModuleBaseInTable(
|
||||
const PROCESS_MODULE* modules,
|
||||
uint32_t count,
|
||||
const char* name
|
||||
) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (_stricmp(modules[i].Name, name) == 0) {
|
||||
return modules[i].Base;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export lookup
|
||||
// ---------------------------------------------------------------------------
|
||||
void* LdrGetExport(const char* moduleName, const char* functionName) {
|
||||
uintptr_t base = FindModuleBase(moduleName);
|
||||
static uintptr_t FindProcessOrGlobalModuleBase(PROCESS* process, const char* name) {
|
||||
if (process) {
|
||||
uintptr_t base = FindProcessModuleBaseInTable(process->Modules, process->ModuleCount, name);
|
||||
if (base) return base;
|
||||
}
|
||||
return FindGlobalModuleBase(name);
|
||||
}
|
||||
|
||||
static void* GetExportAtBase(uintptr_t base, const char* functionName) {
|
||||
if (!base) return (void *)0;
|
||||
|
||||
uint32_t peOffset = *(uint32_t *)(base + 0x3C);
|
||||
@@ -169,6 +204,26 @@ void* LdrGetExport(const char* moduleName, const char* functionName) {
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Export lookup
|
||||
// ---------------------------------------------------------------------------
|
||||
void* LdrGetExport(const char* moduleName, const char* functionName) {
|
||||
uintptr_t base = FindGlobalModuleBase(moduleName);
|
||||
return GetExportAtBase(base, functionName);
|
||||
}
|
||||
|
||||
void* LdrGetExportForProcess(PROCESS* process, const char* moduleName, const char* functionName) {
|
||||
uintptr_t base = FindProcessOrGlobalModuleBase(process, moduleName);
|
||||
return GetExportAtBase(base, functionName);
|
||||
}
|
||||
|
||||
size_t LdrGetImageSize(uintptr_t base) {
|
||||
uint32_t peOffset = *(uint32_t *)(base + 0x3C);
|
||||
PE_HEADER* pe = (PE_HEADER *)(base + peOffset);
|
||||
if (pe->Signature != PE_SIGNATURE) return 0;
|
||||
return (size_t)pe->OptionalHeader.SizeOfImage;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Entry point lookup
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -216,43 +271,210 @@ static KSTATUS LdrApplyRelocations(uintptr_t base, uintptr_t delta) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Import resolution
|
||||
// ---------------------------------------------------------------------------
|
||||
KSTATUS LdrResolveImports(uintptr_t imageBase) {
|
||||
typedef void* (*EXPORT_LOOKUP_FN)(void* ctx, const char* moduleName, const char* functionName);
|
||||
|
||||
static void* GlobalExportLookup(void* ctx, const char* moduleName, const char* functionName) {
|
||||
(void)ctx;
|
||||
return LdrGetExport(moduleName, functionName);
|
||||
}
|
||||
|
||||
static void* ProcessExportLookup(void* ctx, const char* moduleName, const char* functionName) {
|
||||
return LdrGetExportForProcess((PROCESS*)ctx, moduleName, functionName);
|
||||
}
|
||||
|
||||
static KSTATUS LdrResolveImportsCommon(
|
||||
PROCESS* process,
|
||||
uintptr_t imageBase,
|
||||
EXPORT_LOOKUP_FN lookup,
|
||||
void* ctx
|
||||
) {
|
||||
uint32_t peOffset = *(uint32_t *)(imageBase + 0x3C);
|
||||
PE_HEADER* pe = (PE_HEADER *)(imageBase + peOffset);
|
||||
OPT_HEADER64* opt = &pe->OptionalHeader;
|
||||
|
||||
if (opt->NumberOfRvaAndSizes < 2) return STATUS_SUCCESS; // no imports
|
||||
if (opt->NumberOfRvaAndSizes < 2)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
uint32_t impRva = opt->DataDirectory[1].VirtualAddress;
|
||||
if (!impRva) return STATUS_SUCCESS;
|
||||
if (!impRva)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
IMPORT_DESC* imp = (IMPORT_DESC *)(imageBase + impRva);
|
||||
|
||||
while (imp->Name) {
|
||||
const char* dllName = (const char *)(imageBase + imp->Name);
|
||||
if (!_stricmp(dllName, "kernel32.dll") || !_stricmp(dllName, "user32.dll")
|
||||
|| !_stricmp(dllName, "ole32.dll") || !_stricmp(dllName, "winmm.dll"))
|
||||
|
||||
// Win32 compatibility remap
|
||||
if (!_stricmp(dllName, "kernel32.dll") ||
|
||||
!_stricmp(dllName, "user32.dll") ||
|
||||
!_stricmp(dllName, "ole32.dll") ||
|
||||
!_stricmp(dllName, "winmm.dll")) {
|
||||
dllName = "win32.dll";
|
||||
uint64_t* thunk = (uint64_t *)(imageBase + imp->FirstThunk);
|
||||
uint64_t* origThunk = (uint64_t *)(imageBase + (imp->OriginalFirstThunk
|
||||
? imp->OriginalFirstThunk
|
||||
: imp->FirstThunk));
|
||||
}
|
||||
|
||||
//
|
||||
// Ensure dependency is loaded into the process
|
||||
//
|
||||
if (process) {
|
||||
uintptr_t modBase =
|
||||
FindProcessOrGlobalModuleBase(process, dllName);
|
||||
|
||||
if (!modBase) {
|
||||
KSTATUS s =
|
||||
LdrLoadModuleForProcess(process, dllName, &modBase);
|
||||
|
||||
if (!KSUCCESS(s)) {
|
||||
DbgPrint(
|
||||
"LdrResolveImports: Failed to load dependency %s (%d)\n",
|
||||
dllName,
|
||||
s
|
||||
);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t* thunk =
|
||||
(uint64_t *)(imageBase + imp->FirstThunk);
|
||||
|
||||
uint64_t* origThunk =
|
||||
(uint64_t *)(imageBase +
|
||||
(imp->OriginalFirstThunk
|
||||
? imp->OriginalFirstThunk
|
||||
: imp->FirstThunk));
|
||||
|
||||
while (*origThunk) {
|
||||
if (*origThunk & (1ULL << 63)) {
|
||||
// Import by ordinal - not supported.
|
||||
DbgPrint("LdrResolveImports: Ordinal imports not supported! (%s)\n", dllName);
|
||||
DbgPrint(
|
||||
"LdrResolveImports: Ordinal imports not supported! (%s)\n",
|
||||
dllName
|
||||
);
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
const char* funcName = (const char *)(imageBase + (*origThunk & 0xFFFFFFFF) + 2);
|
||||
void* addr = LdrGetExport(dllName, funcName);
|
||||
|
||||
const char* funcName =
|
||||
(const char *)(imageBase +
|
||||
(*origThunk & 0xFFFFFFFF) + 2);
|
||||
|
||||
void* addr = lookup(ctx, dllName, funcName);
|
||||
|
||||
if (!addr) {
|
||||
DbgPrint("LdrResolveImports: Function not found! (%s)\n", funcName);
|
||||
DbgPrint(
|
||||
"LdrResolveImports: Function not found! (%s!%s)\n",
|
||||
dllName,
|
||||
funcName
|
||||
);
|
||||
return STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
*thunk = (uint64_t)addr;
|
||||
|
||||
thunk++;
|
||||
origThunk++;
|
||||
}
|
||||
|
||||
imp++;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KSTATUS LdrResolveImports(uintptr_t imageBase) {
|
||||
return LdrResolveImportsCommon(
|
||||
(PROCESS*)0,
|
||||
imageBase,
|
||||
GlobalExportLookup,
|
||||
(void*)0
|
||||
);
|
||||
}
|
||||
|
||||
KSTATUS LdrResolveImportsForProcess(PROCESS* process, uintptr_t imageBase) {
|
||||
return LdrResolveImportsCommon(
|
||||
process,
|
||||
imageBase,
|
||||
ProcessExportLookup,
|
||||
process
|
||||
);
|
||||
}
|
||||
|
||||
static KSTATUS LdrRegisterProcessModule(PROCESS* process, const char* name, uintptr_t base) {
|
||||
if (!process || !name || !base) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
for (uint32_t i = 0; i < process->ModuleCount; i++) {
|
||||
if (_stricmp(process->Modules[i].Name, name) == 0) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (process->ModuleCount >= PROCESS_MODULE_MAX) return STATUS_NO_MEMORY;
|
||||
|
||||
PROCESS_MODULE* mod = &process->Modules[process->ModuleCount++];
|
||||
strncpy(mod->Name, name, 31);
|
||||
mod->Name[31] = '\0';
|
||||
mod->Base = base;
|
||||
mod->Size = LdrGetImageSize(base);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
KSTATUS LdrLoadModuleForProcess(PROCESS* process, const char* filename, uintptr_t* baseOut) {
|
||||
if (!process || !filename) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
for (uint32_t i = 0; i < process->ModuleCount; i++) {
|
||||
if (_stricmp(process->Modules[i].Name, filename) == 0) {
|
||||
if (baseOut) *baseOut = process->Modules[i].Base;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
FILE_OBJECT* f;
|
||||
KSTATUS s = IoOpenFile(filename, &f);
|
||||
if (!KSUCCESS(s)) {
|
||||
char path[260];
|
||||
memcpy(path, "0:/system/", 10);
|
||||
memcpy(path + 10, filename, strnlen(filename, 248) + 1);
|
||||
path[259] = '\0';
|
||||
s = IoOpenFile(path, &f);
|
||||
if (!KSUCCESS(s)) {
|
||||
DbgPrint("LdrLoadModuleForProcess: Failed to open %s (%d)\n", filename, s);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t fileSize = IoGetFileSize(f);
|
||||
void* mem = MmAllocatePool((size_t)fileSize);
|
||||
if (!mem) {
|
||||
IoCloseFile(f);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
size_t got = 0;
|
||||
s = IoReadFile(f, mem, (size_t)fileSize, &got);
|
||||
IoCloseFile(f);
|
||||
if (!KSUCCESS(s)) {
|
||||
MmFreePool(mem);
|
||||
return s;
|
||||
}
|
||||
|
||||
uintptr_t imageBase = 0;
|
||||
s = LdrLoadImage(mem, (size_t)fileSize, &imageBase, true);
|
||||
MmFreePool(mem);
|
||||
if (!KSUCCESS(s)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
s = LdrResolveImportsForProcess(process, imageBase);
|
||||
if (!KSUCCESS(s)) {
|
||||
MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase));
|
||||
return s;
|
||||
}
|
||||
|
||||
s = LdrRegisterProcessModule(process, filename, imageBase);
|
||||
if (!KSUCCESS(s)) {
|
||||
MmFreeUserMemory((void*)imageBase, LdrGetImageSize(imageBase));
|
||||
return s;
|
||||
}
|
||||
|
||||
if (baseOut) *baseOut = imageBase;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -271,7 +493,6 @@ KSTATUS LdrLoadImage(const void* buffer, size_t size, uintptr_t* baseOut, bool u
|
||||
if (!mem) return STATUS_NO_MEMORY;
|
||||
memset(mem, 0, imageSize);
|
||||
|
||||
// Copy headers and sections
|
||||
memcpy(mem, buffer, opt->SizeOfHeaders);
|
||||
SECTION_HEADER* sec = (SECTION_HEADER *)((uint8_t *)&pe->OptionalHeader + pe->SizeOfOptionalHeader);
|
||||
for (int i = 0; i < pe->NumberOfSections; i++) {
|
||||
@@ -280,21 +501,16 @@ KSTATUS LdrLoadImage(const void* buffer, size_t size, uintptr_t* baseOut, bool u
|
||||
if (sec[i].SizeOfRawData) {
|
||||
memcpy(dst, src, sec[i].SizeOfRawData < sec[i].VirtualSize ? sec[i].SizeOfRawData : sec[i].VirtualSize);
|
||||
}
|
||||
|
||||
|
||||
uint64_t prot = PAGE_PRESENT | PAGE_WRITE | (user ? PAGE_USER : 0);
|
||||
MmSetPageProtect((uintptr_t)mem + sec[i].VirtualAddress, sec[i].VirtualSize, prot);
|
||||
}
|
||||
|
||||
// Apply Relocations
|
||||
uintptr_t delta = (uintptr_t)mem - opt->ImageBase;
|
||||
if (delta != 0) {
|
||||
LdrApplyRelocations((uintptr_t)mem, delta);
|
||||
}
|
||||
|
||||
// Resolve Imports
|
||||
KSTATUS status = LdrResolveImports((uintptr_t)mem);
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
*baseOut = (uintptr_t)mem;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
Reference in new issue
Block a user