From b53ae15c82ea6b14c51ca411c627c27180e9b79f Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 26 Sep 2025 19:59:58 -0600 Subject: [PATCH] Force builtin lmgr stub and stub missing imports --- common.h | 2 + dll/kernel32.cpp | 9 +++++ loader.cpp | 14 +++++-- module_registry.cpp | 92 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 99 insertions(+), 18 deletions(-) diff --git a/common.h b/common.h index fc7bffc..44a7d3a 100644 --- a/common.h +++ b/common.h @@ -127,6 +127,8 @@ namespace wibo { void freeModule(HMODULE module); void *resolveFuncByName(HMODULE module, const char *funcName); void *resolveFuncByOrdinal(HMODULE module, uint16_t ordinal); + void *resolveMissingImportByName(const char *dllName, const char *funcName); + void *resolveMissingImportByOrdinal(const char *dllName, uint16_t ordinal); struct ResourceIdentifier { ResourceIdentifier() : isString(false), id(0) {} diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index a7434a5..a8ba573 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -261,6 +261,14 @@ namespace kernel32 { wibo::lastError = dwErrCode; } + BOOL WIN_FUNC IsBadReadPtr(const void *lp, uintptr_t ucb) { + DEBUG_LOG("STUB: IsBadReadPtr(ptr=%p, size=%zu)\n", lp, static_cast(ucb)); + if (!lp) { + return TRUE; + } + return FALSE; + } + BOOL WIN_FUNC Wow64DisableWow64FsRedirection(void **OldValue) { DEBUG_LOG("Wow64DisableWow64FsRedirection\n"); if (OldValue) { @@ -3387,6 +3395,7 @@ static void *resolveByName(const char *name) { // errhandlingapi.h if (strcmp(name, "GetLastError") == 0) return (void *) kernel32::GetLastError; if (strcmp(name, "SetLastError") == 0) return (void *) kernel32::SetLastError; + if (strcmp(name, "IsBadReadPtr") == 0) return (void *) kernel32::IsBadReadPtr; if (strcmp(name, "Wow64DisableWow64FsRedirection") == 0) return (void *) kernel32::Wow64DisableWow64FsRedirection; if (strcmp(name, "Wow64RevertWow64FsRedirection") == 0) return (void *) kernel32::Wow64RevertWow64FsRedirection; if (strcmp(name, "RaiseException") == 0) return (void *) kernel32::RaiseException; diff --git a/loader.cpp b/loader.cpp index fc09f61..ec1a531 100644 --- a/loader.cpp +++ b/loader.cpp @@ -290,14 +290,16 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) { // Import by ordinal uint16_t ordinal = lookup & 0xFFFF; DEBUG_LOG(" Ordinal: %d\n", ordinal); - void *func = resolveFuncByOrdinal(module, ordinal); + void *func = module ? resolveFuncByOrdinal(module, ordinal) + : resolveMissingImportByOrdinal(dllName, ordinal); DEBUG_LOG(" -> %p\n", func); *addressTable = reinterpret_cast(func); } else { // Import by name PEHintNameTableEntry *hintName = fromRVA(lookup); DEBUG_LOG(" Name: %s (IAT=%p)\n", hintName->name, addressTable); - void *func = resolveFuncByName(module, hintName->name); + void *func = module ? resolveFuncByName(module, hintName->name) + : resolveMissingImportByName(dllName, hintName->name); DEBUG_LOG(" -> %p\n", func); *addressTable = reinterpret_cast(func); } @@ -321,11 +323,15 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) { if (lookup & 0x80000000) { uint16_t ordinal = lookup & 0xFFFF; DEBUG_LOG(" Ordinal: %d (IAT=%p)\n", ordinal, addressTable); - *addressTable = reinterpret_cast(resolveFuncByOrdinal(module, ordinal)); + void *func = module ? resolveFuncByOrdinal(module, ordinal) + : resolveMissingImportByOrdinal(dllName, ordinal); + *addressTable = reinterpret_cast(func); } else { PEHintNameTableEntry *hintName = fromRVA(lookup); DEBUG_LOG(" Name: %s\n", hintName->name); - *addressTable = reinterpret_cast(resolveFuncByName(module, hintName->name)); + void *func = module ? resolveFuncByName(module, hintName->name) + : resolveMissingImportByName(dllName, hintName->name); + *addressTable = reinterpret_cast(func); } ++lookupTable; ++addressTable; diff --git a/module_registry.cpp b/module_registry.cpp index 9e90af3..2b8e9c5 100644 --- a/module_registry.cpp +++ b/module_registry.cpp @@ -3,6 +3,7 @@ #include "strutil.h" #include +#include #include #include #include @@ -63,16 +64,35 @@ struct PEExportDirectory { FOR_256_2(0, 3) FOR_256_2(1, 0) FOR_256_2(1, 1) FOR_256_2(1, 2) FOR_256_2(1, 3) FOR_256_2(2, 0) FOR_256_2(2, 1) \ FOR_256_2(2, 2) FOR_256_2(2, 3) FOR_256_2(3, 0) FOR_256_2(3, 1) FOR_256_2(3, 2) FOR_256_2(3, 3) +static constexpr size_t MAX_STUBS = 0x100; static int stubIndex = 0; -static char stubDlls[0x100][0x100]; -static char stubFuncNames[0x100][0x100]; +static std::array stubDlls; +static std::array stubFuncNames; +static std::unordered_map stubCache; + +static std::string makeStubKey(const char *dllName, const char *funcName) { + std::string key; + if (dllName) { + key.assign(dllName); + std::transform(key.begin(), key.end(), key.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + } + key.push_back(':'); + if (funcName) { + std::string func(funcName); + std::transform(func.begin(), func.end(), func.begin(), + [](unsigned char c) { return static_cast(std::tolower(c)); }); + key += func; + } + return key; +} static void stubBase(int index) { - printf("Unhandled function %s (%s)\n", stubFuncNames[index], stubDlls[index]); + printf("Unhandled function %s (%s)\n", stubFuncNames[index].c_str(), stubDlls[index].c_str()); exit(1); } -void (*stubFuncs[0x100])(void) = { +void (*stubFuncs[MAX_STUBS])(void) = { #define FOR_ITER(i) []() { stubBase(i); }, FOR_256 #undef FOR_ITER @@ -84,12 +104,23 @@ void (*stubFuncs[0x100])(void) = { void *resolveMissingFuncName(const char *dllName, const char *funcName) { DEBUG_LOG("Missing function: %s (%s)\n", dllName, funcName); - assert(stubIndex < 0x100); - assert(strlen(dllName) < 0x100); - assert(strlen(funcName) < 0x100); - strcpy(stubFuncNames[stubIndex], funcName); - strcpy(stubDlls[stubIndex], dllName); - return (void *)stubFuncs[stubIndex++]; + std::string key = makeStubKey(dllName, funcName); + auto existing = stubCache.find(key); + if (existing != stubCache.end()) { + return existing->second; + } + if (stubIndex >= static_cast(MAX_STUBS)) { + fprintf(stderr, + "Too many missing functions encountered (>%zu). Last failure: %s (%s)\n", + MAX_STUBS, funcName, dllName); + exit(1); + } + stubFuncNames[stubIndex] = funcName ? funcName : ""; + stubDlls[stubIndex] = dllName ? dllName : ""; + void *stub = (void *)stubFuncs[stubIndex]; + stubCache.emplace(std::move(key), stub); + stubIndex++; + return stub; } void *resolveMissingFuncOrdinal(const char *dllName, uint16_t ordinal) { @@ -113,6 +144,8 @@ struct ModuleRegistry { std::unordered_map onExitTables; std::unordered_map> builtinAliasLists; std::unordered_map builtinAliasMap; + std::unordered_set pinnedAliases; + std::unordered_set pinnedModules; }; ModuleRegistry ®istry() { @@ -322,6 +355,9 @@ void registerAlias(const std::string &alias, wibo::ModuleInfo *info) { reg.modulesByAlias[alias] = info; return; } + if (reg.pinnedAliases.count(alias)) { + return; + } // Prefer externally loaded modules over built-ins when both are present. if (it->second && it->second->module != nullptr && info->module == nullptr) { reg.modulesByAlias[alias] = info; @@ -345,15 +381,25 @@ void registerBuiltinModule(const wibo::Module *module) { reg.builtinAliasLists[module] = {}; auto &aliasList = reg.builtinAliasLists[module]; + const bool pinModule = (module == &lib_lmgr); + if (pinModule) { + reg.pinnedModules.insert(raw); + } for (size_t i = 0; module->names[i]; ++i) { std::string alias = normalizeAlias(module->names[i]); aliasList.push_back(alias); + if (pinModule) { + reg.pinnedAliases.insert(alias); + } registerAlias(alias, raw); reg.builtinAliasMap[alias] = raw; ParsedModuleName parsed = parseModuleName(module->names[i]); std::string baseAlias = normalizedBaseKey(parsed); if (baseAlias != alias) { aliasList.push_back(baseAlias); + if (pinModule) { + reg.pinnedAliases.insert(baseAlias); + } registerAlias(baseAlias, raw); reg.builtinAliasMap[baseAlias] = raw; } @@ -706,10 +752,13 @@ HMODULE loadModule(const char *dllName) { lastError = ERROR_SUCCESS; return existing; } - if (ModuleInfo *external = resolveAndLoadExternal()) { - DEBUG_LOG(" replaced builtin module %s with external copy\n", requested.c_str()); - lastError = ERROR_SUCCESS; - return external; + bool pinned = reg.pinnedModules.count(existing) != 0; + if (!pinned) { + if (ModuleInfo *external = resolveAndLoadExternal()) { + DEBUG_LOG(" replaced builtin module %s with external copy\n", requested.c_str()); + lastError = ERROR_SUCCESS; + return external; + } } lastError = ERROR_SUCCESS; DEBUG_LOG(" returning builtin module %s\n", existing->originalName.c_str()); @@ -828,6 +877,21 @@ void *resolveFuncByOrdinal(HMODULE module, uint16_t ordinal) { return resolveMissingFuncOrdinal(info->originalName.c_str(), ordinal); } +void *resolveMissingImportByName(const char *dllName, const char *funcName) { + const char *safeDll = dllName ? dllName : ""; + const char *safeFunc = funcName ? funcName : ""; + std::lock_guard lock(registry().mutex); + ensureInitialized(); + return resolveMissingFuncName(safeDll, safeFunc); +} + +void *resolveMissingImportByOrdinal(const char *dllName, uint16_t ordinal) { + const char *safeDll = dllName ? dllName : ""; + std::lock_guard lock(registry().mutex); + ensureInitialized(); + return resolveMissingFuncOrdinal(safeDll, ordinal); +} + Executable *executableFromModule(HMODULE module) { if (isMainModule(module)) { return mainModule;