diff --git a/Module.mk b/Module.mk index c44caa0..d0f58e4 100644 --- a/Module.mk +++ b/Module.mk @@ -77,6 +77,7 @@ imps += avs avs-ea3 include src/main/aciodrv/Module.mk include src/main/acioemu/Module.mk include src/main/aciotest/Module.mk +include src/main/asiohook/Module.mk include src/main/bio2emu/Module.mk include src/main/bsthook/Module.mk include src/main/bstio/Module.mk diff --git a/src/main/asiohook/Module.mk b/src/main/asiohook/Module.mk new file mode 100644 index 0000000..9707fb4 --- /dev/null +++ b/src/main/asiohook/Module.mk @@ -0,0 +1,9 @@ +libs += asiohook + +libs_asiohook := \ + hook \ + hooklib \ + util \ + +src_asiohook := \ + asio-reghook.c \ diff --git a/src/main/asiohook/asio-reghook.c b/src/main/asiohook/asio-reghook.c new file mode 100644 index 0000000..f64d5f2 --- /dev/null +++ b/src/main/asiohook/asio-reghook.c @@ -0,0 +1,199 @@ +#define LOG_MODULE "asio-reghook" + +// clang-format off +// Don't format because the order is important here +#include +#include +// clang-format on + +#include + +#include + +#include "hook/com-proxy.h" +#include "hook/table.h" + +#include "asiohook/asio-reghook.h" + +#include "util/defs.h" +#include "util/log.h" +#include "util/str.h" +#include "util/time.h" + +// MAXDRVNAMELEN +#define ASIO_NAME_STRING_SIZE 128 + +static char asio_expected_name[ASIO_NAME_STRING_SIZE] = "XONAR SOUND CARD(64)"; +static char asio_target_name[ASIO_NAME_STRING_SIZE] = "XONAR SOUND CARD(64)"; +static HKEY asio_root_key; +static HKEY asio_sub_key; + +LSTATUS my_RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult); + +LSTATUS my_RegEnumKeyA(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName); + +LSTATUS my_RegOpenKeyExA( + HKEY hKey, + LPCSTR lpSubKey, + DWORD ulOptions, + REGSAM samDesired, + PHKEY phkResult); + +LSTATUS my_RegQueryValueExA( + HKEY hKey, + LPCSTR lpValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData); + +LSTATUS my_RegCloseKey(HKEY hKey); + +LSTATUS (*real_RegOpenKeyA)(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult); + +LSTATUS (*real_RegEnumKeyA) +(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName); + +LSTATUS (*real_RegOpenKeyExA) +(HKEY hKey, + LPCSTR lpSubKey, + DWORD ulOptions, + REGSAM samDesired, + PHKEY phkResult); + +LSTATUS (*real_RegQueryValueExA) +(HKEY hKey, + LPCSTR lpValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData); + +LSTATUS (*real_RegCloseKey)(HKEY hKey); + +static const struct hook_symbol asio_reghook_advapi32_syms[] = { + {.name = "RegOpenKeyA", + .patch = my_RegOpenKeyA, + .link = (void **) &real_RegOpenKeyA}, + {.name = "RegEnumKeyA", + .patch = my_RegEnumKeyA, + .link = (void **) &real_RegEnumKeyA}, + {.name = "RegOpenKeyExA", + .patch = my_RegOpenKeyExA, + .link = (void **) &real_RegOpenKeyExA}, + {.name = "RegQueryValueExA", + .patch = my_RegQueryValueExA, + .link = (void **) &real_RegQueryValueExA}, + {.name = "RegCloseKey", + .patch = my_RegCloseKey, + .link = (void **) &real_RegCloseKey}, +}; + +LSTATUS my_RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) +{ + LSTATUS result = real_RegOpenKeyA(hKey, lpSubKey, phkResult); + + if (!strcmp("software\\asio", lpSubKey)) { + log_info("ASIO root key found"); + asio_root_key = *phkResult; + } + + return result; +} + +LSTATUS my_RegEnumKeyA(HKEY hKey, DWORD dwIndex, LPSTR lpName, DWORD cchName) +{ + LSTATUS result = real_RegEnumKeyA(hKey, dwIndex, lpName, cchName); + + if (hKey == asio_root_key) { + if (!strcmp(asio_target_name, lpName)) { + log_info( + "Replacing key [%s] with [%s]", + asio_target_name, + asio_expected_name); + strncpy(lpName, asio_expected_name, cchName); + } + } + + return result; +} + +LSTATUS my_RegOpenKeyExA( + HKEY hKey, + LPCSTR lpSubKey, + DWORD ulOptions, + REGSAM samDesired, + PHKEY phkResult) +{ + if (hKey == asio_root_key) { + if (!strcmp(asio_expected_name, lpSubKey)) { + // swap to the real one so the call succeeds + LSTATUS result = real_RegOpenKeyExA( + hKey, asio_target_name, ulOptions, samDesired, phkResult); + + asio_sub_key = *phkResult; + log_info("ASIO device key found"); + + return result; + } + } + + return real_RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult); +} + +LSTATUS my_RegQueryValueExA( + HKEY hKey, + LPCSTR lpValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData) +{ + DWORD lpcbData_orig = *lpcbData; + LSTATUS result = real_RegQueryValueExA( + hKey, lpValueName, lpReserved, lpType, lpData, lpcbData); + + if (result == ERROR_SUCCESS) { + if (hKey == asio_sub_key) { + if (!strcmp("description", lpValueName)) { + log_info( + "Replacing description [%s] with [%s]", + lpData, + asio_expected_name); + strncpy((char *) lpData, asio_expected_name, lpcbData_orig); + } + } + } + + return result; +} + +LSTATUS my_RegCloseKey(HKEY hKey) +{ + if (hKey == asio_root_key) { + asio_root_key = NULL; + } + + if (hKey == asio_sub_key) { + asio_sub_key = NULL; + } + + return real_RegCloseKey(hKey); +} + +void asio_reghook_init(const char *expected_name, const char *target_name) +{ + strncpy(asio_expected_name, expected_name, ASIO_NAME_STRING_SIZE - 1); + strncpy(asio_target_name, target_name, ASIO_NAME_STRING_SIZE - 1); + + asio_expected_name[ASIO_NAME_STRING_SIZE - 1] = '\0'; + asio_target_name[ASIO_NAME_STRING_SIZE - 1] = '\0'; + + hook_table_apply( + NULL, + "Advapi32.dll", + asio_reghook_advapi32_syms, + lengthof(asio_reghook_advapi32_syms)); + + log_info("Inserted reg hooks for ASIO override"); +} diff --git a/src/main/asiohook/asio-reghook.h b/src/main/asiohook/asio-reghook.h new file mode 100644 index 0000000..cc74e61 --- /dev/null +++ b/src/main/asiohook/asio-reghook.h @@ -0,0 +1,6 @@ +#ifndef IASIO_REG_HOOK_H +#define IASIO_REG_HOOK_H + +void asio_reghook_init(const char *expected_name, const char *target_name); + +#endif