From d8202e1df488086690ad96676c5e3ab447e3e925 Mon Sep 17 00:00:00 2001 From: r0x5a <155115880+r0x5a@users.noreply.github.com> Date: Thu, 12 Dec 2024 02:28:02 +0800 Subject: [PATCH] dns: add port overriding support --- doc/config/common.md | 18 ++++++++++ hooklib/dns.c | 81 +++++++++++++++++++++++++++++++++++++++++++- hooklib/dns.h | 1 + meson.build | 1 + platform/config.c | 4 +++ platform/dns.c | 16 +++++---- platform/dns.h | 3 ++ 7 files changed, 117 insertions(+), 7 deletions(-) diff --git a/doc/config/common.md b/doc/config/common.md index 3c86751..f2e0380 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -203,6 +203,24 @@ Default: `0` Replace the HOST field in HTTP request headers with the settings above. This may help bypass network restrictions in some regions. +### `startupPort` + +Default: `0` (i.e. no operation will perform) + +Overrides the port of connections to the `startup` server. The current implementation affects every TCP connection to the port 80. + +### `billingPort` + +Default: `0` (i.e. no operation will perform) + +Overrides the port of connections to the `billing` server. The current implementation affects every TCP connection to the port 8443. + +### `aimedbPort` + +Default: `0` (i.e. no operation will perform) + +Overrides the port of connections to the `aimedb` server. The current implementation affects every TCP connection to the port 22345. + ## `[ds]` Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX diff --git a/hooklib/dns.c b/hooklib/dns.c index 8884989..7cea522 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -88,6 +88,11 @@ static DWORD WINAPI hook_send( int len, int flags); +static int WINAPI hook_connect( + SOCKET s, + const struct sockaddr *name, + int namelen); + /* Link pointers */ static DNS_STATUS (WINAPI *next_DnsQuery_A)( @@ -135,6 +140,11 @@ static DWORD (WINAPI *next_send)( int len, int flags); +static int (__stdcall *next_connect)( + SOCKET s, + const struct sockaddr *name, + int namelen); + static const struct hook_symbol dns_hook_syms_dnsapi[] = { { .name = "DnsQuery_A", @@ -180,11 +190,22 @@ static struct hook_symbol http_hook_syms_ws2[] = { }, }; +static struct hook_symbol port_hook_syms_ws2[] = { + { + .name = "connect", + .patch = hook_connect, + .link = (void **) &next_connect + }, +}; + static bool dns_hook_initted; static CRITICAL_SECTION dns_hook_lock; static struct dns_hook_entry *dns_hook_entries; static size_t dns_hook_nentries; static char received_title_url[255]; +static unsigned short startup_port; +static unsigned short billing_port; +static unsigned short aimedb_port; static void dns_hook_init(void) { @@ -226,6 +247,21 @@ void http_hook_init(){ _countof(http_hook_syms_ws2)); } +void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port){ + startup_port = _startup_port; + billing_port = _billing_port; + aimedb_port = _aimedb_port; + for (size_t i = 0; i < _countof(port_hook_syms_ws2); ++i) { + port_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", port_hook_syms_ws2[i].name); + } + + hook_table_apply( + NULL, + "ws2_32.dll", + port_hook_syms_ws2, + _countof(port_hook_syms_ws2)); +} + // This function match domain and subdomains like *.naominet.jp. bool match_domain(const wchar_t* target, const wchar_t* pattern) { if (_wcsicmp(pattern, target) == 0) { @@ -624,7 +660,7 @@ static bool WINAPI hook_WinHttpCrackUrl( if (match_domain(pwszUrl, pos->from)) { wchar_t* toAddr = pos->to; wchar_t titleBuffer[255]; - + if(wcscmp(toAddr, L"title") == 0) { size_t wstr_c; mbstowcs_s(&wstr_c, titleBuffer, 255, received_title_url, strlen(received_title_url)); @@ -651,6 +687,49 @@ static bool WINAPI hook_WinHttpCrackUrl( ); } +int WINAPI hook_connect(SOCKET s, const struct sockaddr *name, int namelen) { + const struct sockaddr_in *n; + struct sockaddr_in new_name; + unsigned ip; + unsigned short port, new_port; + + EnterCriticalSection(&dns_hook_lock); + + n = (const struct sockaddr_in *)name; + ip = n->sin_addr.S_un.S_addr; + if (WSANtohs(s, n->sin_port, &port)) return SOCKET_ERROR; + + if (port == 80 && startup_port) { + new_port = startup_port; + } else if (port == 8443 && billing_port) { + new_port = billing_port; + } else if (port == 22345 && aimedb_port) { + new_port = aimedb_port; + } else { // No match + dprintf("TCP Connect: %u.%u.%u.%u:%hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port); + + LeaveCriticalSection(&dns_hook_lock); + return next_connect( + s, + name, + namelen + ); + } + + // matched + new_name = *n; + if (WSAHtons(s, new_port, &new_name.sin_port)) return SOCKET_ERROR; + + dprintf("TCP Connect: %u.%u.%u.%u:%hu, mapped to port %hu\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port, new_port); + + LeaveCriticalSection(&dns_hook_lock); + return next_connect( + s, + (const struct sockaddr *)&new_name, + sizeof(new_name) + ); +} + DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) { if (strstr(buf, "HTTP/") != NULL) { char *new_buf = malloc(len + 1); diff --git a/hooklib/dns.h b/hooklib/dns.h index ed46959..9279a37 100644 --- a/hooklib/dns.h +++ b/hooklib/dns.h @@ -4,6 +4,7 @@ #include void http_hook_init(); +void port_hook_init(unsigned short _startup_port, unsigned short _billing_port, unsigned short _aimedb_port); // if to_src is NULL, all lookups for from_src will fail HRESULT dns_hook_push(const wchar_t *from_src, const wchar_t *to_src); diff --git a/meson.build b/meson.build index 4a962a4..41b49f4 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,7 @@ if cc.get_id() != 'msvc' '-static-libgcc', # '-ggdb', # Add debug information '-lcrypt32', # Bcrypt needed for prashook + '-lws2_32', # WSAHtons / WSANtohs needed for porthook # '-Wl,-s', # Strip debug symbols language: 'c', ) diff --git a/platform/config.c b/platform/config.c index a4362a3..2904019 100644 --- a/platform/config.c +++ b/platform/config.c @@ -123,6 +123,10 @@ void dns_config_load(struct dns_config *cfg, const wchar_t *filename) filename); cfg->replaceHost = GetPrivateProfileIntW(L"dns", L"replaceHost", 0, filename); + + cfg->startupPort = GetPrivateProfileIntW(L"dns", L"startupPort", 0, filename); + cfg->billingPort = GetPrivateProfileIntW(L"dns", L"billingPort", 0, filename); + cfg->aimedbPort = GetPrivateProfileIntW(L"dns", L"aimedbPort", 0, filename); } void hwmon_config_load(struct hwmon_config *cfg, const wchar_t *filename) diff --git a/platform/dns.c b/platform/dns.c index 9ca8a5b..d87d8a4 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -20,6 +20,10 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) http_hook_init(); } + if(cfg->startupPort || cfg->billingPort || cfg->aimedbPort){ + port_hook_init(cfg->startupPort, cfg->billingPort, cfg->aimedbPort); + } + hr = dns_hook_push(L"tenporouter.loc", cfg->router); if (FAILED(hr)) { @@ -112,40 +116,40 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) if (FAILED(hr)) { return hr; } - + // WAHLAP PowerOn hr = dns_hook_push(L"at.sys-all.cn", cfg->startup); if (FAILED(hr)) { return hr; } - + hr = dns_hook_push(L"at.sys-allnet.cn", cfg->startup); if (FAILED(hr)) { return hr; } - + // WAHLAP WeChat AimeDB Server hr = dns_hook_push(L"ai.sys-all.cn", cfg->aimedb); if (FAILED(hr)) { return hr; } - + hr = dns_hook_push(L"ai.sys-allnet.cn", cfg->aimedb); if (FAILED(hr)) { return hr; } - + // WAHLAP Billing hr = dns_hook_push(L"bl.sys-all.cn", cfg->billing); if (FAILED(hr)) { return hr; } - + hr = dns_hook_push(L"bl.sys-allnet.cn", cfg->billing); if (FAILED(hr)) { diff --git a/platform/dns.h b/platform/dns.h index 0a2c2bc..1a19d26 100644 --- a/platform/dns.h +++ b/platform/dns.h @@ -13,6 +13,9 @@ struct dns_config { wchar_t aimedb[128]; wchar_t title[128]; bool replaceHost; + unsigned short startupPort; + unsigned short billingPort; + unsigned short aimedbPort; }; HRESULT dns_platform_hook_init(const struct dns_config *cfg);