Reorg headers, module_registry -> modules, remove ActCtx msvcr80.dll hack

This commit is contained in:
Luke Street 2025-10-05 17:46:16 -06:00
parent b87fb5e472
commit 0d76e541c1
53 changed files with 420 additions and 423 deletions

View File

@ -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

View File

@ -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 <cstring>
@ -105,7 +106,7 @@ void *resolveByName(const char *name) {
} // namespace
wibo::Module lib_advapi32 = {
wibo::ModuleStub lib_advapi32 = {
(const char *[]){
"advapi32",
nullptr,

View File

@ -1,5 +1,7 @@
#include "processthreadsapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"

View File

@ -1,5 +1,7 @@
#include "securitybaseapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"

View File

@ -1,5 +1,7 @@
#include "winbase.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "internal.h"
#include "strutil.h"

View File

@ -1,5 +1,7 @@
#include "wincrypt.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include <cstring>

View File

@ -1,5 +1,7 @@
#include "winreg.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "handles.h"
#include "strutil.h"

View File

@ -1,5 +1,7 @@
#include "common.h"
#include "context.h"
#include "errors.h"
#include "modules.h"
#include <sys/random.h>
#include <vector>
@ -72,7 +74,7 @@ static void *resolveByName(const char *name) {
return nullptr;
}
wibo::Module lib_bcrypt = {
wibo::ModuleStub lib_bcrypt = {
(const char *[]){
"bcrypt",
nullptr,

View File

@ -1,4 +1,6 @@
#include "common.h"
#include "context.h"
#include "modules.h"
#include <csignal>
#include <cstdarg>
@ -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",

View File

@ -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,

View File

@ -1,5 +1,7 @@
#include "debugapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
namespace kernel32 {

View File

@ -1,5 +1,7 @@
#include "errhandlingapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
namespace {

View File

@ -1,5 +1,7 @@
#include "fibersapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
namespace {

View File

@ -2,6 +2,7 @@
#include "access.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "files.h"
#include "handles.h"

View File

@ -1,5 +1,6 @@
#include "handleapi.h"
#include "context.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"

View File

@ -1,5 +1,7 @@
#include "heapapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"

View File

@ -1,5 +1,7 @@
#include "interlockedapi.h"
#include "common.h"
#include "context.h"
#include <cstring>

View File

@ -1,5 +1,6 @@
#include "ioapiset.h"
#include "context.h"
#include "errors.h"
#include "synchapi.h"

View File

@ -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"

View File

@ -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 <cerrno>

View File

@ -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 <cerrno>
#include <cstdio>
#include <fcntl.h>
#include <unistd.h>

View File

@ -1,5 +1,6 @@
#include "processenv.h"
#include "context.h"
#include "errors.h"
#include "files.h"
#include "internal.h"

View File

@ -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"

View File

@ -1,5 +1,7 @@
#include "profileapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
namespace kernel32 {

View File

@ -1,5 +1,6 @@
#include "stringapiset.h"
#include "context.h"
#include "errors.h"
#include "strutil.h"

View File

@ -1,6 +1,7 @@
#include "synchapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"

View File

@ -1,5 +1,7 @@
#include "sysinfoapi.h"
#include "common.h"
#include "context.h"
#include "errors.h"
#include "timeutil.h"

View File

@ -1,5 +1,6 @@
#include "timezoneapi.h"
#include "context.h"
#include "errors.h"
#include "timeutil.h"

View File

@ -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 <algorithm>
@ -13,16 +14,15 @@
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <limits>
#include <mimalloc.h>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <sys/mman.h>
#include <sys/statvfs.h>
#include <system_error>
#include <unordered_map>
#include <vector>
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[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
" <assemblyIdentity type=\"win32\" name=\"Microsoft.VC80.CRT\" version=\"8.0.50727.762\" processorArchitecture=\"x86\" publicKeyToken=\"1fc8b3b9a1e18e3b\"/>\n"
" <file name=\"msvcr80.dll\"/>\n"
" <file name=\"msvcp80.dll\"/>\n"
" <file name=\"msvcm80.dll\"/>\n"
"</assembly>\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 : "<null>", ReturnedData);
std::vector<uint16_t> 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<LPCWSTR>(widePtr), ReturnedData);
return FindActCtxSectionStringW(dwFlags, lpExtensionGuid, ulSectionId, reinterpret_cast<LPCWSTR>(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<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);
ReturnedData->ulLength = matchedEntry->dllData.Size;
ReturnedData->lpSectionBase = const_cast<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);

View File

@ -1,11 +1,11 @@
#include "wincon.h"
#include "context.h"
#include "errors.h"
#include "files.h"
#include "handles.h"
#include "strutil.h"
#include <cstdio>
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<FileObject>(hConsoleOutput);
if (file->fd == STDOUT_FILENO || file->fd == STDERR_FILENO) {
auto str = wideStringToString(static_cast<const uint16_t *>(lpBuffer), nNumberOfCharsToWrite);
auto str = wideStringToString(static_cast<const uint16_t *>(lpBuffer), static_cast<int>(nNumberOfCharsToWrite));
dprintf(file->fd, "%s", str.c_str());
if (lpNumberOfCharsWritten) {
*lpNumberOfCharsWritten = nNumberOfCharsToWrite;

View File

@ -1,5 +1,6 @@
#include "winnls.h"
#include "context.h"
#include "errors.h"
#include "strutil.h"

View File

@ -1,6 +1,7 @@
#include "winnt.h"
#include "common.h"
#include "context.h"
namespace kernel32 {

View File

@ -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 {

View File

@ -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",

View File

@ -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,

View File

@ -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 <algorithm>
#include <array>
#include <cctype>
#include <cerrno>
#include <climits>
#include <clocale>
#include <cmath>
#include <cctype>
#include <float.h>
#include <csignal>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <csignal>
#include <cstring>
#include <ctime>
#include <cwchar>
#include <cwctype>
#include <fcntl.h>
#include <filesystem>
#include <float.h>
#include <math.h>
#include <memory>
#include <mutex>
#include <optional>
#include <ctime>
#include <spawn.h>
#include <string>
#include <strings.h>
#include <type_traits>
#include <unordered_map>
#include <unistd.h>
#include <vector>
#include <spawn.h>
#include <sys/wait.h>
#include <math.h>
#include <utime.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <type_traits>
#include <unistd.h>
#include <unordered_map>
#include <utime.h>
#include <vector>
#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",

View File

@ -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,

View File

@ -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,

View File

@ -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,
};

View File

@ -1,4 +1,6 @@
#include "common.h"
#include "context.h"
#include "modules.h"
#include <cstdarg>
#include <cstdlib>
@ -283,7 +285,7 @@ void *resolveByName(const char *name) {
} // namespace
wibo::Module lib_rpcrt4 = {
wibo::ModuleStub lib_rpcrt4 = {
(const char *[]){"rpcrt4", nullptr},
resolveByName,
nullptr,

View File

@ -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,

View File

@ -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,

View File

@ -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<uint16_t>(ptr[0] | (ptr[1] << 8));
}
static uint16_t readU16(const uint8_t *ptr) { return static_cast<uint16_t>(ptr[0] | (ptr[1] << 8)); }
static size_t align4(size_t offset) {
return (offset + 3u) & ~static_cast<size_t>(3u);
}
static size_t align4(size_t offset) { return (offset + 3u) & ~static_cast<size_t>(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<size_t>(cursor - block), static_cast<size_t>(end - block));
DEBUG_LOG("key cursor beyond block: cursor=%zu end=%zu\n", static_cast<size_t>(cursor - block),
static_cast<size_t>(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<uint32_t>(valueLength) * sizeof(uint16_t)
: static_cast<uint32_t>(valueLength);
valueBytes =
type == 1 ? static_cast<uint32_t>(valueLength) * sizeof(uint16_t) : static_cast<uint32_t>(valueLength);
if (cursor + valueBytes > end) {
DEBUG_LOG("value beyond block: bytes=%u remaining=%zu\n", valueBytes, static_cast<size_t>(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<std::string> &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<std::string> &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<unsigned int>(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,

View File

@ -6,13 +6,9 @@
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include <unordered_map>
#include <utility>
#include <vector>
// 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<std::filesystem::path> 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<SectionInfo> sections;
bool findResource(const ResourceIdentifier &type, const ResourceIdentifier &name, std::optional<uint16_t> language,
ResourceLocation &out) const;
template <typename T> T *fromRVA(uintptr_t rva) const { return (T *)(rva + (uint8_t *)imageBase); }
template <typename T> T *fromRVA(T *rva) const { return fromRVA<T>((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<wibo::Executable> 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<void *> exportsByOrdinal;
std::unordered_map<std::string, uint16_t> exportNameToOrdinal;
bool exportsInitialized = false;
std::vector<void *> onExitFunctions;
};
ModuleInfo *registerProcessModule(std::unique_ptr<Executable> 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<HMODULE>(mainModule) ||
(mainModule && mainModule->executable && hModule == mainModule->executable->imageBase);
}
} // namespace wibo

View File

@ -1,4 +1,4 @@
#include "common.h"
#include "context.h"
#include <cstddef>

36
src/context.h Normal file
View File

@ -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)

View File

@ -1,9 +1,9 @@
#include "common.h"
#include "errors.h"
#include "modules.h"
#include <algorithm>
#include <cstring>
#include <errno.h>
#include <memory>
#include <strings.h>
#include <sys/mman.h>
#include <sys/syscall.h>
@ -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<uintptr_t>(section.virtualAddress), pageSizeValue);
uintptr_t sectionStart =
alignDown(imageBaseAddr + static_cast<uintptr_t>(section.virtualAddress), pageSizeValue);
uintptr_t sectionEnd = alignUp(imageBaseAddr + static_cast<uintptr_t>(section.virtualAddress) +
static_cast<uintptr_t>(sectionSpan),
pageSizeValue);
static_cast<uintptr_t>(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) {

View File

@ -1,7 +1,10 @@
#include "common.h"
#include "context.h"
#include "files.h"
#include "modules.h"
#include "processes.h"
#include "strutil.h"
#include <asm/ldt.h>
#include <charconv>
#include <cstdarg>

View File

@ -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 <utility>
#include <vector>
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<wibo::ModuleInfo>;
struct ModuleRegistry {
std::recursive_mutex mutex;
std::unordered_map<std::string, ModulePtr> modulesByKey;
std::unordered_map<std::string, wibo::ModulePtr> modulesByKey;
std::unordered_map<std::string, wibo::ModuleInfo *> modulesByAlias;
std::optional<std::filesystem::path> dllDirectory;
bool initialized = false;
std::unordered_map<void *, wibo::ModuleInfo *> onExitTables;
std::unordered_map<const wibo::Module *, std::vector<std::string>> builtinAliasLists;
std::unordered_map<const wibo::ModuleStub *, std::vector<std::string>> builtinAliasLists;
std::unordered_map<std::string, wibo::ModuleInfo *> builtinAliasMap;
std::unordered_set<std::string> pinnedAliases;
std::unordered_set<wibo::ModuleInfo *> pinnedModules;
@ -150,18 +151,18 @@ struct LockedRegistry {
ModuleRegistry &operator*() const { return *reg; }
};
void registerBuiltinModule(ModuleRegistry &reg, const wibo::Module *module);
void registerBuiltinModule(ModuleRegistry &reg, 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 &reg, 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 &reg, const wibo::Module *module) {
void registerBuiltinModule(ModuleRegistry &reg, const wibo::ModuleStub *module) {
if (!module) {
return;
}
ModulePtr entry = std::make_unique<wibo::ModuleInfo>();
wibo::ModulePtr entry = std::make_shared<wibo::ModuleInfo>();
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> executable, std::f
ModulePtr info = std::make_unique<ModuleInfo>();
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<ModuleInfo>();
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<size_t>(ordinal - info->exportOrdinalBase);
@ -1109,4 +1110,9 @@ Executable *executableFromModule(HMODULE module) {
return info->executable.get();
}
std::unordered_map<std::string, ModulePtr> allLoadedModules() {
auto reg = registry();
return reg->modulesByKey;
}
} // namespace wibo

129
src/modules.h Normal file
View File

@ -0,0 +1,129 @@
#pragma once
#include "common.h"
#include <optional>
#include <unordered_map>
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<uint16_t> language,
ResourceLocation &out) const;
template <typename T> T *fromRVA(uintptr_t rva) const { return (T *)(rva + (uint8_t *)imageBase); }
template <typename T> T *fromRVA(T *rva) const { return fromRVA<T>((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<SectionInfo> 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<wibo::Executable> 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<void *> exportsByOrdinal;
std::unordered_map<std::string, uint16_t> exportNameToOrdinal;
bool exportsInitialized = false;
std::vector<void *> onExitFunctions;
};
extern ModuleInfo *mainModule;
using ModulePtr = std::shared_ptr<wibo::ModuleInfo>;
void initializeModuleRegistry();
void shutdownModuleRegistry();
ModuleInfo *moduleInfoFromHandle(HMODULE module);
void setDllDirectoryOverride(const std::filesystem::path &path);
void clearDllDirectoryOverride();
std::optional<std::filesystem::path> 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<std::string, ModulePtr> 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> 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<HMODULE>(mainModule) ||
(mainModule && mainModule->executable && hModule == mainModule->executable->imageBase);
}
} // namespace wibo

View File

@ -1,6 +1,8 @@
#include "resources.h"
#include "errors.h"
#include "common.h"
#include "errors.h"
#include "modules.h"
namespace {

View File

@ -1,12 +1,44 @@
#pragma once
#include <cstdint>
#include <string>
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);

View File

@ -1,5 +1,7 @@
#include "strutil.h"
#include "common.h"
#include <algorithm>
#include <cctype>
#include <cstdint>