From c895c275cfdc90f1c55483e252f5d87628e8cbf3 Mon Sep 17 00:00:00 2001 From: beerpsi Date: Mon, 15 Apr 2024 20:34:30 +0700 Subject: [PATCH] CRLF -> LF --- unityhook/config.c | 24 +-- unityhook/doorstop.c | 346 +++++++++++++++++++++---------------------- unityhook/hook.c | 220 +++++++++++++-------------- 3 files changed, 295 insertions(+), 295 deletions(-) diff --git a/unityhook/config.c b/unityhook/config.c index 4de977b..3fd9289 100644 --- a/unityhook/config.c +++ b/unityhook/config.c @@ -1,12 +1,12 @@ -#include "config.h" - -void unity_config_load(struct unity_config *cfg, const wchar_t *filename) { - GetPrivateProfileStringW( - L"unity", - L"targetAssembly", - L"", - cfg->target_assembly, - _countof(cfg->target_assembly), - filename - ); -} +#include "config.h" + +void unity_config_load(struct unity_config *cfg, const wchar_t *filename) { + GetPrivateProfileStringW( + L"unity", + L"targetAssembly", + L"", + cfg->target_assembly, + _countof(cfg->target_assembly), + filename + ); +} diff --git a/unityhook/doorstop.c b/unityhook/doorstop.c index 38424d5..07b6799 100644 --- a/unityhook/doorstop.c +++ b/unityhook/doorstop.c @@ -1,173 +1,173 @@ -// A simplified version of NeighTools' UnityDoorstop, allowing mod loaders -// like BepInEx to be loaded into Unity games. -// -// SPDX-License-Identifier: CC0 -// https://github.com/NeighTools/UnityDoorstop -#include - -#include -#include - -#include "hooklib/procaddr.h" -#include "util/dprintf.h" - -#include "doorstop.h" -#include "mono.h" -#include "util.h" - -static void * my_mono_jit_init_version(const char *root_domain_name, const char *runtime_version); -void doorstop_invoke(void *domain); - -static char module_name[MAX_PATH]; -static bool doorstop_hook_initted; -static struct unity_config unity_config; -static struct hook_symbol unity_mono_syms[] = { -{ - .name = "mono_jit_init_version", - .patch = my_mono_jit_init_version, - } -}; - -void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module) { - if (doorstop_hook_initted || cfg->target_assembly[0] == 0) { - return; - } - - GetModuleBaseNameA(GetCurrentProcess(), module, module_name, MAX_PATH); - - memcpy(&unity_config, cfg, sizeof(*cfg)); - load_mono_functions(module); - proc_addr_table_push(module_name, unity_mono_syms, _countof(unity_mono_syms)); - - doorstop_hook_initted = true; -} - -static void * my_mono_jit_init_version(const char *root_domain_name, const char *runtime_version) { - dprintf("Unity: Starting Mono domain \"%s\"\n", root_domain_name); - - SetEnvironmentVariableW(L"DOORSTOP_DLL_SEARCH_DIRS", widen(mono_assembly_getrootdir())); - - void* domain = mono_jit_init_version(root_domain_name, runtime_version); - - doorstop_invoke(domain); - return domain; -} - -void doorstop_invoke(void* domain) { - if (GetEnvironmentVariableW(L"DOORSTOP_INITIALIZED", NULL, 0) != 0) { - dprintf("Unity: Doorstop is already initialized.\n"); - return; - } - - SetEnvironmentVariableW(L"DOORSTOP_INITIALIZED", L"TRUE"); - - mono_thread_set_main(mono_thread_current()); - - if (mono_domain_set_config) { -#define CONFIG_EXT L".config" - - wchar_t exe_path[MAX_PATH]; - size_t exe_path_len = GetModuleFileNameW(NULL, exe_path, MAX_PATH); - wchar_t *folder_name = wcsdup(exe_path); - - PathCchRemoveFileSpec(folder_name, exe_path_len + 1); - - char *exe_path_n = narrow(exe_path); - char *folder_name_n = narrow(folder_name); - - dprintf("Unity: Setting config paths: base dir: %s; config path: %s\n", folder_name_n, exe_path_n); - - mono_domain_set_config(domain, folder_name_n, exe_path_n); - - free(folder_name); - free(exe_path_n); - free(folder_name_n); - -#undef CONFIG_EXT - } - - SetEnvironmentVariableW(L"DOORSTOP_INVOKE_DLL_PATH", unity_config.target_assembly); - - char *assembly_dir = mono_assembly_getrootdir(); - dprintf("Unity: Assembly directory: %s\n", assembly_dir); - - SetEnvironmentVariableA("DOORSTOP_MANAGED_FOLDER_DIR", assembly_dir); - - wchar_t app_path[MAX_PATH]; - GetModuleFileNameW(NULL, app_path, MAX_PATH); - SetEnvironmentVariableW(L"DOORSTOP_PROCESS_PATH", app_path); - - char* dll_path = narrow(unity_config.target_assembly); - - dprintf("Unity: Loading assembly: %s\n", dll_path); - - void* assembly = mono_domain_assembly_open(domain, dll_path); - - if (!assembly) { - dprintf("Unity: Failed to load assembly\n"); - free(dll_path); - return; - } - - void *image = mono_assembly_get_image(assembly); - - if (!image) { - dprintf("Unity: Assembly image doesn't exist\n"); - free(dll_path); - return; - } - - void *desc = mono_method_desc_new("*:Main", FALSE); - void *method = mono_method_desc_search_in_image(desc, image); - - if (!method) { - dprintf("Unity: Assembly does not have a valid entrypoint.\n"); - free(dll_path); - return; - } - - void *signature = mono_method_signature(method); - UINT32 params = mono_signature_get_param_count(signature); - void **args = NULL; - - if (params == 1) { - // If there is a parameter, it's most likely a string[]. - void *args_array = mono_array_new(domain, mono_get_string_class(), 0); - args = malloc(sizeof(void*) * 1); - args[0] = args_array; - } - - dprintf("Unity: Invoking method %p\n", method); - - void *exc = NULL; - mono_runtime_invoke(method, NULL, args, &exc); - - if (exc) { - dprintf("Unity: Error invoking method!\n"); - - void *ex_class = mono_get_exception_class(); - void *to_string_desc = mono_method_desc_new("*:ToString()", FALSE); - void* to_string_method = mono_method_desc_search_in_class(to_string_desc, ex_class); - - mono_method_desc_free(to_string_desc); - - if (to_string_method) { - void* real_to_string_method = mono_object_get_virtual_method(exc, to_string_method); - void* exc2 = NULL; - void* str = mono_runtime_invoke(real_to_string_method, exc, NULL, &exc2); - - if (!exc2) { - char* exc_str = mono_string_to_utf8(str); - dprintf("Unity: Error message: %s\n", exc_str); - } - } - } - - mono_method_desc_free(desc); - free(dll_path); - - if (args) { - free(args); - args = NULL; - } -} +// A simplified version of NeighTools' UnityDoorstop, allowing mod loaders +// like BepInEx to be loaded into Unity games. +// +// SPDX-License-Identifier: CC0 +// https://github.com/NeighTools/UnityDoorstop +#include + +#include +#include + +#include "hooklib/procaddr.h" +#include "util/dprintf.h" + +#include "doorstop.h" +#include "mono.h" +#include "util.h" + +static void * my_mono_jit_init_version(const char *root_domain_name, const char *runtime_version); +void doorstop_invoke(void *domain); + +static char module_name[MAX_PATH]; +static bool doorstop_hook_initted; +static struct unity_config unity_config; +static struct hook_symbol unity_mono_syms[] = { +{ + .name = "mono_jit_init_version", + .patch = my_mono_jit_init_version, + } +}; + +void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module) { + if (doorstop_hook_initted || cfg->target_assembly[0] == 0) { + return; + } + + GetModuleBaseNameA(GetCurrentProcess(), module, module_name, MAX_PATH); + + memcpy(&unity_config, cfg, sizeof(*cfg)); + load_mono_functions(module); + proc_addr_table_push(module_name, unity_mono_syms, _countof(unity_mono_syms)); + + doorstop_hook_initted = true; +} + +static void * my_mono_jit_init_version(const char *root_domain_name, const char *runtime_version) { + dprintf("Unity: Starting Mono domain \"%s\"\n", root_domain_name); + + SetEnvironmentVariableW(L"DOORSTOP_DLL_SEARCH_DIRS", widen(mono_assembly_getrootdir())); + + void* domain = mono_jit_init_version(root_domain_name, runtime_version); + + doorstop_invoke(domain); + return domain; +} + +void doorstop_invoke(void* domain) { + if (GetEnvironmentVariableW(L"DOORSTOP_INITIALIZED", NULL, 0) != 0) { + dprintf("Unity: Doorstop is already initialized.\n"); + return; + } + + SetEnvironmentVariableW(L"DOORSTOP_INITIALIZED", L"TRUE"); + + mono_thread_set_main(mono_thread_current()); + + if (mono_domain_set_config) { +#define CONFIG_EXT L".config" + + wchar_t exe_path[MAX_PATH]; + size_t exe_path_len = GetModuleFileNameW(NULL, exe_path, MAX_PATH); + wchar_t *folder_name = wcsdup(exe_path); + + PathCchRemoveFileSpec(folder_name, exe_path_len + 1); + + char *exe_path_n = narrow(exe_path); + char *folder_name_n = narrow(folder_name); + + dprintf("Unity: Setting config paths: base dir: %s; config path: %s\n", folder_name_n, exe_path_n); + + mono_domain_set_config(domain, folder_name_n, exe_path_n); + + free(folder_name); + free(exe_path_n); + free(folder_name_n); + +#undef CONFIG_EXT + } + + SetEnvironmentVariableW(L"DOORSTOP_INVOKE_DLL_PATH", unity_config.target_assembly); + + char *assembly_dir = mono_assembly_getrootdir(); + dprintf("Unity: Assembly directory: %s\n", assembly_dir); + + SetEnvironmentVariableA("DOORSTOP_MANAGED_FOLDER_DIR", assembly_dir); + + wchar_t app_path[MAX_PATH]; + GetModuleFileNameW(NULL, app_path, MAX_PATH); + SetEnvironmentVariableW(L"DOORSTOP_PROCESS_PATH", app_path); + + char* dll_path = narrow(unity_config.target_assembly); + + dprintf("Unity: Loading assembly: %s\n", dll_path); + + void* assembly = mono_domain_assembly_open(domain, dll_path); + + if (!assembly) { + dprintf("Unity: Failed to load assembly\n"); + free(dll_path); + return; + } + + void *image = mono_assembly_get_image(assembly); + + if (!image) { + dprintf("Unity: Assembly image doesn't exist\n"); + free(dll_path); + return; + } + + void *desc = mono_method_desc_new("*:Main", FALSE); + void *method = mono_method_desc_search_in_image(desc, image); + + if (!method) { + dprintf("Unity: Assembly does not have a valid entrypoint.\n"); + free(dll_path); + return; + } + + void *signature = mono_method_signature(method); + UINT32 params = mono_signature_get_param_count(signature); + void **args = NULL; + + if (params == 1) { + // If there is a parameter, it's most likely a string[]. + void *args_array = mono_array_new(domain, mono_get_string_class(), 0); + args = malloc(sizeof(void*) * 1); + args[0] = args_array; + } + + dprintf("Unity: Invoking method %p\n", method); + + void *exc = NULL; + mono_runtime_invoke(method, NULL, args, &exc); + + if (exc) { + dprintf("Unity: Error invoking method!\n"); + + void *ex_class = mono_get_exception_class(); + void *to_string_desc = mono_method_desc_new("*:ToString()", FALSE); + void* to_string_method = mono_method_desc_search_in_class(to_string_desc, ex_class); + + mono_method_desc_free(to_string_desc); + + if (to_string_method) { + void* real_to_string_method = mono_object_get_virtual_method(exc, to_string_method); + void* exc2 = NULL; + void* str = mono_runtime_invoke(real_to_string_method, exc, NULL, &exc2); + + if (!exc2) { + char* exc_str = mono_string_to_utf8(str); + dprintf("Unity: Error message: %s\n", exc_str); + } + } + } + + mono_method_desc_free(desc); + free(dll_path); + + if (args) { + free(args); + args = NULL; + } +} diff --git a/unityhook/hook.c b/unityhook/hook.c index caf950f..aa0deb0 100644 --- a/unityhook/hook.c +++ b/unityhook/hook.c @@ -1,110 +1,110 @@ -#include -#include - -#include "hook/table.h" -#include "hooklib/path.h" -#include "util/dprintf.h" - -#include "doorstop.h" -#include "hook.h" - -static bool unity_hook_initted; -static struct unity_config unity_config; - -static const wchar_t *target_modules[] = { - L"mono.dll", - L"mono-2.0-bdwgc.dll", - L"cri_ware_unity.dll", -}; -static const size_t target_modules_len = _countof(target_modules); - -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, - }, -}; - -void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) { - assert(cfg != NULL); - - if (unity_hook_initted) { - return; - } - - memcpy(&unity_config, cfg, sizeof(*cfg)); - dll_hook_insert_hooks(NULL); - - unity_hook_initted = true; - dprintf("Unity: Hook enabled.\n"); -} - -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); - - // mono entrypoint for injecting target_assembly - if (GetProcAddress(result, "mono_jit_init_version")) { - doorstop_mono_hook_init(&unity_config, result); - } - - 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; -} +#include +#include + +#include "hook/table.h" +#include "hooklib/path.h" +#include "util/dprintf.h" + +#include "doorstop.h" +#include "hook.h" + +static bool unity_hook_initted; +static struct unity_config unity_config; + +static const wchar_t *target_modules[] = { + L"mono.dll", + L"mono-2.0-bdwgc.dll", + L"cri_ware_unity.dll", +}; +static const size_t target_modules_len = _countof(target_modules); + +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, + }, +}; + +void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) { + assert(cfg != NULL); + + if (unity_hook_initted) { + return; + } + + memcpy(&unity_config, cfg, sizeof(*cfg)); + dll_hook_insert_hooks(NULL); + + unity_hook_initted = true; + dprintf("Unity: Hook enabled.\n"); +} + +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); + + // mono entrypoint for injecting target_assembly + if (GetProcAddress(result, "mono_jit_init_version")) { + doorstop_mono_hook_init(&unity_config, result); + } + + 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; +}