From ceb2b63e8b6d49097231934f411fd9ffe1fad15d Mon Sep 17 00:00:00 2001 From: Sanhei Date: Mon, 11 Nov 2024 16:24:33 +0000 Subject: [PATCH] Modify host header in HTTP requests to bypass domain censorship in China. (#34) Co-authored-by: Sanheiii <35133371+Sanheiii@users.noreply.github.com> Reviewed-on: https://gitea.tendokyu.moe/Dniel97/segatools/pulls/34 Co-authored-by: Sanhei Co-committed-by: Sanhei --- doc/config/common.md | 6 +++ hooklib/dns.c | 82 ++++++++++++++++++++++++++++++++++++- hooklib/dns.h | 2 +- meson.build | 1 + platform/config.c | 2 + platform/dns.c | 4 ++ platform/dns.h | 1 + util/get_function_ordinal.c | 34 +++++++++++++++ util/get_function_ordinal.h | 6 +++ util/meson.build | 3 ++ 10 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 util/get_function_ordinal.c create mode 100644 util/get_function_ordinal.h diff --git a/doc/config/common.md b/doc/config/common.md index e778a8a..3c86751 100644 --- a/doc/config/common.md +++ b/doc/config/common.md @@ -197,6 +197,12 @@ Default: Empty string (i.e. use value from `default` setting) Overrides the target of the `aime.naominet.jp` host lookup. +### `replaceHost` + +Default: `0` + +Replace the HOST field in HTTP request headers with the settings above. This may help bypass network restrictions in some regions. + ## `[ds]` Controls emulation of the "DS (Dallas Semiconductor) EEPROM" chip on the AMEX diff --git a/hooklib/dns.c b/hooklib/dns.c index d7f0c4a..c3b95fb 100644 --- a/hooklib/dns.c +++ b/hooklib/dns.c @@ -14,6 +14,7 @@ #include "hook/table.h" #include "util/dprintf.h" +#include "util/get_function_ordinal.h" #include "hooklib/dns.h" @@ -81,6 +82,12 @@ static bool WINAPI hook_WinHttpCrackUrl( DWORD dwFlags, LPURL_COMPONENTS lpUrlComponents); +static DWORD WINAPI hook_send( + SOCKET s, + const char* buf, + int len, + int flags); + /* Link pointers */ static DNS_STATUS (WINAPI *next_DnsQuery_A)( @@ -122,6 +129,12 @@ static bool (WINAPI *next_WinHttpCrackUrl)( DWORD dwFlags, LPURL_COMPONENTS lpUrlComponents); +static DWORD (WINAPI *next_send)( + SOCKET s, + const char* buf, + int len, + int flags); + static const struct hook_symbol dns_hook_syms_dnsapi[] = { { .name = "DnsQuery_A", @@ -144,7 +157,7 @@ static const struct hook_symbol dns_hook_syms_ws2[] = { .ordinal = 176, .patch = hook_getaddrinfo, .link = (void **) &next_getaddrinfo, - } + }, }; static const struct hook_symbol dns_hook_syms_winhttp[] = { @@ -157,7 +170,14 @@ static const struct hook_symbol dns_hook_syms_winhttp[] = { .patch = hook_WinHttpCrackUrl, .link = (void **) &next_WinHttpCrackUrl, } +}; +static struct hook_symbol http_hook_syms_ws2[] = { + { + .name = "send", + .patch = hook_send, + .link = (void **) &next_send + }, }; static bool dns_hook_initted; @@ -186,7 +206,7 @@ static void dns_hook_init(void) "ws2_32.dll", dns_hook_syms_ws2, _countof(dns_hook_syms_ws2)); - + hook_table_apply( NULL, "winhttp.dll", @@ -194,6 +214,18 @@ static void dns_hook_init(void) _countof(dns_hook_syms_winhttp)); } +void http_hook_init(){ + for (size_t i = 0; i < _countof(http_hook_syms_ws2); ++i) { + http_hook_syms_ws2[i].ordinal = get_function_ordinal("ws2_32.dll", http_hook_syms_ws2[i].name); + } + + hook_table_apply( + NULL, + "ws2_32.dll", + http_hook_syms_ws2, + _countof(http_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) { @@ -618,3 +650,49 @@ static bool WINAPI hook_WinHttpCrackUrl( lpUrlComponents ); } + +DWORD WINAPI hook_send(SOCKET s, const char* buf, int len, int flags) { + if (strstr(buf, "HTTP/") != NULL) { + char *new_buf = malloc(len + 1); + if (new_buf == NULL) return SOCKET_ERROR; + + memcpy(new_buf, buf, len); + new_buf[len] = '\0'; + + char *host_start = strstr(new_buf, "Host: "); + if (host_start != NULL) { + char *host_end = strstr(host_start, "\r\n"); + if (host_end != NULL) { + host_end += 2; + int host_len = host_end - host_start; + + char *host_value_start = host_start + 6; + char *host_value_end = strstr(host_value_start, "\r\n"); + if (host_value_end != NULL) { + int value_len = host_value_end - host_value_start; + char host_value[value_len + 1]; + strncpy(host_value, host_value_start, value_len); + host_value[value_len] = '\0'; + + for (struct dns_hook_entry *entry = dns_hook_entries; entry && entry->from; entry++) { + char from_value[256]; + wcstombs(from_value, entry->from, sizeof(from_value)); + + if (strcmp(host_value, from_value) == 0) { + char to_value[256]; + wcstombs(to_value, entry->to, sizeof(to_value)); + snprintf(host_start, len - (host_start - new_buf), "Host: %s\r\n", to_value); + break; + } + } + } + len = (int)strlen(new_buf); + } + } + DWORD result = next_send(s, new_buf, len, flags); + free(new_buf); + return result; + } + + return next_send(s, buf, len, flags); +} \ No newline at end of file diff --git a/hooklib/dns.h b/hooklib/dns.h index 1f93b0f..ed46959 100644 --- a/hooklib/dns.h +++ b/hooklib/dns.h @@ -3,7 +3,7 @@ #include #include - +void http_hook_init(); // 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 129a387..12df35a 100644 --- a/meson.build +++ b/meson.build @@ -81,6 +81,7 @@ dinput8_lib = cc.find_library('dinput8') dxguid_lib = cc.find_library('dxguid') xinput_lib = cc.find_library('xinput') pathcch_lib = cc.find_library('pathcch') +imagehlp_lib = cc.find_library('imagehlp') inc = include_directories('.') capnhook = subproject('capnhook') diff --git a/platform/config.c b/platform/config.c index ad97905..a4362a3 100644 --- a/platform/config.c +++ b/platform/config.c @@ -121,6 +121,8 @@ void dns_config_load(struct dns_config *cfg, const wchar_t *filename) cfg->title, _countof(cfg->title), filename); + + cfg->replaceHost = GetPrivateProfileIntW(L"dns", L"replaceHost", 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 5fe9262..9ca8a5b 100644 --- a/platform/dns.c +++ b/platform/dns.c @@ -16,6 +16,10 @@ HRESULT dns_platform_hook_init(const struct dns_config *cfg) return S_FALSE; } + if(cfg->replaceHost){ + http_hook_init(); + } + hr = dns_hook_push(L"tenporouter.loc", cfg->router); if (FAILED(hr)) { diff --git a/platform/dns.h b/platform/dns.h index e822ff3..0a2c2bc 100644 --- a/platform/dns.h +++ b/platform/dns.h @@ -12,6 +12,7 @@ struct dns_config { wchar_t billing[128]; wchar_t aimedb[128]; wchar_t title[128]; + bool replaceHost; }; HRESULT dns_platform_hook_init(const struct dns_config *cfg); diff --git a/util/get_function_ordinal.c b/util/get_function_ordinal.c new file mode 100644 index 0000000..470bf7f --- /dev/null +++ b/util/get_function_ordinal.c @@ -0,0 +1,34 @@ +#include "get_function_ordinal.h" + +DWORD get_function_ordinal(const char* dllName, const char* functionName) { + HMODULE hModule = LoadLibraryA(dllName); + if (!hModule) { + dprintf("Failed to load DLL: %s\n", dllName); + return 0; + } + + ULONG size; + PIMAGE_EXPORT_DIRECTORY exportDir = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData( + hModule, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size); + if (!exportDir) { + dprintf("Failed to get export table\n"); + FreeLibrary(hModule); + return 0; + } + + DWORD* functionNames = (DWORD*)((BYTE*)hModule + exportDir->AddressOfNames); + WORD* ordinals = (WORD*)((BYTE*)hModule + exportDir->AddressOfNameOrdinals); + + for (DWORD i = 0; i < exportDir->NumberOfNames; ++i) { + char* name = (char*)((BYTE*)hModule + functionNames[i]); + if (strcmp(name, functionName) == 0) { + DWORD ordinal = ordinals[i] + exportDir->Base; + FreeLibrary(hModule); + return ordinal; + } + } + + dprintf("Function not found: %s\n", functionName); + FreeLibrary(hModule); + return 0; +} \ No newline at end of file diff --git a/util/get_function_ordinal.h b/util/get_function_ordinal.h new file mode 100644 index 0000000..6bc4b9e --- /dev/null +++ b/util/get_function_ordinal.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include "dprintf.h" + +DWORD get_function_ordinal(const char* dllName, const char* functionName); \ No newline at end of file diff --git a/util/meson.build b/util/meson.build index 575d123..2c29609 100644 --- a/util/meson.build +++ b/util/meson.build @@ -5,6 +5,7 @@ util_lib = static_library( c_pch : '../precompiled.h', dependencies : [ capnhook.get_variable('hook_dep'), + imagehlp_lib, ], sources : [ 'async.c', @@ -17,6 +18,8 @@ util_lib = static_library( 'dprintf.h', 'dump.c', 'dump.h', + 'get_function_ordinal.c', + 'get_function_ordinal.h', 'lib.c', 'lib.h', 'str.c',