From d264ae0b376b7b844e461c2468a7430ea12f90d7 Mon Sep 17 00:00:00 2001 From: kyoubate-haruka <46010460+kyoubate-haruka@users.noreply.github.com> Date: Sat, 13 Sep 2025 11:37:23 +0200 Subject: [PATCH] ekt: add UDP broadcast netenv redirection --- common/platform/config.c | 25 ++++++++++++ common/platform/netenv.c | 86 +++++++++++++++++++++++++++++++++++++++- common/platform/netenv.h | 1 + common/platform/nusec.h | 1 + doc/config/common.md | 6 +++ games/ekthook/dllmain.c | 6 ++- 6 files changed, 122 insertions(+), 3 deletions(-) diff --git a/common/platform/config.c b/common/platform/config.c index adc6451..41a3ed1 100644 --- a/common/platform/config.c +++ b/common/platform/config.c @@ -12,6 +12,9 @@ #include "platform/amvideo.h" #include "platform/clock.h" #include "platform/config.h" + +#include + #include "platform/dns.h" #include "platform/epay.h" #include "platform/hwmon.h" @@ -23,12 +26,21 @@ #include "platform/platform.h" #include "platform/vfs.h" #include "platform/system.h" +#include "util/dprintf.h" void platform_config_load(struct platform_config *cfg, const wchar_t *filename) { assert(cfg != NULL); assert(filename != NULL); + if (!PathFileExistsW(filename)) { + wchar_t temp[MAX_PATH]; + dprintf("ERROR: Configuration does not exist\n"); + dprintf(" Configured: \"%ls\"\n", filename); + GetFullPathNameW(filename, _countof(temp), temp, NULL); + dprintf(" Expanded: \"%ls\"\n", temp); + } + amvideo_config_load(&cfg->amvideo, filename); clock_config_load(&cfg->clock, filename); dns_config_load(&cfg->dns, filename); @@ -201,6 +213,7 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename) wchar_t game_id[5]; wchar_t platform_id[5]; wchar_t subnet[16]; + wchar_t bcast[16]; unsigned int ip[4]; size_t i; @@ -212,6 +225,7 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename) memset(game_id, 0, sizeof(game_id)); memset(platform_id, 0, sizeof(platform_id)); memset(subnet, 0, sizeof(subnet)); + memset(bcast, 0, sizeof(bcast)); cfg->enable = GetPrivateProfileIntW(L"keychip", L"enable", 1, filename); @@ -255,6 +269,14 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename) _countof(subnet), filename); + GetPrivateProfileStringW( + L"netenv", + L"broadcast", + L"255.255.255.255", + bcast, + _countof(bcast), + filename); + for (i = 0 ; i < 16 ; i++) { cfg->keychip_id[i] = (char) keychip_id[i]; } @@ -270,6 +292,9 @@ void nusec_config_load(struct nusec_config *cfg, const wchar_t *filename) swscanf(subnet, L"%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]); cfg->subnet = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | 0; + swscanf(bcast, L"%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]); + cfg->bcast = (ip[0] << 24) | (ip[1] << 16) | (ip[2] << 8) | (ip[3]); + GetPrivateProfileStringW( L"keychip", L"billingCa", diff --git a/common/platform/netenv.c b/common/platform/netenv.c index 4fb77d2..ecf2d7e 100644 --- a/common/platform/netenv.c +++ b/common/platform/netenv.c @@ -16,6 +16,8 @@ #include "hook/table.h" #include "platform/netenv.h" + +#include "hook/procaddr.h" #include "platform/nusec.h" #include "util/dprintf.h" @@ -72,6 +74,14 @@ static uint32_t WINAPI hook_IcmpSendEcho2( uint32_t ReplySize, uint32_t Timeout); +static int WINAPI hook_sendto( + SOCKET s, + const char* buf, + int len, + int flags, + const struct sockaddr *to, + int tolen); + /* Link pointers */ static uint32_t (WINAPI *next_GetAdaptersAddresses)( @@ -108,6 +118,15 @@ static uint32_t (WINAPI *next_IcmpSendEcho2)( uint32_t ReplySize, uint32_t Timeout); +static int (WINAPI *next_sendto)( + SOCKET s, + const char *buf, + int len, + int flags, + const struct sockaddr *to, + int tolen); + + static const struct hook_symbol netenv_hook_syms[] = { { .name = "GetAdaptersAddresses", @@ -132,7 +151,17 @@ static const struct hook_symbol netenv_hook_syms[] = { } }; +static struct hook_symbol netenv_hook_syms_ws2[] = { + { + .name = "sendto", + .patch = hook_sendto, + .ordinal = 20, + .link = (void **) &next_sendto + }, +}; + static uint32_t netenv_ip_prefix; +static uint32_t netenv_ip_bcast; static uint32_t netenv_ip_iface; static uint32_t netenv_ip_router; static uint8_t netenv_mac_addr[6]; @@ -155,17 +184,34 @@ HRESULT netenv_hook_init( } netenv_ip_prefix = kc_cfg->subnet; + netenv_ip_bcast = kc_cfg->bcast; netenv_ip_iface = kc_cfg->subnet | cfg->addr_suffix; netenv_ip_router = kc_cfg->subnet | cfg->router_suffix; memcpy(netenv_mac_addr, cfg->mac_addr, sizeof(netenv_mac_addr)); + netenv_hook_apply_hooks(NULL); + + return S_OK; +} + +void netenv_hook_apply_hooks(HMODULE mod) { hook_table_apply( - NULL, + mod, "iphlpapi.dll", netenv_hook_syms, _countof(netenv_hook_syms)); - return S_OK; + hook_table_apply( + mod, + "ws2_32.dll", + netenv_hook_syms_ws2, + _countof(netenv_hook_syms_ws2)); + + proc_addr_table_push( + mod, + "ws2_32.dll", + netenv_hook_syms_ws2, + _countof(netenv_hook_syms_ws2)); } static uint32_t WINAPI hook_GetAdaptersAddresses( @@ -506,3 +552,39 @@ static uint32_t WINAPI hook_IcmpSendEcho2( return 1; } + +static int WINAPI hook_sendto( + SOCKET s, + const char* buf, + int len, + int flags, + const struct sockaddr* to, + int tolen) { + if (to->sa_family != AF_INET) { + // we only care about IP packets + return next_sendto(s, buf, len, flags, to, tolen); + } + + const struct sockaddr_in* original_to = (struct sockaddr_in*)to; + + uint32_t bc_addr = _byteswap_ulong(netenv_ip_prefix | 0xFF); + + if (original_to->sin_addr.S_un.S_addr == bc_addr) { + + uint32_t src_addr = _byteswap_ulong(original_to->sin_addr.S_un.S_addr); + uint32_t dest_addr = _byteswap_ulong(netenv_ip_bcast); + + dprintf("Netenv: sendTo broadcast %u.%u.%u.%u -> %u.%u.%u.%u\n", + (src_addr >> 24) & 0xff, (src_addr >> 16) & 0xff, (src_addr >> 8) & 0xff, src_addr & 0xff, + (dest_addr >> 24) & 0xff, (dest_addr >> 16) & 0xff, (dest_addr >> 8) & 0xff, dest_addr & 0xff); + + struct sockaddr_in modified_to = {0}; + memcpy(&modified_to, original_to, tolen); + + modified_to.sin_addr.S_un.S_addr = dest_addr; + + return next_sendto(s, buf, len, flags, (struct sockaddr*)&modified_to, sizeof(modified_to)); + } + + return next_sendto(s, buf, len, flags, to, tolen); +} \ No newline at end of file diff --git a/common/platform/netenv.h b/common/platform/netenv.h index 977a3f6..88cae15 100644 --- a/common/platform/netenv.h +++ b/common/platform/netenv.h @@ -18,3 +18,4 @@ HRESULT netenv_hook_init( const struct netenv_config *cfg, const struct nusec_config *kc_cfg); +void netenv_hook_apply_hooks(HMODULE mod); \ No newline at end of file diff --git a/common/platform/nusec.h b/common/platform/nusec.h index 5d3dd4f..5d86f8d 100644 --- a/common/platform/nusec.h +++ b/common/platform/nusec.h @@ -14,6 +14,7 @@ struct nusec_config { uint8_t region; uint8_t system_flag; uint32_t subnet; + uint32_t bcast; uint16_t billing_type; wchar_t billing_ca[MAX_PATH]; wchar_t billing_pub[MAX_PATH]; diff --git a/doc/config/common.md b/doc/config/common.md index 68adfc4..c286a3f 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -576,6 +576,12 @@ Default: `01:02:03:04:05:06` The MAC address of the virtualized Ethernet adapter. The exact value shouldn't ever matter. +### `broadcast` + +Default: `255.255.255.255` + +The UDP broadcast address that should be used if packets are being sent to the virtual keychip's subnet. This is used for cab-to-cab communication (Local Play, Satellite to Terminal, etc.). Depending on your network adapters (VPNs etc), sometimes you must explicitely specify your real LANs subnet. + ## `[pcbid]` Configure Windows host name virtualization. The ALLS-series platform no longer diff --git a/games/ekthook/dllmain.c b/games/ekthook/dllmain.c index 202f302..305a995 100644 --- a/games/ekthook/dllmain.c +++ b/games/ekthook/dllmain.c @@ -49,6 +49,10 @@ static HMODULE ekt_hook_mod; static process_entry_t ekt_startup; static struct ekt_hook_config ekt_hook_cfg; +static void unity_hook_callback(HMODULE hmodule, const wchar_t* p) { + netenv_hook_apply_hooks(hmodule); +} + static DWORD CALLBACK ekt_pre_startup(void) { HRESULT hr; @@ -141,7 +145,7 @@ static DWORD CALLBACK ekt_pre_startup(void) There seems to be an issue with other DLL hooks if `LoadLibraryW` is hooked earlier in the `ekthook` initialization. */ - unity_hook_init(&ekt_hook_cfg.unity, ekt_hook_mod, NULL); + unity_hook_init(&ekt_hook_cfg.unity, ekt_hook_mod, unity_hook_callback); /* Initialize debug helpers */