diff --git a/CMakeLists.txt b/CMakeLists.txt index 56283d7..b737eba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,7 +80,7 @@ add_executable(wibo src/handles.cpp src/loader.cpp src/main.cpp - src/module_registry.cpp + src/modules.cpp src/processes.cpp src/resources.cpp src/strutil.cpp diff --git a/dll/advapi32.cpp b/dll/advapi32.cpp index fd509ba..b35db8a 100644 --- a/dll/advapi32.cpp +++ b/dll/advapi32.cpp @@ -1,9 +1,10 @@ +#include "modules.h" + #include "advapi32/processthreadsapi.h" #include "advapi32/securitybaseapi.h" #include "advapi32/winbase.h" #include "advapi32/wincrypt.h" #include "advapi32/winreg.h" -#include "common.h" #include @@ -105,7 +106,7 @@ void *resolveByName(const char *name) { } // namespace -wibo::Module lib_advapi32 = { +wibo::ModuleStub lib_advapi32 = { (const char *[]){ "advapi32", nullptr, diff --git a/dll/advapi32/processthreadsapi.cpp b/dll/advapi32/processthreadsapi.cpp index f488a07..b41050b 100644 --- a/dll/advapi32/processthreadsapi.cpp +++ b/dll/advapi32/processthreadsapi.cpp @@ -1,5 +1,7 @@ #include "processthreadsapi.h" +#include "common.h" +#include "context.h" #include "errors.h" #include "handles.h" #include "internal.h" diff --git a/dll/advapi32/securitybaseapi.cpp b/dll/advapi32/securitybaseapi.cpp index efcb2fc..00cc95e 100644 --- a/dll/advapi32/securitybaseapi.cpp +++ b/dll/advapi32/securitybaseapi.cpp @@ -1,5 +1,7 @@ #include "securitybaseapi.h" +#include "common.h" +#include "context.h" #include "errors.h" #include "handles.h" #include "internal.h" diff --git a/dll/advapi32/winbase.cpp b/dll/advapi32/winbase.cpp index da4b237..d53ba3b 100644 --- a/dll/advapi32/winbase.cpp +++ b/dll/advapi32/winbase.cpp @@ -1,5 +1,7 @@ #include "winbase.h" +#include "common.h" +#include "context.h" #include "errors.h" #include "internal.h" #include "strutil.h" diff --git a/dll/advapi32/wincrypt.cpp b/dll/advapi32/wincrypt.cpp index 6600599..9aac437 100644 --- a/dll/advapi32/wincrypt.cpp +++ b/dll/advapi32/wincrypt.cpp @@ -1,5 +1,7 @@ #include "wincrypt.h" +#include "common.h" +#include "context.h" #include "errors.h" #include diff --git a/dll/advapi32/winreg.cpp b/dll/advapi32/winreg.cpp index 946222a..47b3d9a 100644 --- a/dll/advapi32/winreg.cpp +++ b/dll/advapi32/winreg.cpp @@ -1,5 +1,7 @@ #include "winreg.h" +#include "common.h" +#include "context.h" #include "errors.h" #include "handles.h" #include "strutil.h" diff --git a/dll/bcrypt.cpp b/dll/bcrypt.cpp index a45d424..a743f76 100644 --- a/dll/bcrypt.cpp +++ b/dll/bcrypt.cpp @@ -1,5 +1,7 @@ #include "common.h" +#include "context.h" #include "errors.h" +#include "modules.h" #include #include @@ -72,7 +74,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_bcrypt = { +wibo::ModuleStub lib_bcrypt = { (const char *[]){ "bcrypt", nullptr, diff --git a/dll/crt.cpp b/dll/crt.cpp index af5d7f9..af99059 100644 --- a/dll/crt.cpp +++ b/dll/crt.cpp @@ -1,4 +1,6 @@ #include "common.h" +#include "context.h" +#include "modules.h" #include #include @@ -436,7 +438,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_crt = { +wibo::ModuleStub lib_crt = { (const char *[]){ "api-ms-win-crt-heap-l1-1-0", "api-ms-win-crt-locale-l1-1-0", diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 8063c08..63cd8c9 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -1,4 +1,4 @@ -#include "common.h" +#include "modules.h" #include "kernel32/debugapi.h" #include "kernel32/errhandlingapi.h" @@ -600,7 +600,7 @@ void *resolveByName(const char *name) { } // namespace -wibo::Module lib_kernel32 = { +wibo::ModuleStub lib_kernel32 = { (const char *[]){ "kernel32", nullptr, diff --git a/dll/kernel32/debugapi.cpp b/dll/kernel32/debugapi.cpp index 03cf282..90b99bf 100644 --- a/dll/kernel32/debugapi.cpp +++ b/dll/kernel32/debugapi.cpp @@ -1,5 +1,7 @@ #include "debugapi.h" + #include "common.h" +#include "context.h" #include "errors.h" namespace kernel32 { diff --git a/dll/kernel32/errhandlingapi.cpp b/dll/kernel32/errhandlingapi.cpp index 2b0ad5a..c0a7f7c 100644 --- a/dll/kernel32/errhandlingapi.cpp +++ b/dll/kernel32/errhandlingapi.cpp @@ -1,5 +1,7 @@ #include "errhandlingapi.h" + #include "common.h" +#include "context.h" #include "errors.h" namespace { diff --git a/dll/kernel32/fibersapi.cpp b/dll/kernel32/fibersapi.cpp index edecb76..f4aae99 100644 --- a/dll/kernel32/fibersapi.cpp +++ b/dll/kernel32/fibersapi.cpp @@ -1,5 +1,7 @@ #include "fibersapi.h" + #include "common.h" +#include "context.h" #include "errors.h" namespace { diff --git a/dll/kernel32/fileapi.cpp b/dll/kernel32/fileapi.cpp index dd7603d..aef8678 100644 --- a/dll/kernel32/fileapi.cpp +++ b/dll/kernel32/fileapi.cpp @@ -2,6 +2,7 @@ #include "access.h" #include "common.h" +#include "context.h" #include "errors.h" #include "files.h" #include "handles.h" diff --git a/dll/kernel32/handleapi.cpp b/dll/kernel32/handleapi.cpp index 512e144..a70212c 100644 --- a/dll/kernel32/handleapi.cpp +++ b/dll/kernel32/handleapi.cpp @@ -1,5 +1,6 @@ #include "handleapi.h" +#include "context.h" #include "errors.h" #include "handles.h" #include "internal.h" diff --git a/dll/kernel32/heapapi.cpp b/dll/kernel32/heapapi.cpp index ef74348..d50e4f0 100644 --- a/dll/kernel32/heapapi.cpp +++ b/dll/kernel32/heapapi.cpp @@ -1,5 +1,7 @@ #include "heapapi.h" + #include "common.h" +#include "context.h" #include "errors.h" #include "handles.h" #include "internal.h" diff --git a/dll/kernel32/interlockedapi.cpp b/dll/kernel32/interlockedapi.cpp index 16b6887..9e06ded 100644 --- a/dll/kernel32/interlockedapi.cpp +++ b/dll/kernel32/interlockedapi.cpp @@ -1,5 +1,7 @@ #include "interlockedapi.h" + #include "common.h" +#include "context.h" #include diff --git a/dll/kernel32/ioapiset.cpp b/dll/kernel32/ioapiset.cpp index 43f1403..0f0d258 100644 --- a/dll/kernel32/ioapiset.cpp +++ b/dll/kernel32/ioapiset.cpp @@ -1,5 +1,6 @@ #include "ioapiset.h" +#include "context.h" #include "errors.h" #include "synchapi.h" diff --git a/dll/kernel32/libloaderapi.cpp b/dll/kernel32/libloaderapi.cpp index b2d8dab..86f6c5f 100644 --- a/dll/kernel32/libloaderapi.cpp +++ b/dll/kernel32/libloaderapi.cpp @@ -1,7 +1,9 @@ #include "libloaderapi.h" +#include "context.h" #include "errors.h" #include "files.h" +#include "modules.h" #include "resources.h" #include "strutil.h" diff --git a/dll/kernel32/memoryapi.cpp b/dll/kernel32/memoryapi.cpp index 7dd9bf1..3560cb9 100644 --- a/dll/kernel32/memoryapi.cpp +++ b/dll/kernel32/memoryapi.cpp @@ -1,8 +1,11 @@ #include "memoryapi.h" + #include "common.h" +#include "context.h" #include "errors.h" #include "handles.h" #include "internal.h" +#include "modules.h" #include "strutil.h" #include diff --git a/dll/kernel32/namedpipeapi.cpp b/dll/kernel32/namedpipeapi.cpp index f936c56..fe190f0 100644 --- a/dll/kernel32/namedpipeapi.cpp +++ b/dll/kernel32/namedpipeapi.cpp @@ -1,14 +1,11 @@ #include "namedpipeapi.h" #include "common.h" +#include "context.h" #include "errors.h" -#include "fileapi.h" -#include "files.h" #include "handles.h" #include "internal.h" -#include -#include #include #include diff --git a/dll/kernel32/processenv.cpp b/dll/kernel32/processenv.cpp index 4b89532..81a4178 100644 --- a/dll/kernel32/processenv.cpp +++ b/dll/kernel32/processenv.cpp @@ -1,5 +1,6 @@ #include "processenv.h" +#include "context.h" #include "errors.h" #include "files.h" #include "internal.h" diff --git a/dll/kernel32/processthreadsapi.cpp b/dll/kernel32/processthreadsapi.cpp index a8c2bbf..cf680e8 100644 --- a/dll/kernel32/processthreadsapi.cpp +++ b/dll/kernel32/processthreadsapi.cpp @@ -1,9 +1,12 @@ #include "processthreadsapi.h" + #include "common.h" +#include "context.h" #include "errors.h" #include "files.h" #include "handles.h" #include "internal.h" +#include "modules.h" #include "processes.h" #include "strutil.h" #include "timeutil.h" diff --git a/dll/kernel32/profileapi.cpp b/dll/kernel32/profileapi.cpp index 54ba7e8..21744c1 100644 --- a/dll/kernel32/profileapi.cpp +++ b/dll/kernel32/profileapi.cpp @@ -1,5 +1,7 @@ #include "profileapi.h" + #include "common.h" +#include "context.h" #include "errors.h" namespace kernel32 { diff --git a/dll/kernel32/stringapiset.cpp b/dll/kernel32/stringapiset.cpp index 74038ff..d5562b3 100644 --- a/dll/kernel32/stringapiset.cpp +++ b/dll/kernel32/stringapiset.cpp @@ -1,5 +1,6 @@ #include "stringapiset.h" +#include "context.h" #include "errors.h" #include "strutil.h" diff --git a/dll/kernel32/synchapi.cpp b/dll/kernel32/synchapi.cpp index 40fbd5c..db21ea8 100644 --- a/dll/kernel32/synchapi.cpp +++ b/dll/kernel32/synchapi.cpp @@ -1,6 +1,7 @@ #include "synchapi.h" #include "common.h" +#include "context.h" #include "errors.h" #include "handles.h" #include "internal.h" diff --git a/dll/kernel32/sysinfoapi.cpp b/dll/kernel32/sysinfoapi.cpp index 2fdf2f0..a055302 100644 --- a/dll/kernel32/sysinfoapi.cpp +++ b/dll/kernel32/sysinfoapi.cpp @@ -1,5 +1,7 @@ #include "sysinfoapi.h" + #include "common.h" +#include "context.h" #include "errors.h" #include "timeutil.h" diff --git a/dll/kernel32/timezoneapi.cpp b/dll/kernel32/timezoneapi.cpp index a2a06b2..f461b77 100644 --- a/dll/kernel32/timezoneapi.cpp +++ b/dll/kernel32/timezoneapi.cpp @@ -1,5 +1,6 @@ #include "timezoneapi.h" +#include "context.h" #include "errors.h" #include "timeutil.h" diff --git a/dll/kernel32/winbase.cpp b/dll/kernel32/winbase.cpp index 2f82dad..2aa6510 100644 --- a/dll/kernel32/winbase.cpp +++ b/dll/kernel32/winbase.cpp @@ -1,9 +1,10 @@ #include "winbase.h" +#include "context.h" #include "errors.h" #include "files.h" -#include "handles.h" #include "internal.h" +#include "modules.h" #include "strutil.h" #include @@ -13,16 +14,15 @@ #include #include #include -#include #include #include #include #include -#include -#include #include #include #include +#include +#include namespace { @@ -317,6 +317,7 @@ ActivationContext *currentActivationContext() { } } // namespace + void ensureDefaultActivationContext() { static std::once_flag initFlag; std::call_once(initFlag, [] { @@ -331,48 +332,10 @@ void ensureDefaultActivationContext() { entry.dllData.PathSegmentOffset = 0; ctx->dllRedirections.emplace_back(std::move(entry)); }; - addDll("msvcr80.dll"); - addDll("msvcp80.dll"); - addDll("mfc80.dll"); - addDll("mfc80u.dll"); - addDll("msvcrt.dll"); - }); -} - -constexpr const char kVc80ManifestName[] = "Microsoft.VC80.CRT.manifest"; - -void ensureVc80ManifestOnDisk(const DllRedirectionEntry &entry) { - static std::once_flag manifestOnce; - if (entry.nameLower != "msvcr80.dll") { - return; - } - std::call_once(manifestOnce, [] { - wibo::ModuleInfo *module = wibo::findLoadedModule("msvcr80.dll"); - if (!module || module->resolvedPath.empty()) { - DEBUG_LOG("VC80 manifest: module not yet loaded, skipping creation\n"); - return; - } - std::filesystem::path manifestPath = module->resolvedPath.parent_path() / kVc80ManifestName; - std::error_code ec; - if (std::filesystem::exists(manifestPath, ec)) { - return; - } - constexpr const char kManifestContents[] = - "\n" - "\n" - " \n" - " \n" - " \n" - " \n" - "\n"; - std::ofstream out(manifestPath, std::ios::binary); - if (!out) { - DEBUG_LOG("VC80 manifest: failed to create %s\n", manifestPath.string().c_str()); - return; - } - out.write(kManifestContents, sizeof(kManifestContents) - 1); - if (!out) { - DEBUG_LOG("VC80 manifest: write error for %s\n", manifestPath.string().c_str()); + for (const auto &[key, module] : wibo::allLoadedModules()) { + if (!module->moduleStub) { + addDll(module->normalizedName); + } } }); } @@ -631,7 +594,7 @@ BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName) { } BOOL WIN_FUNC FindActCtxSectionStringA(DWORD dwFlags, const GUID *lpExtensionGuid, ULONG ulSectionId, - LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData) { + LPCSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData) { DEBUG_LOG("FindActCtxSectionStringA(%#x, %p, %u, %s, %p)\n", dwFlags, lpExtensionGuid, ulSectionId, lpStringToFind ? lpStringToFind : "", ReturnedData); std::vector wideStorage; @@ -643,15 +606,15 @@ BOOL WIN_FUNC FindActCtxSectionStringA(DWORD dwFlags, const GUID *lpExtensionGui } } const uint16_t *widePtr = wideStorage.empty() ? nullptr : wideStorage.data(); - return FindActCtxSectionStringW(dwFlags, lpExtensionGuid, ulSectionId, - reinterpret_cast(widePtr), ReturnedData); + return FindActCtxSectionStringW(dwFlags, lpExtensionGuid, ulSectionId, reinterpret_cast(widePtr), + ReturnedData); } BOOL WIN_FUNC FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid, ULONG ulSectionId, - LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData) { + LPCWSTR lpStringToFind, PACTCTX_SECTION_KEYED_DATA ReturnedData) { std::string lookup = lpStringToFind ? wideStringToString(lpStringToFind) : std::string(); - DEBUG_LOG("FindActCtxSectionStringW(%#x, %p, %u, %s, %p)\n", dwFlags, lpExtensionGuid, ulSectionId, - lookup.c_str(), ReturnedData); + DEBUG_LOG("FindActCtxSectionStringW(%#x, %p, %u, %s, %p)\n", dwFlags, lpExtensionGuid, ulSectionId, lookup.c_str(), + ReturnedData); if (lpExtensionGuid) { wibo::lastError = ERROR_INVALID_PARAMETER; @@ -701,8 +664,6 @@ BOOL WIN_FUNC FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGui return FALSE; } - ensureVc80ManifestOnDisk(*matchedEntry); - ReturnedData->lpData = const_cast(&matchedEntry->dllData); ReturnedData->ulLength = matchedEntry->dllData.Size; ReturnedData->lpSectionBase = const_cast(&matchedEntry->dllData); diff --git a/dll/kernel32/wincon.cpp b/dll/kernel32/wincon.cpp index fa75e63..702b52f 100644 --- a/dll/kernel32/wincon.cpp +++ b/dll/kernel32/wincon.cpp @@ -1,11 +1,11 @@ #include "wincon.h" +#include "context.h" #include "errors.h" #include "files.h" +#include "handles.h" #include "strutil.h" -#include - namespace kernel32 { BOOL WIN_FUNC GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode) { @@ -83,7 +83,7 @@ BOOL WIN_FUNC WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumb auto file = wibo::handles().getAs(hConsoleOutput); if (file->fd == STDOUT_FILENO || file->fd == STDERR_FILENO) { - auto str = wideStringToString(static_cast(lpBuffer), nNumberOfCharsToWrite); + auto str = wideStringToString(static_cast(lpBuffer), static_cast(nNumberOfCharsToWrite)); dprintf(file->fd, "%s", str.c_str()); if (lpNumberOfCharsWritten) { *lpNumberOfCharsWritten = nNumberOfCharsToWrite; diff --git a/dll/kernel32/winnls.cpp b/dll/kernel32/winnls.cpp index 209933a..8332164 100644 --- a/dll/kernel32/winnls.cpp +++ b/dll/kernel32/winnls.cpp @@ -1,5 +1,6 @@ #include "winnls.h" +#include "context.h" #include "errors.h" #include "strutil.h" diff --git a/dll/kernel32/winnt.cpp b/dll/kernel32/winnt.cpp index ce3f665..1ba1861 100644 --- a/dll/kernel32/winnt.cpp +++ b/dll/kernel32/winnt.cpp @@ -1,6 +1,7 @@ #include "winnt.h" #include "common.h" +#include "context.h" namespace kernel32 { diff --git a/dll/kernel32/wow64apiset.cpp b/dll/kernel32/wow64apiset.cpp index 7e1534f..90568a6 100644 --- a/dll/kernel32/wow64apiset.cpp +++ b/dll/kernel32/wow64apiset.cpp @@ -1,8 +1,10 @@ #include "wow64apiset.h" + #include "common.h" -#include "kernel32/internal.h" +#include "context.h" #include "errors.h" #include "handles.h" +#include "internal.h" namespace kernel32 { diff --git a/dll/lmgr.cpp b/dll/lmgr.cpp index 9a6d4f2..9842a7a 100644 --- a/dll/lmgr.cpp +++ b/dll/lmgr.cpp @@ -1,4 +1,6 @@ #include "common.h" +#include "context.h" +#include "modules.h" namespace lmgr { int WIN_ENTRY lp_checkout(int a, int b, const char* c, const char* d, int e, const char* f, int* out) { @@ -25,7 +27,7 @@ static void *resolveByOrdinal(uint16_t ordinal) { return 0; } -wibo::Module lib_lmgr = { +wibo::ModuleStub lib_lmgr = { (const char *[]){ "lmgr11", "lmgr326b", diff --git a/dll/mscoree.cpp b/dll/mscoree.cpp index 98b290b..46016f6 100644 --- a/dll/mscoree.cpp +++ b/dll/mscoree.cpp @@ -1,4 +1,6 @@ #include "common.h" +#include "context.h" +#include "modules.h" namespace mscoree { @@ -16,7 +18,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_mscoree = { +wibo::ModuleStub lib_mscoree = { (const char *[]){ "mscoree", nullptr, diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index df203af..69ad602 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -1,46 +1,50 @@ #include "common.h" +#include "context.h" +#include "files.h" #include "kernel32/internal.h" +#include "modules.h" +#include "processes.h" +#include "strutil.h" + #include #include +#include #include #include #include #include -#include -#include +#include #include #include #include #include -#include #include +#include #include #include +#include #include +#include +#include #include #include #include -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include +#include +#include + #ifndef O_BINARY #define O_BINARY 0 #endif -#include "files.h" -#include "processes.h" -#include "strutil.h" typedef void (*_PVFV)(); typedef int (*_PIFV)(); @@ -3218,7 +3222,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_msvcrt = { +wibo::ModuleStub lib_msvcrt = { (const char *[]){ "msvcrt", "msvcrt40", diff --git a/dll/ntdll.cpp b/dll/ntdll.cpp index a5b256d..fb09740 100644 --- a/dll/ntdll.cpp +++ b/dll/ntdll.cpp @@ -1,9 +1,11 @@ #include "common.h" -#include "kernel32/internal.h" +#include "context.h" #include "errors.h" #include "files.h" #include "handles.h" +#include "kernel32/internal.h" #include "kernel32/processthreadsapi.h" +#include "modules.h" #include "processes.h" #include "strutil.h" @@ -408,7 +410,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_ntdll = { +wibo::ModuleStub lib_ntdll = { (const char *[]){ "ntdll", nullptr, diff --git a/dll/ole32.cpp b/dll/ole32.cpp index 3b1558f..7866618 100644 --- a/dll/ole32.cpp +++ b/dll/ole32.cpp @@ -1,4 +1,6 @@ #include "common.h" +#include "context.h" +#include "modules.h" namespace ole32 { int WIN_FUNC CoInitialize(void *pvReserved) { @@ -37,7 +39,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_ole32 = { +wibo::ModuleStub lib_ole32 = { (const char *[]){ "ole32", nullptr, diff --git a/dll/psapi.cpp b/dll/psapi.cpp deleted file mode 100644 index b1003c1..0000000 --- a/dll/psapi.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "common.h" -#include "errors.h" -#include "handles.h" - -namespace psapi { -BOOL WIN_FUNC EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, DWORD *lpcbNeeded) { - HOST_CONTEXT_GUARD(); - DEBUG_LOG("EnumProcessModules(%p, %p, %u, %p)\n", hProcess, lphModule, cb, lpcbNeeded); - - bool recognizedHandle = false; - if (hProcess == (HANDLE)0xFFFFFFFF) { - recognizedHandle = true; - } else { - auto data = handles::dataFromHandle(hProcess, false); - recognizedHandle = (data.type == handles::TYPE_PROCESS); - } - if (!recognizedHandle) { - wibo::lastError = ERROR_ACCESS_DENIED; - return FALSE; - } - - HMODULE currentModule = wibo::mainModule ? wibo::mainModule->handle : nullptr; - DWORD required = currentModule ? sizeof(HMODULE) : 0; - if (lpcbNeeded) { - *lpcbNeeded = required; - } - - if (required == 0) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - - if (!lphModule || cb < required) { - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - - lphModule[0] = currentModule; - wibo::lastError = ERROR_SUCCESS; - return TRUE; -} -} // namespace psapi - -static void *resolveByName(const char *name) { - if (strcmp(name, "EnumProcessModules") == 0) - return (void *)psapi::EnumProcessModules; - if (strcmp(name, "K32EnumProcessModules") == 0) - return (void *)psapi::EnumProcessModules; - return nullptr; -} - -static void *resolveByOrdinal(uint16_t ordinal) { - switch (ordinal) { - case 4: // EnumProcessModules - return (void *)psapi::EnumProcessModules; - default: - return nullptr; - } -} - -wibo::Module lib_psapi = { - (const char *[]){ - "psapi", - nullptr, - }, - resolveByName, - resolveByOrdinal, -}; diff --git a/dll/rpcrt4.cpp b/dll/rpcrt4.cpp index 127d9f6..beb20e1 100644 --- a/dll/rpcrt4.cpp +++ b/dll/rpcrt4.cpp @@ -1,4 +1,6 @@ #include "common.h" +#include "context.h" +#include "modules.h" #include #include @@ -283,7 +285,7 @@ void *resolveByName(const char *name) { } // namespace -wibo::Module lib_rpcrt4 = { +wibo::ModuleStub lib_rpcrt4 = { (const char *[]){"rpcrt4", nullptr}, resolveByName, nullptr, diff --git a/dll/user32.cpp b/dll/user32.cpp index 6fa80d8..af50abf 100644 --- a/dll/user32.cpp +++ b/dll/user32.cpp @@ -1,6 +1,8 @@ #include "common.h" +#include "context.h" #include "errors.h" -#include "strutil.h" +#include "modules.h" +#include "resources.h" namespace user32 { constexpr uint32_t RT_STRING_ID = 6; @@ -186,7 +188,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_user32 = { +wibo::ModuleStub lib_user32 = { (const char *[]){ "user32", nullptr, diff --git a/dll/vcruntime.cpp b/dll/vcruntime.cpp index 5ca6078..9e45c0a 100644 --- a/dll/vcruntime.cpp +++ b/dll/vcruntime.cpp @@ -1,4 +1,6 @@ #include "common.h" +#include "context.h" +#include "modules.h" namespace vcruntime { @@ -36,7 +38,7 @@ static void *resolveByName(const char *name) { return nullptr; } -wibo::Module lib_vcruntime = { +wibo::ModuleStub lib_vcruntime = { (const char *[]){ "vcruntime140", nullptr, diff --git a/dll/version.cpp b/dll/version.cpp index 8641325..41248d8 100644 --- a/dll/version.cpp +++ b/dll/version.cpp @@ -1,6 +1,8 @@ #include "common.h" +#include "context.h" #include "errors.h" #include "files.h" +#include "modules.h" #include "resources.h" #include "strutil.h" @@ -14,13 +16,9 @@ namespace { constexpr uint32_t RT_VERSION = 16; -static uint16_t readU16(const uint8_t *ptr) { - return static_cast(ptr[0] | (ptr[1] << 8)); -} +static uint16_t readU16(const uint8_t *ptr) { return static_cast(ptr[0] | (ptr[1] << 8)); } -static size_t align4(size_t offset) { - return (offset + 3u) & ~static_cast(3u); -} +static size_t align4(size_t offset) { return (offset + 3u) & ~static_cast(3u); } static std::string narrowKey(const std::u16string &key) { std::string result; @@ -70,7 +68,8 @@ static bool parseVersionBlock(const uint8_t *block, size_t available, VersionBlo cursor = block + sizeof(uint16_t) * 3 + (out.key.size() + 1) * sizeof(uint16_t); if (cursor > end) { - DEBUG_LOG("key cursor beyond block: cursor=%zu end=%zu\n", static_cast(cursor - block), static_cast(end - block)); + DEBUG_LOG("key cursor beyond block: cursor=%zu end=%zu\n", static_cast(cursor - block), + static_cast(end - block)); return false; } @@ -78,8 +77,8 @@ static bool parseVersionBlock(const uint8_t *block, size_t available, VersionBlo uint32_t valueBytes = 0; if (valueLength) { - valueBytes = type == 1 ? static_cast(valueLength) * sizeof(uint16_t) - : static_cast(valueLength); + valueBytes = + type == 1 ? static_cast(valueLength) * sizeof(uint16_t) : static_cast(valueLength); if (cursor + valueBytes > end) { DEBUG_LOG("value beyond block: bytes=%u remaining=%zu\n", valueBytes, static_cast(end - cursor)); return false; @@ -100,12 +99,8 @@ static bool parseVersionBlock(const uint8_t *block, size_t available, VersionBlo return true; } -static bool queryVersionBlock(const uint8_t *block, size_t available, - const std::vector &segments, - size_t depth, - const uint8_t **outPtr, - uint32_t *outLen, - uint16_t *outType) { +static bool queryVersionBlock(const uint8_t *block, size_t available, const std::vector &segments, + size_t depth, const uint8_t **outPtr, uint32_t *outLen, uint16_t *outType) { VersionBlockView view; if (!parseVersionBlock(block, available, view)) return false; @@ -217,9 +212,10 @@ unsigned int WIN_FUNC GetFileVersionInfoSizeA(const char *lptstrFilename, unsign return static_cast(buffer.size()); } -unsigned int WIN_FUNC GetFileVersionInfoA(const char *lptstrFilename, unsigned int dwHandle, unsigned int dwLen, void *lpData) { +unsigned int WIN_FUNC GetFileVersionInfoA(const char *lptstrFilename, unsigned int dwHandle, unsigned int dwLen, + void *lpData) { HOST_CONTEXT_GUARD(); - (void) dwHandle; + (void)dwHandle; DEBUG_LOG("GetFileVersionInfoA(%s, %u, %p)\n", lptstrFilename, dwLen, lpData); if (!lpData || dwLen == 0) { wibo::lastError = ERROR_INVALID_PARAMETER; @@ -243,7 +239,8 @@ unsigned int WIN_FUNC GetFileVersionInfoA(const char *lptstrFilename, unsigned i return 1; } -static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, void **lplpBuffer, unsigned int *puLen) { +static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, void **lplpBuffer, + unsigned int *puLen) { if (!pBlock) return 0; @@ -280,7 +277,8 @@ static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &sub return 1; } -unsigned int WIN_FUNC VerQueryValueA(const void *pBlock, const char *lpSubBlock, void **lplpBuffer, unsigned int *puLen) { +unsigned int WIN_FUNC VerQueryValueA(const void *pBlock, const char *lpSubBlock, void **lplpBuffer, + unsigned int *puLen) { HOST_CONTEXT_GUARD(); DEBUG_LOG("VerQueryValueA(%p, %s, %p, %p)\n", pBlock, lpSubBlock ? lpSubBlock : "(null)", lplpBuffer, puLen); if (!lpSubBlock) @@ -295,14 +293,16 @@ unsigned int WIN_FUNC GetFileVersionInfoSizeW(const uint16_t *lptstrFilename, un return GetFileVersionInfoSizeA(narrow.c_str(), lpdwHandle); } -unsigned int WIN_FUNC GetFileVersionInfoW(const uint16_t *lptstrFilename, unsigned int dwHandle, unsigned int dwLen, void *lpData) { +unsigned int WIN_FUNC GetFileVersionInfoW(const uint16_t *lptstrFilename, unsigned int dwHandle, unsigned int dwLen, + void *lpData) { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetFileVersionInfoW -> "); auto narrow = wideStringToString(lptstrFilename); return GetFileVersionInfoA(narrow.c_str(), dwHandle, dwLen, lpData); } -unsigned int WIN_FUNC VerQueryValueW(const void *pBlock, const uint16_t *lpSubBlock, void **lplpBuffer, unsigned int *puLen) { +unsigned int WIN_FUNC VerQueryValueW(const void *pBlock, const uint16_t *lpSubBlock, void **lplpBuffer, + unsigned int *puLen) { HOST_CONTEXT_GUARD(); if (!lpSubBlock) return 0; @@ -314,16 +314,22 @@ unsigned int WIN_FUNC VerQueryValueW(const void *pBlock, const uint16_t *lpSubBl } // namespace version static void *resolveByName(const char *name) { - if (strcmp(name, "GetFileVersionInfoSizeA") == 0) return (void *) version::GetFileVersionInfoSizeA; - if (strcmp(name, "GetFileVersionInfoA") == 0) return (void *) version::GetFileVersionInfoA; - if (strcmp(name, "VerQueryValueA") == 0) return (void *) version::VerQueryValueA; - if (strcmp(name, "GetFileVersionInfoSizeW") == 0) return (void *) version::GetFileVersionInfoSizeW; - if (strcmp(name, "GetFileVersionInfoW") == 0) return (void *) version::GetFileVersionInfoW; - if (strcmp(name, "VerQueryValueW") == 0) return (void *) version::VerQueryValueW; + if (strcmp(name, "GetFileVersionInfoSizeA") == 0) + return (void *)version::GetFileVersionInfoSizeA; + if (strcmp(name, "GetFileVersionInfoA") == 0) + return (void *)version::GetFileVersionInfoA; + if (strcmp(name, "VerQueryValueA") == 0) + return (void *)version::VerQueryValueA; + if (strcmp(name, "GetFileVersionInfoSizeW") == 0) + return (void *)version::GetFileVersionInfoSizeW; + if (strcmp(name, "GetFileVersionInfoW") == 0) + return (void *)version::GetFileVersionInfoW; + if (strcmp(name, "VerQueryValueW") == 0) + return (void *)version::VerQueryValueW; return nullptr; } -wibo::Module lib_version = { +wibo::ModuleStub lib_version = { (const char *[]){ "version", nullptr, diff --git a/src/common.h b/src/common.h index c06dcdc..9fab80f 100644 --- a/src/common.h +++ b/src/common.h @@ -6,13 +6,9 @@ #include #include #include -#include -#include #include #include #include -#include -#include #include // On Windows, the incoming stack is aligned to a 4 byte boundary. @@ -240,10 +236,11 @@ struct TIB { uint16_t hostFsSelector; uint16_t hostGsSelector; uint8_t hostSegmentsValid; - uint8_t hostSegmentsPadding[5]; + uint8_t padding[3]; }; namespace wibo { + extern thread_local uint32_t lastError; extern char **argv; extern int argc; @@ -257,185 +254,13 @@ extern uint16_t tibSelector; extern int tibEntryNumber; extern PEB *processPeb; +TIB *allocateTib(); +void destroyTib(TIB *tib); +void initializeTibStackInfo(TIB *tib); +bool installTibForCurrentThread(TIB *tib); void setThreadTibForHost(TIB *tib); TIB *getThreadTibForHost(); -class HostContextGuard { -public: - HostContextGuard(); - ~HostContextGuard(); - HostContextGuard(const HostContextGuard &) = delete; - HostContextGuard &operator=(const HostContextGuard &) = delete; - -private: - uint16_t previousFs_; - uint16_t previousGs_; - bool restore_; -}; - -class GuestContextGuard { -public: - explicit GuestContextGuard(TIB *tib); - ~GuestContextGuard(); - GuestContextGuard(const GuestContextGuard &) = delete; - GuestContextGuard &operator=(const GuestContextGuard &) = delete; - -private: - uint16_t previousFs_; - uint16_t previousGs_; - bool applied_; -}; - -#define HOST_CONTEXT_GUARD() wibo::HostContextGuard _wiboHostContextGuard -#define GUEST_CONTEXT_GUARD(tibPtr) wibo::GuestContextGuard _wiboGuestContextGuard(tibPtr) - -TIB *allocateTib(); -void initializeTibStackInfo(TIB *tib); -bool installTibForCurrentThread(TIB *tib); -void destroyTib(TIB *tib); - void debug_log(const char *fmt, ...); -using ResolveByName = void *(*)(const char *); -using ResolveByOrdinal = void *(*)(uint16_t); -struct Module { - const char **names; - ResolveByName byName; - ResolveByOrdinal byOrdinal; -}; -struct ModuleInfo; -void initializeModuleRegistry(); -void shutdownModuleRegistry(); -ModuleInfo *moduleInfoFromHandle(HMODULE module); -void setDllDirectoryOverride(const std::filesystem::path &path); -void clearDllDirectoryOverride(); -std::optional dllDirectoryOverride(); -ModuleInfo *findLoadedModule(const char *name); -void registerOnExitTable(void *table); -void addOnExitFunction(void *table, void (*func)()); -void executeOnExitTable(void *table); -void runPendingOnExit(ModuleInfo &info); -void notifyDllThreadAttach(); -void notifyDllThreadDetach(); -BOOL disableThreadNotifications(ModuleInfo *info); - -ModuleInfo *loadModule(const char *name); -void freeModule(ModuleInfo *info); -void *resolveFuncByName(ModuleInfo *info, const char *funcName); -void *resolveFuncByOrdinal(ModuleInfo *info, 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) {} - static ResourceIdentifier fromID(uint32_t value) { - ResourceIdentifier ident; - ident.isString = false; - ident.id = value; - return ident; - } - static ResourceIdentifier fromString(std::u16string value) { - ResourceIdentifier ident; - ident.isString = true; - ident.name = std::move(value); - return ident; - } - bool isString; - uint32_t id; - std::u16string name; -}; - -struct ResourceLocation { - const void *dataEntry = nullptr; - const void *data = nullptr; - uint32_t size = 0; - uint16_t language = 0; -}; - -struct ImageResourceDataEntry { - uint32_t offsetToData; - uint32_t size; - uint32_t codePage; - uint32_t reserved; -}; - -struct Executable { - Executable() = default; - ~Executable(); - bool loadPE(FILE *file, bool exec); - bool resolveImports(); - - struct SectionInfo { - uintptr_t base = 0; - size_t size = 0; - DWORD protect = PAGE_NOACCESS; - DWORD characteristics = 0; - }; - - void *imageBase = nullptr; - size_t imageSize = 0; - void *entryPoint = nullptr; - void *rsrcBase = nullptr; - uint32_t rsrcSize = 0; - uintptr_t preferredImageBase = 0; - intptr_t relocationDelta = 0; - uint32_t exportDirectoryRVA = 0; - uint32_t exportDirectorySize = 0; - uint32_t relocationDirectoryRVA = 0; - uint32_t relocationDirectorySize = 0; - uint32_t importDirectoryRVA = 0; - uint32_t importDirectorySize = 0; - uint32_t delayImportDirectoryRVA = 0; - uint32_t delayImportDirectorySize = 0; - bool execMapped = false; - bool importsResolved = false; - bool importsResolving = false; - std::vector sections; - - bool findResource(const ResourceIdentifier &type, const ResourceIdentifier &name, std::optional language, - ResourceLocation &out) const; - template T *fromRVA(uintptr_t rva) const { return (T *)(rva + (uint8_t *)imageBase); } - template T *fromRVA(T *rva) const { return fromRVA((uintptr_t)rva); } -}; - -extern ModuleInfo *mainModule; -struct ModuleInfo { - // Windows-style handle to the module. For the main module, this is the image base. - // For other modules, this is a pointer to the ModuleInfo structure. - HMODULE handle; - // Original name used to load the module - std::string originalName; - // Normalized module name - std::string normalizedName; - // Full path to the loaded module - std::filesystem::path resolvedPath; - // Pointer to the built-in module, nullptr if loaded from file - const wibo::Module *module = nullptr; - // Loaded PE executable - std::unique_ptr executable; - // Reference count, or UINT_MAX for built-in modules - unsigned int refCount = 0; - bool processAttachCalled = false; - bool processAttachSucceeded = false; - bool threadNotificationsEnabled = true; - uint32_t exportOrdinalBase = 0; - std::vector exportsByOrdinal; - std::unordered_map exportNameToOrdinal; - bool exportsInitialized = false; - std::vector onExitFunctions; -}; - -ModuleInfo *registerProcessModule(std::unique_ptr executable, std::filesystem::path resolvedPath, - std::string originalName); -Executable *executableFromModule(HMODULE module); -ModuleInfo *moduleInfoFromAddress(void *addr); - -/** - * HMODULE will be `nullptr` or `mainModule->imageBase` if it's the main module, - * otherwise it will be a pointer to a `wibo::ModuleInfo`. - */ -inline bool isMainModule(HMODULE hModule) { - return hModule == nullptr || hModule == reinterpret_cast(mainModule) || - (mainModule && mainModule->executable && hModule == mainModule->executable->imageBase); -} } // namespace wibo diff --git a/src/context.cpp b/src/context.cpp index 3b9bf8d..58ea23f 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -1,4 +1,4 @@ -#include "common.h" +#include "context.h" #include diff --git a/src/context.h b/src/context.h new file mode 100644 index 0000000..2a5a9a2 --- /dev/null +++ b/src/context.h @@ -0,0 +1,36 @@ +#pragma once + +#include "common.h" + +namespace wibo { + +class HostContextGuard { + public: + HostContextGuard(); + ~HostContextGuard(); + HostContextGuard(const HostContextGuard &) = delete; + HostContextGuard &operator=(const HostContextGuard &) = delete; + + private: + uint16_t previousFs_; + uint16_t previousGs_; + bool restore_; +}; + +class GuestContextGuard { + public: + explicit GuestContextGuard(TIB *tib); + ~GuestContextGuard(); + GuestContextGuard(const GuestContextGuard &) = delete; + GuestContextGuard &operator=(const GuestContextGuard &) = delete; + + private: + uint16_t previousFs_; + uint16_t previousGs_; + bool applied_; +}; + +} // namespace wibo + +#define HOST_CONTEXT_GUARD() wibo::HostContextGuard _wiboHostContextGuard +#define GUEST_CONTEXT_GUARD(tibPtr) wibo::GuestContextGuard _wiboGuestContextGuard(tibPtr) diff --git a/src/loader.cpp b/src/loader.cpp index cd2890b..c1207fe 100644 --- a/src/loader.cpp +++ b/src/loader.cpp @@ -1,9 +1,9 @@ #include "common.h" #include "errors.h" +#include "modules.h" + #include #include -#include -#include #include #include #include @@ -291,10 +291,11 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) { size_t sectionSpan = std::max(section.virtualSize, section.sizeOfRawData); if (sectionSpan != 0) { - uintptr_t sectionStart = alignDown(imageBaseAddr + static_cast(section.virtualAddress), pageSizeValue); + uintptr_t sectionStart = + alignDown(imageBaseAddr + static_cast(section.virtualAddress), pageSizeValue); uintptr_t sectionEnd = alignUp(imageBaseAddr + static_cast(section.virtualAddress) + - static_cast(sectionSpan), - pageSizeValue); + static_cast(sectionSpan), + pageSizeValue); if (sectionEnd > sectionStart) { Executable::SectionInfo sectionInfo{}; sectionInfo.base = sectionStart; @@ -305,9 +306,8 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) { } } } - std::sort(sections.begin(), sections.end(), [](const SectionInfo &lhs, const SectionInfo &rhs) { - return lhs.base < rhs.base; - }); + std::sort(sections.begin(), sections.end(), + [](const SectionInfo &lhs, const SectionInfo &rhs) { return lhs.base < rhs.base; }); if (exec && relocationDelta != 0) { if (relocationDirectoryRVA == 0 || relocationDirectorySize == 0) { diff --git a/src/main.cpp b/src/main.cpp index ae44743..83b82cd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,10 @@ #include "common.h" +#include "context.h" #include "files.h" +#include "modules.h" #include "processes.h" #include "strutil.h" + #include #include #include diff --git a/src/module_registry.cpp b/src/modules.cpp similarity index 94% rename from src/module_registry.cpp rename to src/modules.cpp index ba75385..97122b3 100644 --- a/src/module_registry.cpp +++ b/src/modules.cpp @@ -1,4 +1,7 @@ +#include "modules.h" + #include "common.h" +#include "context.h" #include "errors.h" #include "files.h" #include "strutil.h" @@ -17,19 +20,19 @@ #include #include -extern const wibo::Module lib_advapi32; -extern const wibo::Module lib_bcrypt; -extern const wibo::Module lib_crt; -extern const wibo::Module lib_kernel32; -extern const wibo::Module lib_lmgr; -extern const wibo::Module lib_mscoree; -extern const wibo::Module lib_msvcrt; -extern const wibo::Module lib_ntdll; -extern const wibo::Module lib_rpcrt4; -extern const wibo::Module lib_ole32; -extern const wibo::Module lib_user32; -extern const wibo::Module lib_vcruntime; -extern const wibo::Module lib_version; +extern const wibo::ModuleStub lib_advapi32; +extern const wibo::ModuleStub lib_bcrypt; +extern const wibo::ModuleStub lib_crt; +extern const wibo::ModuleStub lib_kernel32; +extern const wibo::ModuleStub lib_lmgr; +extern const wibo::ModuleStub lib_mscoree; +extern const wibo::ModuleStub lib_msvcrt; +extern const wibo::ModuleStub lib_ntdll; +extern const wibo::ModuleStub lib_rpcrt4; +extern const wibo::ModuleStub lib_ole32; +extern const wibo::ModuleStub lib_user32; +extern const wibo::ModuleStub lib_vcruntime; +extern const wibo::ModuleStub lib_version; namespace { @@ -118,16 +121,14 @@ StubFuncType resolveMissingFuncOrdinal(const char *dllName, uint16_t ordinal) { return resolveMissingFuncName(dllName, buf); } -using ModulePtr = std::unique_ptr; - struct ModuleRegistry { std::recursive_mutex mutex; - std::unordered_map modulesByKey; + std::unordered_map modulesByKey; std::unordered_map modulesByAlias; std::optional dllDirectory; bool initialized = false; std::unordered_map onExitTables; - std::unordered_map> builtinAliasLists; + std::unordered_map> builtinAliasLists; std::unordered_map builtinAliasMap; std::unordered_set pinnedAliases; std::unordered_set pinnedModules; @@ -150,18 +151,18 @@ struct LockedRegistry { ModuleRegistry &operator*() const { return *reg; } }; -void registerBuiltinModule(ModuleRegistry ®, const wibo::Module *module); +void registerBuiltinModule(ModuleRegistry ®, const wibo::ModuleStub *module); LockedRegistry registry() { static ModuleRegistry reg; std::unique_lock guard(reg.mutex); if (!reg.initialized) { reg.initialized = true; - const wibo::Module *builtins[] = { + const wibo::ModuleStub *builtins[] = { &lib_advapi32, &lib_bcrypt, &lib_crt, &lib_kernel32, &lib_lmgr, &lib_mscoree, &lib_msvcrt, &lib_ntdll, &lib_ole32, &lib_rpcrt4, &lib_user32, &lib_vcruntime, &lib_version, nullptr, }; - for (const wibo::Module **module = builtins; *module; ++module) { + for (const wibo::ModuleStub **module = builtins; *module; ++module) { registerBuiltinModule(reg, *module); } } @@ -365,18 +366,18 @@ void registerAlias(ModuleRegistry ®, const std::string &alias, wibo::ModuleIn return; } // Prefer externally loaded modules over built-ins when both are present. - if (it->second && it->second->module != nullptr && info->module == nullptr) { + if (it->second && it->second->moduleStub != nullptr && info->moduleStub == nullptr) { reg.modulesByAlias[alias] = info; } } -void registerBuiltinModule(ModuleRegistry ®, const wibo::Module *module) { +void registerBuiltinModule(ModuleRegistry ®, const wibo::ModuleStub *module) { if (!module) { return; } - ModulePtr entry = std::make_unique(); + wibo::ModulePtr entry = std::make_shared(); entry->handle = entry.get(); - entry->module = module; + entry->moduleStub = module; entry->refCount = UINT_MAX; entry->originalName = module->names[0] ? module->names[0] : ""; entry->normalizedName = normalizedBaseKey(parseModuleName(entry->originalName)); @@ -520,7 +521,7 @@ bool shouldDeliverThreadNotifications(const wibo::ModuleInfo &info) { if (&info == wibo::mainModule) { return false; } - if (info.module != nullptr) { + if (info.moduleStub != nullptr) { return false; } if (!info.executable) { @@ -536,7 +537,7 @@ bool shouldDeliverThreadNotifications(const wibo::ModuleInfo &info) { } void ensureExportsInitialized(wibo::ModuleInfo &info) { - if (info.module || info.exportsInitialized) + if (info.moduleStub || info.exportsInitialized) return; if (!info.executable) return; @@ -604,7 +605,7 @@ ModuleInfo *registerProcessModule(std::unique_ptr executable, std::f ModulePtr info = std::make_unique(); info->handle = executable->imageBase; // Use image base as handle for main module - info->module = nullptr; + info->moduleStub = nullptr; info->originalName = std::move(originalName); info->normalizedName = std::move(normalizedName); info->resolvedPath = std::move(resolvedPath); @@ -655,7 +656,7 @@ void shutdownModuleRegistry() { auto reg = registry(); for (auto &pair : reg->modulesByKey) { ModuleInfo *info = pair.second.get(); - if (!info || info->module) { + if (!info || info->moduleStub) { continue; } runPendingOnExit(*info); @@ -877,7 +878,7 @@ ModuleInfo *loadModule(const char *dllName) { ModulePtr info = std::make_unique(); info->handle = info.get(); - info->module = nullptr; + info->moduleStub = nullptr; info->originalName = requested; info->normalizedName = normalizedBaseKey(parsed); info->resolvedPath = files::canonicalPath(path); @@ -940,8 +941,8 @@ ModuleInfo *loadModule(const char *dllName) { existing = findByAlias(*reg, normalizeAlias(requested)); } if (existing) { - DEBUG_LOG(" found existing module alias %s (builtin=%d)\n", alias.c_str(), existing->module != nullptr); - if (existing->module == nullptr) { + DEBUG_LOG(" found existing module alias %s (builtin=%d)\n", alias.c_str(), existing->moduleStub != nullptr); + if (existing->moduleStub == nullptr) { if (existing->refCount != UINT_MAX) { existing->refCount++; } @@ -986,7 +987,7 @@ ModuleInfo *loadModule(const char *dllName) { builtin = builtinIt->second; } } - if (builtin && builtin->module != nullptr) { + if (builtin && builtin->moduleStub != nullptr) { DEBUG_LOG(" falling back to builtin module %s\n", builtin->originalName.c_str()); lastError = (diskError != ERROR_SUCCESS) ? diskError : ERROR_SUCCESS; return builtin; @@ -1032,14 +1033,14 @@ void *resolveFuncByName(ModuleInfo *info, const char *funcName) { if (!info) { return nullptr; } - if (info->module && info->module->byName) { - void *func = info->module->byName(funcName); + if (info->moduleStub && info->moduleStub->byName) { + void *func = info->moduleStub->byName(funcName); if (func) { return func; } } ensureExportsInitialized(*info); - if (!info->module) { + if (!info->moduleStub) { auto it = info->exportNameToOrdinal.find(funcName); if (it != info->exportNameToOrdinal.end()) { return resolveFuncByOrdinal(info, it->second); @@ -1052,13 +1053,13 @@ void *resolveFuncByOrdinal(ModuleInfo *info, uint16_t ordinal) { if (!info) { return nullptr; } - if (info->module && info->module->byOrdinal) { - void *func = info->module->byOrdinal(ordinal); + if (info->moduleStub && info->moduleStub->byOrdinal) { + void *func = info->moduleStub->byOrdinal(ordinal); if (func) { return func; } } - if (!info->module) { + if (!info->moduleStub) { ensureExportsInitialized(*info); if (!info->exportsByOrdinal.empty() && ordinal >= info->exportOrdinalBase) { auto index = static_cast(ordinal - info->exportOrdinalBase); @@ -1109,4 +1110,9 @@ Executable *executableFromModule(HMODULE module) { return info->executable.get(); } +std::unordered_map allLoadedModules() { + auto reg = registry(); + return reg->modulesByKey; +} + } // namespace wibo diff --git a/src/modules.h b/src/modules.h new file mode 100644 index 0000000..8e24834 --- /dev/null +++ b/src/modules.h @@ -0,0 +1,129 @@ +#pragma once + +#include "common.h" + +#include +#include + +namespace wibo { + +using ResolveByName = void *(*)(const char *); +using ResolveByOrdinal = void *(*)(uint16_t); + +struct ResourceIdentifier; +struct ResourceLocation; + +struct ModuleStub { + const char **names; + ResolveByName byName; + ResolveByOrdinal byOrdinal; +}; + +class Executable { + public: + struct SectionInfo { + uintptr_t base = 0; + size_t size = 0; + DWORD protect = PAGE_NOACCESS; + DWORD characteristics = 0; + }; + + Executable() = default; + ~Executable(); + + bool loadPE(FILE *file, bool exec); + bool resolveImports(); + bool findResource(const ResourceIdentifier &type, const ResourceIdentifier &name, std::optional language, + ResourceLocation &out) const; + + template T *fromRVA(uintptr_t rva) const { return (T *)(rva + (uint8_t *)imageBase); } + template T *fromRVA(T *rva) const { return fromRVA((uintptr_t)rva); } + + void *imageBase = nullptr; + size_t imageSize = 0; + void *entryPoint = nullptr; + void *rsrcBase = nullptr; + uint32_t rsrcSize = 0; + uintptr_t preferredImageBase = 0; + intptr_t relocationDelta = 0; + uint32_t exportDirectoryRVA = 0; + uint32_t exportDirectorySize = 0; + uint32_t relocationDirectoryRVA = 0; + uint32_t relocationDirectorySize = 0; + uint32_t importDirectoryRVA = 0; + uint32_t importDirectorySize = 0; + uint32_t delayImportDirectoryRVA = 0; + uint32_t delayImportDirectorySize = 0; + bool execMapped = false; + bool importsResolved = false; + bool importsResolving = false; + std::vector sections; +}; + +struct ModuleInfo { + // Windows-style handle to the module. For the main module, this is the image base. + // For other modules, this is a pointer to the ModuleInfo structure. + HMODULE handle; + // Original name used to load the module + std::string originalName; + // Normalized module name + std::string normalizedName; + // Full path to the loaded module + std::filesystem::path resolvedPath; + // Pointer to the built-in module, nullptr if loaded from file + const wibo::ModuleStub *moduleStub = nullptr; + // Loaded PE executable + std::unique_ptr executable; + // Reference count, or UINT_MAX for built-in modules + unsigned int refCount = 0; + bool processAttachCalled = false; + bool processAttachSucceeded = false; + bool threadNotificationsEnabled = true; + uint32_t exportOrdinalBase = 0; + std::vector exportsByOrdinal; + std::unordered_map exportNameToOrdinal; + bool exportsInitialized = false; + std::vector onExitFunctions; +}; +extern ModuleInfo *mainModule; + +using ModulePtr = std::shared_ptr; + +void initializeModuleRegistry(); +void shutdownModuleRegistry(); +ModuleInfo *moduleInfoFromHandle(HMODULE module); +void setDllDirectoryOverride(const std::filesystem::path &path); +void clearDllDirectoryOverride(); +std::optional dllDirectoryOverride(); +ModuleInfo *findLoadedModule(const char *name); +void registerOnExitTable(void *table); +void addOnExitFunction(void *table, void (*func)()); +void executeOnExitTable(void *table); +void runPendingOnExit(ModuleInfo &info); +void notifyDllThreadAttach(); +void notifyDllThreadDetach(); +BOOL disableThreadNotifications(ModuleInfo *info); +std::unordered_map allLoadedModules(); + +ModuleInfo *loadModule(const char *name); +void freeModule(ModuleInfo *info); +void *resolveFuncByName(ModuleInfo *info, const char *funcName); +void *resolveFuncByOrdinal(ModuleInfo *info, uint16_t ordinal); +void *resolveMissingImportByName(const char *dllName, const char *funcName); +void *resolveMissingImportByOrdinal(const char *dllName, uint16_t ordinal); + +ModuleInfo *registerProcessModule(std::unique_ptr executable, std::filesystem::path resolvedPath, + std::string originalName); +Executable *executableFromModule(HMODULE module); +ModuleInfo *moduleInfoFromAddress(void *addr); + +/** + * HMODULE will be `nullptr` or `mainModule->imageBase` if it's the main module, + * otherwise it will be a pointer to a `wibo::ModuleInfo`. + */ +inline bool isMainModule(HMODULE hModule) { + return hModule == nullptr || hModule == reinterpret_cast(mainModule) || + (mainModule && mainModule->executable && hModule == mainModule->executable->imageBase); +} + +} // namespace wibo diff --git a/src/resources.cpp b/src/resources.cpp index 6bd367f..3b8a35c 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -1,6 +1,8 @@ #include "resources.h" -#include "errors.h" + #include "common.h" +#include "errors.h" +#include "modules.h" namespace { diff --git a/src/resources.h b/src/resources.h index 3296e78..0efeee7 100644 --- a/src/resources.h +++ b/src/resources.h @@ -1,12 +1,44 @@ #pragma once #include +#include namespace wibo { struct Executable; -struct ImageResourceDataEntry; -struct ResourceIdentifier; + +struct ResourceIdentifier { + ResourceIdentifier() : isString(false), id(0) {} + static ResourceIdentifier fromID(uint32_t value) { + ResourceIdentifier ident; + ident.isString = false; + ident.id = value; + return ident; + } + static ResourceIdentifier fromString(std::u16string value) { + ResourceIdentifier ident; + ident.isString = true; + ident.name = std::move(value); + return ident; + } + bool isString; + uint32_t id; + std::u16string name; +}; + +struct ResourceLocation { + const void *dataEntry = nullptr; + const void *data = nullptr; + uint32_t size = 0; + uint16_t language = 0; +}; + +struct ImageResourceDataEntry { + uint32_t offsetToData; + uint32_t size; + uint32_t codePage; + uint32_t reserved; +}; bool resourceEntryBelongsToExecutable(const Executable &exe, const ImageResourceDataEntry *entry); ResourceIdentifier resourceIdentifierFromAnsi(const char *id); diff --git a/src/strutil.cpp b/src/strutil.cpp index 3a542d4..40a619b 100644 --- a/src/strutil.cpp +++ b/src/strutil.cpp @@ -1,5 +1,7 @@ #include "strutil.h" + #include "common.h" + #include #include #include