diff --git a/mu3hook/dllmain.c b/mu3hook/dllmain.c index c34bc51..cc6a980 100644 --- a/mu3hook/dllmain.c +++ b/mu3hook/dllmain.c @@ -11,6 +11,7 @@ #include "mu3hook/config.h" #include "mu3hook/io4.h" +#include "mu3hook/unity.h" #include "platform/platform.h" @@ -33,6 +34,7 @@ static DWORD CALLBACK mu3_pre_startup(void) /* Hook Win32 APIs */ serial_hook_init(); + unity_hook_init(); /* Initialize emulation hooks */ diff --git a/mu3hook/meson.build b/mu3hook/meson.build index 66293dc..4f3ba71 100644 --- a/mu3hook/meson.build +++ b/mu3hook/meson.build @@ -24,5 +24,7 @@ shared_library( 'dllmain.c', 'io4.c', 'io4.h', + 'unity.h', + 'unity.c', ], ) diff --git a/mu3hook/unity.c b/mu3hook/unity.c new file mode 100644 index 0000000..efefc32 --- /dev/null +++ b/mu3hook/unity.c @@ -0,0 +1,95 @@ +#include + +#include + +#include "hook/table.h" + +#include "hooklib/dll.h" +#include "hooklib/path.h" + +#include "util/dprintf.h" + +static void dll_hook_insert_hooks(HMODULE target); + +static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name); +static HMODULE (WINAPI *next_LoadLibraryW)(const wchar_t *name); + +static const struct hook_symbol unity_kernel32_syms[] = { + { + .name = "LoadLibraryW", + .patch = my_LoadLibraryW, + .link = (void **) &next_LoadLibraryW, + }, +}; + +static const wchar_t *target_modules[] = { + L"mono.dll", + L"cri_ware_unity.dll", +}; +static const size_t target_modules_len = _countof(target_modules); + +void unity_hook_init(void) +{ + dll_hook_insert_hooks(NULL); +} + +static void dll_hook_insert_hooks(HMODULE target) +{ + hook_table_apply( + target, + "kernel32.dll", + unity_kernel32_syms, + _countof(unity_kernel32_syms)); +} + +static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) +{ + const wchar_t *name_end; + const wchar_t *target_module; + bool already_loaded; + HMODULE result; + size_t name_len; + size_t target_module_len; + + if (name == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + + return NULL; + } + + // Check if the module is already loaded + already_loaded = GetModuleHandleW(name) != NULL; + + // Must call the next handler so the DLL reference count is incremented + result = next_LoadLibraryW(name); + + if (!already_loaded && result != NULL) { + name_len = wcslen(name); + + for (size_t i = 0; i < target_modules_len; i++) { + target_module = target_modules[i]; + target_module_len = wcslen(target_module); + + // Check if the newly loaded library is at least the length of + // the name of the target module + if (name_len < target_module_len) { + continue; + } + + name_end = &name[name_len - target_module_len]; + + // Check if the name of the newly loaded library is one of the + // modules the path hooks should be injected into + if (_wcsicmp(name_end, target_module) != 0) { + continue; + } + + dprintf("Unity: Loaded %S\n", target_module); + + dll_hook_insert_hooks(result); + path_hook_insert_hooks(result); + } + } + + return result; +} diff --git a/mu3hook/unity.h b/mu3hook/unity.h new file mode 100644 index 0000000..99c3bd9 --- /dev/null +++ b/mu3hook/unity.h @@ -0,0 +1,3 @@ +#pragma once + +void unity_hook_init(void);