forked from Hay1tsme/segatools
mai2/mu3/cm: Integrate UnityDoorstop with segatools #11
@ -40,4 +40,5 @@ void cm_hook_config_load(
|
|||||||
vfd_config_load(&cfg->vfd, filename);
|
vfd_config_load(&cfg->vfd, filename);
|
||||||
touch_screen_config_load(&cfg->touch, filename);
|
touch_screen_config_load(&cfg->touch, filename);
|
||||||
cm_dll_config_load(&cfg->dll, filename);
|
cm_dll_config_load(&cfg->dll, filename);
|
||||||
|
unity_config_load(&cfg->unity, filename);
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include "platform/config.h"
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
#include "unityhook/config.h"
|
||||||
|
|
||||||
struct cm_hook_config {
|
struct cm_hook_config {
|
||||||
struct platform_config platform;
|
struct platform_config platform;
|
||||||
struct aime_config aime;
|
struct aime_config aime;
|
||||||
@ -19,6 +21,7 @@ struct cm_hook_config {
|
|||||||
struct vfd_config vfd;
|
struct vfd_config vfd;
|
||||||
struct cm_dll_config dll;
|
struct cm_dll_config dll;
|
||||||
struct touch_screen_config touch;
|
struct touch_screen_config touch;
|
||||||
|
struct unity_config unity;
|
||||||
};
|
};
|
||||||
|
|
||||||
void cm_dll_config_load(
|
void cm_dll_config_load(
|
||||||
|
@ -16,10 +16,11 @@
|
|||||||
#include "cmhook/config.h"
|
#include "cmhook/config.h"
|
||||||
#include "cmhook/io4.h"
|
#include "cmhook/io4.h"
|
||||||
#include "cmhook/cm-dll.h"
|
#include "cmhook/cm-dll.h"
|
||||||
#include "cmhook/unity.h"
|
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
|
#include "unityhook/hook.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
static HMODULE cm_hook_mod;
|
static HMODULE cm_hook_mod;
|
||||||
@ -83,7 +84,7 @@ static DWORD CALLBACK cm_pre_startup(void)
|
|||||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||||
hooked earlier in the `cmhook` initialization. */
|
hooked earlier in the `cmhook` initialization. */
|
||||||
|
|
||||||
unity_hook_init();
|
unity_hook_init(&cm_hook_cfg.unity, cm_hook_mod);
|
||||||
|
|
||||||
/* Initialize debug helpers */
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ shared_library(
|
|||||||
hooklib_lib,
|
hooklib_lib,
|
||||||
cmio_lib,
|
cmio_lib,
|
||||||
platform_lib,
|
platform_lib,
|
||||||
|
unityhook_lib,
|
||||||
util_lib,
|
util_lib,
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
@ -26,7 +27,5 @@ shared_library(
|
|||||||
'io4.h',
|
'io4.h',
|
||||||
'cm-dll.c',
|
'cm-dll.c',
|
||||||
'cm-dll.h',
|
'cm-dll.h',
|
||||||
'unity.h',
|
|
||||||
'unity.c',
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void unity_hook_init(void);
|
|
5
dist/cm/segatools.ini
vendored
5
dist/cm/segatools.ini
vendored
@ -68,6 +68,11 @@ dipsw1=0
|
|||||||
; Enable/Disable WinTouch emulation
|
; Enable/Disable WinTouch emulation
|
||||||
enable=0
|
enable=0
|
||||||
|
|
||||||
|
[unity]
|
||||||
|
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||||
|
; modding frameworks such as BepInEx.
|
||||||
|
targetAssembly=
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Custom IO settings
|
; Custom IO settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
9
dist/mai2/segatools.ini
vendored
9
dist/mai2/segatools.ini
vendored
@ -83,6 +83,15 @@ path=
|
|||||||
; Leave empty if you want to use Segatools built-in keyboard input.
|
; Leave empty if you want to use Segatools built-in keyboard input.
|
||||||
path=
|
path=
|
||||||
|
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
; Misc. hook settings
|
||||||
|
; -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[unity]
|
||||||
|
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||||
|
; modding frameworks such as BepInEx.
|
||||||
|
targetAssembly=
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Input settings
|
; Input settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
5
dist/mu3/segatools.ini
vendored
5
dist/mu3/segatools.ini
vendored
@ -72,6 +72,11 @@ dipsw1=1
|
|||||||
[gfx]
|
[gfx]
|
||||||
enable=1
|
enable=1
|
||||||
|
|
||||||
|
[unity]
|
||||||
|
; Path to a .NET DLL that should run before the game. Useful for loading
|
||||||
|
; modding frameworks such as BepInEx.
|
||||||
|
targetAssembly=
|
||||||
|
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
; Custom IO settings
|
; Custom IO settings
|
||||||
; -----------------------------------------------------------------------------
|
; -----------------------------------------------------------------------------
|
||||||
|
@ -39,4 +39,5 @@ void mai2_hook_config_load(
|
|||||||
io4_config_load(&cfg->io4, filename);
|
io4_config_load(&cfg->io4, filename);
|
||||||
vfd_config_load(&cfg->vfd, filename);
|
vfd_config_load(&cfg->vfd, filename);
|
||||||
mai2_dll_config_load(&cfg->dll, filename);
|
mai2_dll_config_load(&cfg->dll, filename);
|
||||||
|
unity_config_load(&cfg->unity, filename);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "platform/config.h"
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
#include "unityhook/config.h"
|
||||||
|
|
||||||
struct mai2_hook_config {
|
struct mai2_hook_config {
|
||||||
struct platform_config platform;
|
struct platform_config platform;
|
||||||
struct aime_config aime;
|
struct aime_config aime;
|
||||||
@ -17,6 +19,7 @@ struct mai2_hook_config {
|
|||||||
struct io4_config io4;
|
struct io4_config io4;
|
||||||
struct vfd_config vfd;
|
struct vfd_config vfd;
|
||||||
struct mai2_dll_config dll;
|
struct mai2_dll_config dll;
|
||||||
|
struct unity_config unity;
|
||||||
};
|
};
|
||||||
|
|
||||||
void mai2_dll_config_load(
|
void mai2_dll_config_load(
|
||||||
|
@ -12,10 +12,11 @@
|
|||||||
#include "mai2hook/config.h"
|
#include "mai2hook/config.h"
|
||||||
#include "mai2hook/io4.h"
|
#include "mai2hook/io4.h"
|
||||||
#include "mai2hook/mai2-dll.h"
|
#include "mai2hook/mai2-dll.h"
|
||||||
#include "mai2hook/unity.h"
|
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
|
#include "unityhook/hook.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
static HMODULE mai2_hook_mod;
|
static HMODULE mai2_hook_mod;
|
||||||
@ -80,7 +81,7 @@ static DWORD CALLBACK mai2_pre_startup(void)
|
|||||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||||
hooked earlier in the `mai2hook` initialization. */
|
hooked earlier in the `mai2hook` initialization. */
|
||||||
|
|
||||||
unity_hook_init();
|
unity_hook_init(&mai2_hook_cfg.unity, mai2_hook_mod);
|
||||||
|
|
||||||
/* Initialize debug helpers */
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ shared_library(
|
|||||||
hooklib_lib,
|
hooklib_lib,
|
||||||
mai2io_lib,
|
mai2io_lib,
|
||||||
platform_lib,
|
platform_lib,
|
||||||
|
unityhook_lib,
|
||||||
util_lib,
|
util_lib,
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
@ -25,7 +26,5 @@ shared_library(
|
|||||||
'io4.h',
|
'io4.h',
|
||||||
'mai2-dll.c',
|
'mai2-dll.c',
|
||||||
'mai2-dll.h',
|
'mai2-dll.h',
|
||||||
'unity.h',
|
|
||||||
'unity.c',
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void unity_hook_init(void);
|
|
@ -42,6 +42,7 @@ shlwapi_lib = cc.find_library('shlwapi')
|
|||||||
dinput8_lib = cc.find_library('dinput8')
|
dinput8_lib = cc.find_library('dinput8')
|
||||||
dxguid_lib = cc.find_library('dxguid')
|
dxguid_lib = cc.find_library('dxguid')
|
||||||
xinput_lib = cc.find_library('xinput')
|
xinput_lib = cc.find_library('xinput')
|
||||||
|
pathcch_lib = cc.find_library('pathcch')
|
||||||
|
|
||||||
inc = include_directories('.')
|
inc = include_directories('.')
|
||||||
capnhook = subproject('capnhook')
|
capnhook = subproject('capnhook')
|
||||||
@ -55,6 +56,7 @@ subdir('platform')
|
|||||||
subdir('util')
|
subdir('util')
|
||||||
|
|
||||||
subdir('gfxhook')
|
subdir('gfxhook')
|
||||||
|
subdir('unityhook')
|
||||||
|
|
||||||
subdir('aimeio')
|
subdir('aimeio')
|
||||||
subdir('chuniio')
|
subdir('chuniio')
|
||||||
|
@ -42,4 +42,5 @@ void mu3_hook_config_load(
|
|||||||
gfx_config_load(&cfg->gfx, filename);
|
gfx_config_load(&cfg->gfx, filename);
|
||||||
vfd_config_load(&cfg->vfd, filename);
|
vfd_config_load(&cfg->vfd, filename);
|
||||||
mu3_dll_config_load(&cfg->dll, filename);
|
mu3_dll_config_load(&cfg->dll, filename);
|
||||||
|
unity_config_load(&cfg->unity, filename);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include "platform/config.h"
|
#include "platform/config.h"
|
||||||
|
|
||||||
|
#include "unityhook/config.h"
|
||||||
|
|
||||||
struct mu3_hook_config {
|
struct mu3_hook_config {
|
||||||
struct platform_config platform;
|
struct platform_config platform;
|
||||||
struct aime_config aime;
|
struct aime_config aime;
|
||||||
@ -22,6 +24,7 @@ struct mu3_hook_config {
|
|||||||
// struct led15093_config led15093;
|
// struct led15093_config led15093;
|
||||||
struct vfd_config vfd;
|
struct vfd_config vfd;
|
||||||
struct mu3_dll_config dll;
|
struct mu3_dll_config dll;
|
||||||
|
struct unity_config unity;
|
||||||
};
|
};
|
||||||
|
|
||||||
void mu3_dll_config_load(
|
void mu3_dll_config_load(
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "board/io4.h"
|
|
||||||
#include "board/sg-reader.h"
|
#include "board/sg-reader.h"
|
||||||
#include "board/vfd.h"
|
#include "board/vfd.h"
|
||||||
|
|
||||||
@ -20,10 +19,12 @@
|
|||||||
#include "mu3hook/config.h"
|
#include "mu3hook/config.h"
|
||||||
#include "mu3hook/io4.h"
|
#include "mu3hook/io4.h"
|
||||||
#include "mu3hook/mu3-dll.h"
|
#include "mu3hook/mu3-dll.h"
|
||||||
#include "mu3hook/unity.h"
|
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
|
#include "unityhook/config.h"
|
||||||
|
#include "unityhook/hook.h"
|
||||||
|
|
||||||
#include "util/dprintf.h"
|
#include "util/dprintf.h"
|
||||||
|
|
||||||
static HMODULE mu3_hook_mod;
|
static HMODULE mu3_hook_mod;
|
||||||
@ -99,7 +100,7 @@ static DWORD CALLBACK mu3_pre_startup(void)
|
|||||||
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
There seems to be an issue with other DLL hooks if `LoadLibraryW` is
|
||||||
hooked earlier in the `mu3hook` initialization. */
|
hooked earlier in the `mu3hook` initialization. */
|
||||||
|
|
||||||
unity_hook_init();
|
unity_hook_init(&mu3_hook_cfg.unity, mu3_hook_mod);
|
||||||
|
|
||||||
/* Initialize debug helpers */
|
/* Initialize debug helpers */
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ shared_library(
|
|||||||
hooklib_lib,
|
hooklib_lib,
|
||||||
mu3io_lib,
|
mu3io_lib,
|
||||||
platform_lib,
|
platform_lib,
|
||||||
|
unityhook_lib,
|
||||||
util_lib,
|
util_lib,
|
||||||
],
|
],
|
||||||
sources : [
|
sources : [
|
||||||
@ -27,7 +28,5 @@ shared_library(
|
|||||||
'io4.h',
|
'io4.h',
|
||||||
'mu3-dll.c',
|
'mu3-dll.c',
|
||||||
'mu3-dll.h',
|
'mu3-dll.h',
|
||||||
'unity.h',
|
|
||||||
'unity.c',
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void unity_hook_init(void);
|
|
14
unityhook/config.c
Normal file
14
unityhook/config.c
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
void unity_config_load(struct unity_config *cfg, const wchar_t *filename) {
|
||||||
|
cfg->enable = GetPrivateProfileIntW(L"unity", L"enable", 1, filename);
|
||||||
|
|
||||||
|
GetPrivateProfileStringW(
|
||||||
|
L"unity",
|
||||||
|
L"targetAssembly",
|
||||||
|
L"",
|
||||||
|
cfg->target_assembly,
|
||||||
|
_countof(cfg->target_assembly),
|
||||||
|
filename
|
||||||
|
);
|
||||||
|
}
|
12
unityhook/config.h
Normal file
12
unityhook/config.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
struct unity_config {
|
||||||
|
bool enable;
|
||||||
|
wchar_t target_assembly[MAX_PATH];
|
||||||
|
};
|
||||||
|
|
||||||
|
void unity_config_load(struct unity_config *cfg, const wchar_t *filename);
|
173
unityhook/doorstop.c
Normal file
173
unityhook/doorstop.c
Normal file
@ -0,0 +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 <stdbool.h>
|
||||||
|
|
||||||
|
#include <pathcch.h>
|
||||||
|
#include <psapi.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
5
unityhook/doorstop.h
Normal file
5
unityhook/doorstop.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
void doorstop_mono_hook_init(const struct unity_config *cfg, HINSTANCE module);
|
@ -1,14 +1,23 @@
|
|||||||
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include "hook/table.h"
|
#include "hook/table.h"
|
||||||
|
|
||||||
#include "hooklib/dll.h"
|
|
||||||
#include "hooklib/path.h"
|
#include "hooklib/path.h"
|
||||||
|
|
||||||
#include "util/dprintf.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 void dll_hook_insert_hooks(HMODULE target);
|
||||||
|
|
||||||
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name);
|
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name);
|
||||||
@ -22,19 +31,25 @@ static const struct hook_symbol unity_kernel32_syms[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const wchar_t *target_modules[] = {
|
void unity_hook_init(const struct unity_config *cfg, HINSTANCE self) {
|
||||||
L"mono-2.0-bdwgc.dll",
|
assert(cfg != NULL);
|
||||||
L"cri_ware_unity.dll",
|
|
||||||
};
|
|
||||||
static const size_t target_modules_len = _countof(target_modules);
|
|
||||||
|
|
||||||
void unity_hook_init(void)
|
if (!cfg->enable) {
|
||||||
{
|
return;
|
||||||
dll_hook_insert_hooks(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dll_hook_insert_hooks(HMODULE target)
|
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(
|
hook_table_apply(
|
||||||
target,
|
target,
|
||||||
"kernel32.dll",
|
"kernel32.dll",
|
||||||
@ -42,8 +57,7 @@ static void dll_hook_insert_hooks(HMODULE target)
|
|||||||
_countof(unity_kernel32_syms));
|
_countof(unity_kernel32_syms));
|
||||||
}
|
}
|
||||||
|
|
||||||
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name)
|
static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name) {
|
||||||
{
|
|
||||||
const wchar_t *name_end;
|
const wchar_t *name_end;
|
||||||
const wchar_t *target_module;
|
const wchar_t *target_module;
|
||||||
bool already_loaded;
|
bool already_loaded;
|
||||||
@ -66,6 +80,11 @@ static HMODULE WINAPI my_LoadLibraryW(const wchar_t *name)
|
|||||||
if (!already_loaded && result != NULL) {
|
if (!already_loaded && result != NULL) {
|
||||||
name_len = wcslen(name);
|
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++) {
|
for (size_t i = 0; i < target_modules_len; i++) {
|
||||||
target_module = target_modules[i];
|
target_module = target_modules[i];
|
||||||
target_module_len = wcslen(target_module);
|
target_module_len = wcslen(target_module);
|
7
unityhook/hook.h
Normal file
7
unityhook/hook.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
void unity_hook_init(const struct unity_config *cfg, HINSTANCE self);
|
20
unityhook/meson.build
Normal file
20
unityhook/meson.build
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
unityhook_lib = static_library(
|
||||||
|
'unityhook',
|
||||||
|
include_directories: inc,
|
||||||
|
implicit_include_directories: false,
|
||||||
|
c_pch: '../precompiled.h',
|
||||||
|
dependencies: [
|
||||||
|
capnhook.get_variable('hook_dep'),
|
||||||
|
pathcch_lib
|
||||||
|
],
|
||||||
|
sources: [
|
||||||
|
'mono.h',
|
||||||
|
'config.c',
|
||||||
|
'config.h',
|
||||||
|
'doorstop.c',
|
||||||
|
'doorstop.h',
|
||||||
|
'hook.c',
|
||||||
|
'hook.h',
|
||||||
|
'util.h'
|
||||||
|
],
|
||||||
|
)
|
100
unityhook/mono.h
Normal file
100
unityhook/mono.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// SPDX-License-Identifier: CC0
|
||||||
|
// https://github.com/NeighTools/UnityDoorstop
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// Here we define the pointers to some functions within mono.dll
|
||||||
|
// Note to C learners: these are not signature definitions, but rather "variable"
|
||||||
|
// definitions with the function pointer type.
|
||||||
|
|
||||||
|
// Note: we use void* instead of the real intented structs defined in mono API
|
||||||
|
// This way we don't need to include or define any of Mono's structs, which saves space
|
||||||
|
// This, obviously, comes with a drawback of not being able to easily access the contents of the structs
|
||||||
|
|
||||||
|
void * (*mono_thread_current)();
|
||||||
|
void (*mono_thread_set_main)(void *);
|
||||||
|
|
||||||
|
void *(*mono_jit_init_version)(const char *root_domain_name, const char *runtime_version);
|
||||||
|
void *(*mono_domain_assembly_open)(void *domain, const char *name);
|
||||||
|
void *(*mono_assembly_get_image)(void *assembly);
|
||||||
|
void *(*mono_runtime_invoke)(void *method, void *obj, void **params, void **exc);
|
||||||
|
|
||||||
|
void *(*mono_method_desc_new)(const char *name, int include_namespace);
|
||||||
|
void* (*mono_method_desc_search_in_image)(void* desc, void* image);
|
||||||
|
void *(*mono_method_desc_search_in_class)(void *desc, void *klass);
|
||||||
|
void (*mono_method_desc_free)(void *desc);
|
||||||
|
void *(*mono_method_signature)(void *method);
|
||||||
|
UINT32 (*mono_signature_get_param_count)(void *sig);
|
||||||
|
|
||||||
|
void (*mono_domain_set_config)(void *domain, char *base_dir, char *config_file_name);
|
||||||
|
void *(*mono_array_new)(void *domain, void *eclass, uintptr_t n);
|
||||||
|
void *(*mono_get_string_class)();
|
||||||
|
|
||||||
|
char *(*mono_assembly_getrootdir)();
|
||||||
|
|
||||||
|
// Additional funcs to bootstrap custom MONO
|
||||||
|
void (*mono_set_dirs)(const char* assembly_dir, const char* config_dir);
|
||||||
|
void (*mono_config_parse)(const char* filename);
|
||||||
|
void (*mono_set_assemblies_path)(const char* path);
|
||||||
|
void *(*mono_object_to_string)(void* obj, void** exc);
|
||||||
|
char *(*mono_string_to_utf8)(void* s);
|
||||||
|
|
||||||
|
void *(*mono_image_open_from_data_with_name)(void *data, DWORD data_len, int need_copy, void *status, int refonly,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
void* (*mono_get_exception_class)();
|
||||||
|
void* (*mono_object_get_virtual_method)(void* obj_raw, void* method);
|
||||||
|
|
||||||
|
void* (*mono_jit_parse_options)(int argc, const char** argv);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MONO_DEBUG_FORMAT_NONE,
|
||||||
|
MONO_DEBUG_FORMAT_MONO,
|
||||||
|
/* Deprecated, the mdb debugger is not longer supported. */
|
||||||
|
MONO_DEBUG_FORMAT_DEBUGGER
|
||||||
|
} MonoDebugFormat;
|
||||||
|
|
||||||
|
void* (*mono_debug_init)(MonoDebugFormat format);
|
||||||
|
void* (*mono_debug_domain_create)(void* domain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Loads Mono C API function pointers so that the above definitions can be called.
|
||||||
|
* \param mono_lib Mono.dll module.
|
||||||
|
*/
|
||||||
|
void load_mono_functions(HMODULE mono_lib) {
|
||||||
|
// Enjoy the fact that C allows such sloppy casting
|
||||||
|
// In C++ you would have to cast to the precise function pointer type
|
||||||
|
#define GET_MONO_PROC(name) name = (void*)GetProcAddress(mono_lib, #name)
|
||||||
|
|
||||||
|
// Find and assign all our functions that we are going to use
|
||||||
|
GET_MONO_PROC(mono_domain_assembly_open);
|
||||||
|
GET_MONO_PROC(mono_assembly_get_image);
|
||||||
|
GET_MONO_PROC(mono_runtime_invoke);
|
||||||
|
GET_MONO_PROC(mono_jit_init_version);
|
||||||
|
GET_MONO_PROC(mono_method_desc_new);
|
||||||
|
GET_MONO_PROC(mono_method_desc_search_in_class);
|
||||||
|
GET_MONO_PROC(mono_method_desc_search_in_image);
|
||||||
|
GET_MONO_PROC(mono_method_desc_free);
|
||||||
|
GET_MONO_PROC(mono_method_signature);
|
||||||
|
GET_MONO_PROC(mono_signature_get_param_count);
|
||||||
|
GET_MONO_PROC(mono_array_new);
|
||||||
|
GET_MONO_PROC(mono_get_string_class);
|
||||||
|
GET_MONO_PROC(mono_assembly_getrootdir);
|
||||||
|
GET_MONO_PROC(mono_thread_current);
|
||||||
|
GET_MONO_PROC(mono_thread_set_main);
|
||||||
|
GET_MONO_PROC(mono_domain_set_config);
|
||||||
|
GET_MONO_PROC(mono_set_dirs);
|
||||||
|
GET_MONO_PROC(mono_config_parse);
|
||||||
|
GET_MONO_PROC(mono_set_assemblies_path);
|
||||||
|
GET_MONO_PROC(mono_object_to_string);
|
||||||
|
GET_MONO_PROC(mono_string_to_utf8);
|
||||||
|
GET_MONO_PROC(mono_image_open_from_data_with_name);
|
||||||
|
GET_MONO_PROC(mono_get_exception_class);
|
||||||
|
GET_MONO_PROC(mono_object_get_virtual_method);
|
||||||
|
GET_MONO_PROC(mono_jit_parse_options);
|
||||||
|
GET_MONO_PROC(mono_debug_init);
|
||||||
|
GET_MONO_PROC(mono_debug_domain_create);
|
||||||
|
|
||||||
|
#undef GET_MONO_PROC
|
||||||
|
}
|
20
unityhook/util.h
Normal file
20
unityhook/util.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
wchar_t *widen(const char *str) {
|
||||||
|
const int reqsz = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||||
|
wchar_t *result = malloc(reqsz * sizeof(wchar_t));
|
||||||
|
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, str, -1, result, reqsz);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *narrow(const wchar_t *str) {
|
||||||
|
const int reqsz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
|
||||||
|
char *result = malloc(reqsz * sizeof(char));
|
||||||
|
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, str, -1, result, reqsz, NULL, NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user