mirror of
https://codeberg.org/Nixietab/EOSSDK-Holos.git
synced 2026-08-21 20:23:28 -04:00
add telemetry blocking
This commit is contained in:
parent
98af2b4034
commit
47f8eb112e
2 changed files with 206 additions and 5 deletions
|
|
@ -120,7 +120,6 @@ def main():
|
|||
"EOS_Sanctions_QueryActivePlayerSanctions",
|
||||
"EOS_Sanctions_GetPlayerSanctionCount",
|
||||
"EOS_Sanctions_CopyPlayerSanctionByIndex",
|
||||
|
||||
]
|
||||
|
||||
funcs = []
|
||||
|
|
|
|||
202
main.cpp
202
main.cpp
|
|
@ -48,6 +48,7 @@ static void DrainCallbackQueue() {
|
|||
// logging system
|
||||
FILE *logFile = NULL;
|
||||
FILE *packetFile = NULL;
|
||||
FILE *telemetryFile = NULL;
|
||||
static CRITICAL_SECTION g_packetCs;
|
||||
|
||||
void InitLogFiles();
|
||||
|
|
@ -65,6 +66,27 @@ void Log(const char *format, ...) {
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void LogTelemetry(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
if (logFile) {
|
||||
fprintf(logFile, "[%02u:%02u:%02u.%03u] ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||
vfprintf(logFile, format, args);
|
||||
fprintf(logFile, "\n");
|
||||
}
|
||||
va_end(args);
|
||||
va_start(args, format);
|
||||
if (telemetryFile) {
|
||||
fprintf(telemetryFile, "[%02u:%02u:%02u.%03u] ", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||
vfprintf(telemetryFile, format, args);
|
||||
fprintf(telemetryFile, "\n");
|
||||
fflush(telemetryFile);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void HexDump(const void *data, size_t len, char *out) {
|
||||
const unsigned char *p = (const unsigned char *)data;
|
||||
for (size_t i = 0; i < len; ++i) sprintf(out + i * 3, "%02X ", p[i]);
|
||||
|
|
@ -242,6 +264,12 @@ static const DWORD kAutoTeardownSuppressWindowMs = 100;
|
|||
static LONG g_autoTeardownSuppressed = 0;
|
||||
static volatile DWORD g_autoTeardownSuppressTime = 0;
|
||||
|
||||
// Telemetry blocking config
|
||||
static bool g_telemetryBlock = false;
|
||||
static bool g_dumpTraffic = false;
|
||||
static char g_blockedDomains[1024] = "api.epicgames.dev";
|
||||
static char g_blockedIPs[1024] = "104.18.125.108";
|
||||
|
||||
void LogStateSnapshot(const char *context) {
|
||||
Log("[State] %s | isHost=%d peerConnected=%d lobbyHasRemoteMember=%d initialized=%d clientSawSearchResult=%d",
|
||||
context ? context : "???", (int)AtomicRead(&g_isHost), (int)AtomicRead(&g_peerConnected),
|
||||
|
|
@ -2369,11 +2397,32 @@ void ProxySdkLogCallback(const EOS_LogMessage* Message) {
|
|||
if (Message) {
|
||||
InterlockedIncrement(&g_sdkLogCount);
|
||||
|
||||
bool isTelemetry = Message->Message &&
|
||||
(strstr(Message->Message, "api.epicgames.dev") ||
|
||||
strstr(Message->Message, "0.0.0.0") ||
|
||||
strstr(Message->Message, "Couldn't connect to server") ||
|
||||
strstr(Message->Message, "Connection refused") ||
|
||||
strstr(Message->Message, "Failed to connect to the backend") ||
|
||||
strstr(Message->Message, "EOS_NoConnection"));
|
||||
|
||||
if (isTelemetry) {
|
||||
if (telemetryFile) {
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
fprintf(telemetryFile, "[%02u:%02u:%02u.%03u] [SDK/%s] %s: %s\n",
|
||||
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
|
||||
Message->Category ? Message->Category : "?",
|
||||
LogLevelToStr(Message->Level),
|
||||
Message->Message ? Message->Message : "");
|
||||
fflush(telemetryFile);
|
||||
}
|
||||
} else {
|
||||
Log("[SDK/%s] %s: %s",
|
||||
Message->Category ? Message->Category : "?",
|
||||
LogLevelToStr(Message->Level),
|
||||
Message->Message ? Message->Message : "");
|
||||
}
|
||||
}
|
||||
if (g_gameLogCallback) g_gameLogCallback(Message);
|
||||
}
|
||||
|
||||
|
|
@ -2448,10 +2497,13 @@ void InitLogFiles() {
|
|||
else path[0] = '\0';
|
||||
char logPath[MAX_PATH];
|
||||
char pktPath[MAX_PATH];
|
||||
char telPath[MAX_PATH];
|
||||
strcpy(logPath, path); strcat(logPath, "proxy_p2p.log");
|
||||
strcpy(pktPath, path); strcat(pktPath, "proxy_packets.log");
|
||||
strcpy(telPath, path); strcat(telPath, "telemetry_logs.log");
|
||||
logFile = fopen(logPath, "a");
|
||||
packetFile = fopen(pktPath, "a");
|
||||
telemetryFile = fopen(telPath, "a");
|
||||
if (logFile) {
|
||||
|
||||
setvbuf(logFile, NULL, _IOFBF, 1 << 16);
|
||||
|
|
@ -2468,14 +2520,135 @@ void InitLogFiles() {
|
|||
fprintf(packetFile, "Packet dump started at %02u:%02u:%02u\n", st.wHour, st.wMinute, st.wSecond);
|
||||
fflush(packetFile);
|
||||
}
|
||||
if (telemetryFile) {
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
fprintf(telemetryFile, "\n========== Telemetry Log %02u:%02u:%02u ==========\n",
|
||||
st.wHour, st.wMinute, st.wSecond);
|
||||
fflush(telemetryFile);
|
||||
}
|
||||
}
|
||||
|
||||
void CloseLogFiles() {
|
||||
if (logFile) { fclose(logFile); logFile = NULL; }
|
||||
if (packetFile) { fclose(packetFile); packetFile = NULL; }
|
||||
if (telemetryFile) { fclose(telemetryFile); telemetryFile = NULL; }
|
||||
DeleteCriticalSection(&g_packetCs);
|
||||
}
|
||||
|
||||
// === WinSock Telemetry Blocking Hooks ===
|
||||
|
||||
typedef int (WSAAPI *GetAddrInfoFn)(PCSTR, PCSTR, const ADDRINFOA *, PADDRINFOA *);
|
||||
typedef int (WSAAPI *ConnectFn)(SOCKET, const struct sockaddr *, int);
|
||||
|
||||
static GetAddrInfoFn Real_GetAddrInfo = NULL;
|
||||
static ConnectFn Real_Connect = NULL;
|
||||
|
||||
static bool PatchIat(HMODULE module, const char *sourceDll, const char *funcName,
|
||||
WORD ordinal, void *hook, void **orig) {
|
||||
if (!module) return false;
|
||||
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)module;
|
||||
if (dos->e_magic != 0x5A4D) return false;
|
||||
PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((char*)module + dos->e_lfanew);
|
||||
if (nt->Signature != 0x00004550) return false;
|
||||
PIMAGE_DATA_DIRECTORY importDir = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
if (!importDir->VirtualAddress || !importDir->Size) return false;
|
||||
static const uintptr_t kOrdFlag = 0x8000000000000000ULL;
|
||||
PIMAGE_IMPORT_DESCRIPTOR imports = (PIMAGE_IMPORT_DESCRIPTOR)((char*)module + importDir->VirtualAddress);
|
||||
for (; imports->Name; imports++) {
|
||||
char *dllName = (char*)module + imports->Name;
|
||||
if (_stricmp(dllName, sourceDll) != 0) continue;
|
||||
PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)((char*)module + imports->FirstThunk);
|
||||
PIMAGE_THUNK_DATA origThunk = (PIMAGE_THUNK_DATA)((char*)module + imports->OriginalFirstThunk);
|
||||
for (; thunk->u1.Function; thunk++, origThunk++) {
|
||||
bool match = false;
|
||||
if (funcName) {
|
||||
if (origThunk->u1.Ordinal & kOrdFlag) continue;
|
||||
PIMAGE_IMPORT_BY_NAME imp = (PIMAGE_IMPORT_BY_NAME)((char*)module + origThunk->u1.AddressOfData);
|
||||
if (strcmp(imp->Name, funcName) == 0) match = true;
|
||||
} else {
|
||||
if (!(origThunk->u1.Ordinal & kOrdFlag)) continue;
|
||||
if ((origThunk->u1.Ordinal & 0xFFFF) == ordinal) match = true;
|
||||
}
|
||||
if (!match) continue;
|
||||
if (orig) *orig = (void*)(uintptr_t)thunk->u1.Function;
|
||||
DWORD old;
|
||||
if (VirtualProtect(&thunk->u1.Function, sizeof(void*), PAGE_READWRITE, &old)) {
|
||||
thunk->u1.Function = (uintptr_t)(LONG_PTR)hook;
|
||||
VirtualProtect(&thunk->u1.Function, sizeof(void*), old, &old);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int my_tolower(int c) {
|
||||
return (c >= 'A' && c <= 'Z') ? c + 32 : c;
|
||||
}
|
||||
|
||||
static bool Listed(const char *value, const char *list) {
|
||||
if (!value || !list || !list[0]) return false;
|
||||
const char *p = list;
|
||||
size_t vlen = strlen(value);
|
||||
while (*p) {
|
||||
while (*p == ' ' || *p == ',' || *p == ';') p++;
|
||||
if (!*p) break;
|
||||
const char *start = p;
|
||||
while (*p && *p != ' ' && *p != ',' && *p != ';') p++;
|
||||
size_t len = p - start;
|
||||
if (len != vlen) continue;
|
||||
bool match = true;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (my_tolower((unsigned char)value[i]) != my_tolower((unsigned char)start[i])) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int WSAAPI Hook_GetAddrInfo(PCSTR name, PCSTR svc, const ADDRINFOA *hints, PADDRINFOA *res) {
|
||||
int ret = Real_GetAddrInfo(name, svc, hints, res);
|
||||
if (ret != 0) return ret;
|
||||
if (name && Listed(name, g_blockedDomains)) {
|
||||
if (g_telemetryBlock) {
|
||||
LogTelemetry("[Telemetry] Redirected DNS: %s -> 0.0.0.0 (block via connect)", name);
|
||||
ADDRINFOA *cur = *res;
|
||||
while (cur) {
|
||||
if (cur->ai_family == AF_INET && cur->ai_addr) {
|
||||
((struct sockaddr_in *)cur->ai_addr)->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
} else if (g_dumpTraffic) {
|
||||
LogTelemetry("[Telemetry] Traffic: DNS lookup %s (ALLOWED, dump mode)", name);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int WSAAPI Hook_Connect(SOCKET s, const struct sockaddr *addr, int addrlen) {
|
||||
if (addr && addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
|
||||
char ip[16];
|
||||
strcpy(ip, inet_ntoa(sin->sin_addr));
|
||||
bool isBlocked = g_telemetryBlock && Listed(ip, g_blockedIPs);
|
||||
if (isBlocked) {
|
||||
LogTelemetry("[Telemetry] Blocked connect to %s:%d", ip, ntohs(sin->sin_port));
|
||||
WSASetLastError(WSAECONNREFUSED);
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
if (g_dumpTraffic && Listed(ip, g_blockedIPs)) {
|
||||
LogTelemetry("[Telemetry] Traffic: connect to %s:%d (ALLOWED, dump mode)", ip, ntohs(sin->sin_port));
|
||||
}
|
||||
}
|
||||
return Real_Connect(s, addr, addrlen);
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH: {
|
||||
|
|
@ -2492,6 +2665,25 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
|||
if (dirSlash) *(dirSlash + 1) = '\0';
|
||||
else g_dllDir[0] = '\0';
|
||||
InitLogFiles();
|
||||
|
||||
// Load telemetry config
|
||||
{
|
||||
char iniPath2[MAX_PATH];
|
||||
snprintf(iniPath2, sizeof(iniPath2), "%sdirectip.ini", g_dllDir);
|
||||
char telemetryStr[8] = "true";
|
||||
GetPrivateProfileStringA("Network", "Telemetry", "true", telemetryStr, sizeof(telemetryStr), iniPath2);
|
||||
g_telemetryBlock = (_stricmp(telemetryStr, "false") == 0 || strcmp(telemetryStr, "0") == 0);
|
||||
char dumpStr[8] = "false";
|
||||
GetPrivateProfileStringA("Telemetry", "DumpTraffic", "false", dumpStr, sizeof(dumpStr), iniPath2);
|
||||
g_dumpTraffic = (_stricmp(dumpStr, "true") == 0 || strcmp(dumpStr, "1") == 0);
|
||||
GetPrivateProfileStringA("Telemetry", "BlockDomains", "api.epicgames.dev", g_blockedDomains, sizeof(g_blockedDomains), iniPath2);
|
||||
GetPrivateProfileStringA("Telemetry", "BlockIPs", "104.18.125.108", g_blockedIPs, sizeof(g_blockedIPs), iniPath2);
|
||||
// Do NOT add 0.0.0.0 to the block list — let connect fail naturally
|
||||
// so the EOS SDK's HttpManagerThread doesn't crash on synthetic errors.
|
||||
LogTelemetry("[Telemetry] Config: block=%d dump=%d domains=%s ips=%s",
|
||||
(int)g_telemetryBlock, (int)g_dumpTraffic, g_blockedDomains, g_blockedIPs);
|
||||
}
|
||||
|
||||
char *lastSlash = strrchr(path, '\\');
|
||||
if (!lastSlash) lastSlash = strrchr(path, '/');
|
||||
if (lastSlash) {
|
||||
|
|
@ -2525,6 +2717,16 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
|||
} else {
|
||||
Log("[Proxy] Failed to load original DLL! Error: %d", GetLastError());
|
||||
}
|
||||
|
||||
// Patch EOS SDK IAT for ws2_32 telemetry hooks
|
||||
bool okGa = PatchIat(hOriginalDll, "ws2_32.dll", "getaddrinfo", 0,
|
||||
(void*)Hook_GetAddrInfo, (void**)&Real_GetAddrInfo);
|
||||
bool okCo = PatchIat(hOriginalDll, "ws2_32.dll", NULL, 4,
|
||||
(void*)Hook_Connect, (void**)&Real_Connect);
|
||||
LogTelemetry("[Telemetry] IAT hooks: getaddrinfo=%s(%p) connect=%s(%p)",
|
||||
okGa ? "OK" : "FAIL", (void*)Real_GetAddrInfo,
|
||||
okCo ? "OK" : "FAIL", (void*)Real_Connect);
|
||||
|
||||
break;
|
||||
}
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue