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_QueryActivePlayerSanctions",
|
||||||
"EOS_Sanctions_GetPlayerSanctionCount",
|
"EOS_Sanctions_GetPlayerSanctionCount",
|
||||||
"EOS_Sanctions_CopyPlayerSanctionByIndex",
|
"EOS_Sanctions_CopyPlayerSanctionByIndex",
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
funcs = []
|
funcs = []
|
||||||
|
|
|
||||||
202
main.cpp
202
main.cpp
|
|
@ -48,6 +48,7 @@ static void DrainCallbackQueue() {
|
||||||
// logging system
|
// logging system
|
||||||
FILE *logFile = NULL;
|
FILE *logFile = NULL;
|
||||||
FILE *packetFile = NULL;
|
FILE *packetFile = NULL;
|
||||||
|
FILE *telemetryFile = NULL;
|
||||||
static CRITICAL_SECTION g_packetCs;
|
static CRITICAL_SECTION g_packetCs;
|
||||||
|
|
||||||
void InitLogFiles();
|
void InitLogFiles();
|
||||||
|
|
@ -65,6 +66,27 @@ void Log(const char *format, ...) {
|
||||||
va_end(args);
|
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) {
|
static void HexDump(const void *data, size_t len, char *out) {
|
||||||
const unsigned char *p = (const unsigned char *)data;
|
const unsigned char *p = (const unsigned char *)data;
|
||||||
for (size_t i = 0; i < len; ++i) sprintf(out + i * 3, "%02X ", p[i]);
|
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 LONG g_autoTeardownSuppressed = 0;
|
||||||
static volatile DWORD g_autoTeardownSuppressTime = 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) {
|
void LogStateSnapshot(const char *context) {
|
||||||
Log("[State] %s | isHost=%d peerConnected=%d lobbyHasRemoteMember=%d initialized=%d clientSawSearchResult=%d",
|
Log("[State] %s | isHost=%d peerConnected=%d lobbyHasRemoteMember=%d initialized=%d clientSawSearchResult=%d",
|
||||||
context ? context : "???", (int)AtomicRead(&g_isHost), (int)AtomicRead(&g_peerConnected),
|
context ? context : "???", (int)AtomicRead(&g_isHost), (int)AtomicRead(&g_peerConnected),
|
||||||
|
|
@ -2369,11 +2397,32 @@ void ProxySdkLogCallback(const EOS_LogMessage* Message) {
|
||||||
if (Message) {
|
if (Message) {
|
||||||
InterlockedIncrement(&g_sdkLogCount);
|
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",
|
Log("[SDK/%s] %s: %s",
|
||||||
Message->Category ? Message->Category : "?",
|
Message->Category ? Message->Category : "?",
|
||||||
LogLevelToStr(Message->Level),
|
LogLevelToStr(Message->Level),
|
||||||
Message->Message ? Message->Message : "");
|
Message->Message ? Message->Message : "");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (g_gameLogCallback) g_gameLogCallback(Message);
|
if (g_gameLogCallback) g_gameLogCallback(Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2448,10 +2497,13 @@ void InitLogFiles() {
|
||||||
else path[0] = '\0';
|
else path[0] = '\0';
|
||||||
char logPath[MAX_PATH];
|
char logPath[MAX_PATH];
|
||||||
char pktPath[MAX_PATH];
|
char pktPath[MAX_PATH];
|
||||||
|
char telPath[MAX_PATH];
|
||||||
strcpy(logPath, path); strcat(logPath, "proxy_p2p.log");
|
strcpy(logPath, path); strcat(logPath, "proxy_p2p.log");
|
||||||
strcpy(pktPath, path); strcat(pktPath, "proxy_packets.log");
|
strcpy(pktPath, path); strcat(pktPath, "proxy_packets.log");
|
||||||
|
strcpy(telPath, path); strcat(telPath, "telemetry_logs.log");
|
||||||
logFile = fopen(logPath, "a");
|
logFile = fopen(logPath, "a");
|
||||||
packetFile = fopen(pktPath, "a");
|
packetFile = fopen(pktPath, "a");
|
||||||
|
telemetryFile = fopen(telPath, "a");
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
|
|
||||||
setvbuf(logFile, NULL, _IOFBF, 1 << 16);
|
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);
|
fprintf(packetFile, "Packet dump started at %02u:%02u:%02u\n", st.wHour, st.wMinute, st.wSecond);
|
||||||
fflush(packetFile);
|
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() {
|
void CloseLogFiles() {
|
||||||
if (logFile) { fclose(logFile); logFile = NULL; }
|
if (logFile) { fclose(logFile); logFile = NULL; }
|
||||||
if (packetFile) { fclose(packetFile); packetFile = NULL; }
|
if (packetFile) { fclose(packetFile); packetFile = NULL; }
|
||||||
|
if (telemetryFile) { fclose(telemetryFile); telemetryFile = NULL; }
|
||||||
DeleteCriticalSection(&g_packetCs);
|
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) {
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||||
switch (ul_reason_for_call) {
|
switch (ul_reason_for_call) {
|
||||||
case DLL_PROCESS_ATTACH: {
|
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';
|
if (dirSlash) *(dirSlash + 1) = '\0';
|
||||||
else g_dllDir[0] = '\0';
|
else g_dllDir[0] = '\0';
|
||||||
InitLogFiles();
|
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, '\\');
|
char *lastSlash = strrchr(path, '\\');
|
||||||
if (!lastSlash) lastSlash = strrchr(path, '/');
|
if (!lastSlash) lastSlash = strrchr(path, '/');
|
||||||
if (lastSlash) {
|
if (lastSlash) {
|
||||||
|
|
@ -2525,6 +2717,16 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
||||||
} else {
|
} else {
|
||||||
Log("[Proxy] Failed to load original DLL! Error: %d", GetLastError());
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue