Radicade Public Code

This commit is contained in:
JogmansonReal
2026-10-16 23:33:13 -07:00
commit 55175acdf6
832 changed files with 363261 additions and 0 deletions
@@ -0,0 +1,510 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using BestHTTP;
using HarmonyLib;
using Il2CppInterop.Runtime;
internal static class HileGate
{
internal static bool Enabled;
internal static int DroppedCount;
public static bool DropEnabled { get; } = IsDropEnabled();
private static bool IsDropEnabled()
{
try
{
var raw = System.Environment.GetEnvironmentVariable("RADICADE_HILE_GATE");
if (string.IsNullOrWhiteSpace(raw)) return false;
return raw.Trim().ToLowerInvariant() == "drop";
}
catch { return false; }
}
private static bool _dumped;
public static bool ShouldDrop(HTTPRequest request)
{
if (!Enabled || request?.Uri == null) return false;
var path = request.Uri.AbsolutePath;
if (path == null ||
!path.EndsWith("/api/PlayerReporting/v1/hile", System.StringComparison.OrdinalIgnoreCase))
return false;
Dump(request);
return DropEnabled;
}
public static void Dump(HTTPRequest request)
{
if (_dumped) return;
_dumped = true;
try
{
var body = "<unreadable>";
try
{
var raw = request.RawData;
if (raw != null && raw.Length > 0)
{
body = System.Text.Encoding.UTF8.GetString(raw);
if (body.Length > 2000) body = body.Substring(0, 2000) + "...[truncated]";
}
else
{
var entity = request.GetEntityBody();
if (entity != null && entity.Length > 0)
{
var text = System.Text.Encoding.UTF8.GetString(entity);
body = text + " (" + entity.Length + " bytes in the entity body)";
}
else
{
body = "<empty body>";
}
}
}
catch (System.Exception bodyEx)
{
body = "<body read failed: " + bodyEx.Message + ">";
}
var caller = "<unavailable>";
try { caller = System.Environment.StackTrace; } catch { }
RadicadeEacBypassPlugin.LogSource.LogWarning(
"[HileGate] anti-cheat report captured (full wire form):\n " + request.MethodType
+ " " + request.Uri + "\n body: " + body
+ "\n managed caller stack:" + caller);
}
catch (System.Exception ex)
{
RadicadeEacBypassPlugin.LogSource.LogWarning("[HileGate] capture failed: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(HTTPManager), "SendRequest", new[] { typeof(HTTPRequest) })]
internal static class NameserverConnectionPatches
{
[HarmonyPriority(Priority.Last)]
private static bool Prefix(HTTPRequest request, ref HTTPRequest __result)
{
if (RequestFunnel.Handle(request)) return true;
__result = request;
return false;
}
}
internal static class RequestFunnel
{
private static readonly HashSet<long> Seen = new();
private static bool IsSocketScheme(string url) =>
url.StartsWith("ws:", StringComparison.OrdinalIgnoreCase) ||
url.StartsWith("wss:", StringComparison.OrdinalIgnoreCase);
internal static bool Handle(HTTPRequest request)
{
if (HileGate.ShouldDrop(request))
{
HileGate.DroppedCount++;
RadicadeEacBypassPlugin.LogSource.LogWarning("[HileGate] dropped anti-cheat report POST (no response will arrive).");
return false;
}
try
{
var uri = request?.Uri?.ToString();
if (!string.IsNullOrEmpty(uri))
Diag.Trace("[Net] " + request.MethodType + " " + uri);
}
catch
{
}
if (request?.Uri == null) return true;
if (!Seen.Add(request.Pointer.ToInt64())) return true;
var original = request.Uri.ToString();
var rewritten = IsSocketScheme(original)
? NameserverRedirect.RewriteWebSocket(original, RadicadeEacBypassPlugin.ServerUrl.Value)
: NameserverRedirect.Rewrite(original, RadicadeEacBypassPlugin.ServerUrl.Value);
var withKeyId = ImageSignatureRequest.AddKeyId(rewritten, RadicadeEacBypassPlugin.ServerUrl.Value,
RadicadeEacBypassPlugin.ImageKeyId);
if (withKeyId != rewritten)
{
Diag.Trace("[ImageSig] stated key id on " + withKeyId);
}
rewritten = withKeyId;
if (rewritten != original)
{
request.Uri = new Il2CppSystem.Uri(rewritten);
AlignHostHeader(request, rewritten);
Diag.Trace("[Connection] Redirected nameserver request to the configured Radicade server.");
}
if (RealtimeDiagnostics.Verbose && IsSocketScheme(original))
{
try
{
var outgoing = new System.Text.StringBuilder("[Realtime] socket request: " + original);
var headers = request.Headers;
if (headers != null)
{
foreach (var header in headers)
{
outgoing.Append(" | ").Append(header.Key).Append("=");
var values = header.Value;
if (values != null)
foreach (var value in values) outgoing.Append(value).Append(",");
}
}
RadicadeEacBypassPlugin.LogSource.LogWarning(outgoing.ToString());
}
catch (Exception ex)
{
RadicadeEacBypassPlugin.LogSource.LogWarning("[Realtime] socket request dump failed: "
+ ex.GetType().Name + ": " + ex.Message);
}
}
HubSocketAuth.Capture(request);
HubSocketAuth.CaptureFromLoginResponse(request, request.Uri.ToString());
HubSocketAuth.AuthenticateHubRequest(request, request.Uri.ToString());
HubSocketAuth.AuthenticateServerRequest(request, request.Uri.ToString());
if (Diag.Verbose) AuthGrantTrace.Report(request);
HttpOutcomeTrace.Wrap(request);
return true;
}
private static void AlignHostHeader(HTTPRequest request, string url)
{
if (request == null || string.IsNullOrEmpty(url)) return;
Uri target;
if (!Uri.TryCreate(url, UriKind.Absolute, out target) || string.IsNullOrEmpty(target.Host)) return;
var authority = target.IsDefaultPort ? target.Host : target.Host + ":" + target.Port;
try
{
var stated = request.GetHeaderValues("Host");
if (stated != null && stated.Count > 0)
{
if (stated.Count == 1 && stated[0] == authority) return;
request.RemoveHeader("Host");
}
request.SetHeader("Host", authority);
}
catch (Exception ex)
{
RadicadeEacBypassPlugin.LogSource.LogWarning("[Connection] could not align the Host header on " + url +
": " + ex.GetType().Name + ": " + ex.Message);
}
}
}
internal static class AuthGrantTrace
{
private static readonly HashSet<long> Reported = new();
private static readonly string[] Fields =
{
"account_id", "username", "password", "birthday", "avatar", "avatarJson",
"email", "platform_auth", "device_id", "device_class", "client_id", "ver"
};
internal static void Report(HTTPRequest request)
{
try
{
if (request?.Uri == null) return;
if (!request.Uri.ToString().EndsWith("/auth/connect/token", StringComparison.OrdinalIgnoreCase)) return;
if (!Reported.Add(request.Pointer.ToInt64())) return;
var body = ReadBody(request);
if (string.IsNullOrEmpty(body))
{
RadicadeEacBypassPlugin.LogSource.LogWarning("[AuthGrant] connect/token body was unreadable; the grant is unknown for this request.");
return;
}
string Value(string name)
{
foreach (var pair in body.Split('&'))
{
var separator = pair.IndexOf('=');
if (separator <= 0) continue;
if (!string.Equals(pair.Substring(0, separator), name, StringComparison.OrdinalIgnoreCase)) continue;
return pair.Substring(separator + 1);
}
return null;
}
bool Present(string name)
{
var value = Value(name);
return !string.IsNullOrWhiteSpace(value);
}
var grant = Value("grant_type") ?? "<absent>";
var present = new List<string>();
foreach (var field in Fields)
if (Present(field)) present.Add(field);
RadicadeEacBypassPlugin.LogSource.LogInfo("[AuthGrant] connect/token grant_type=" + grant
+ "; fields present: " + (present.Count == 0 ? "<none>" : string.Join(", ", present))
+ " (values omitted)");
}
catch (Exception ex)
{
RadicadeEacBypassPlugin.LogSource.LogWarning("[AuthGrant] could not read the grant: " + ex.GetType().Name + ": " + ex.Message);
}
}
private static string ReadBody(HTTPRequest request)
{
try
{
var raw = request.RawData;
if (raw != null && raw.Length > 0) return System.Text.Encoding.UTF8.GetString(raw);
}
catch { }
try
{
var entity = request.GetEntityBody();
if (entity != null && entity.Length > 0) return System.Text.Encoding.UTF8.GetString(entity);
}
catch { }
return null;
}
}
[HarmonyPatch]
internal static class SendRequestImplFunnelPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
var impl = AccessTools.Method(typeof(HTTPManager), "SendRequestImpl", new[] { typeof(HTTPRequest) });
return impl == null ? Enumerable.Empty<MethodBase>() : new MethodBase[] { impl };
}
private static void Prefix(object[] __args)
{
try
{
if (__args == null || __args.Length == 0) return;
RequestFunnel.Handle(__args[0] as HTTPRequest);
}
catch (Exception ex)
{
Diag.Warn("[Net] funnel trace failed: " + ex.GetType().Name + ": " + ex.Message);
}
}
}
internal static class HttpOutcomeTrace
{
private static readonly HashSet<long> Wrapped = new();
private static int _completed;
internal static void Wrap(HTTPRequest request)
{
if (request == null) return;
string url;
string method;
string path;
string query;
try
{
if (request.Uri == null) return;
url = Shorten(request.Uri.ToString());
method = request.MethodType.ToString();
path = request.Uri.AbsolutePath;
query = request.Uri.Query;
}
catch
{
return;
}
try
{
if (!Wrapped.Add(request.Pointer.ToInt64())) return;
var original = request.Callback;
request.Callback = DelegateSupport.ConvertDelegate<OnRequestFinishedDelegate>(
new Action<HTTPRequest, HTTPResponse>((req, response) =>
{
try
{
HttpTolerancePatches.RepairResponse(response, path, query);
var completed = System.Threading.Interlocked.Increment(ref _completed);
var status = -1;
var bytes = 0;
var reason = string.Empty;
if (response != null)
{
status = response.StatusCode;
try { var data = response.Data; if (data != null) bytes = data.Length; } catch { }
try { if (!response.IsSuccess && !string.IsNullOrEmpty(response.Message)) reason = " reason=" + response.Message; } catch { }
}
Diag.Trace("[HttpStatus] #" + completed + " " + method + " " + url + " -> "
+ (response == null ? "NO RESPONSE" : status.ToString())
+ " bytes=" + bytes + reason);
if (RealtimeDiagnostics.Verbose && url.IndexOf("/notify/hub/v1", StringComparison.OrdinalIgnoreCase) >= 0)
{
try
{
var answer = new System.Text.StringBuilder();
answer.Append("[Realtime] socket answer: status=").Append(response == null ? -1 : status)
.Append(" message=").Append(response == null ? "<none>" : response.Message);
var answerHeaders = response?.Headers;
if (answerHeaders != null)
{
foreach (var header in answerHeaders)
{
answer.Append(" | ").Append(header.Key).Append("=");
var values = header.Value;
if (values != null)
foreach (var value in values) answer.Append(value).Append(",");
}
}
string body = null;
try { body = response?.DataAsText; } catch { }
if (!string.IsNullOrEmpty(body))
answer.Append(" | body=").Append(body.Length > 200 ? body.Substring(0, 200) : body);
RadicadeEacBypassPlugin.LogSource.LogWarning(answer.ToString());
}
catch (Exception ex)
{
RadicadeEacBypassPlugin.LogSource.LogWarning("[Realtime] socket answer dump failed: "
+ ex.GetType().Name + ": " + ex.Message);
}
}
}
catch
{
}
finally
{
try { original?.Invoke(req, response); } catch { }
}
}));
}
catch (Exception ex)
{
Diag.Warn("[HttpStatus] could not instrument " + method + " " + url + ": "
+ ex.GetType().Name + ": " + ex.Message);
}
}
private static string Shorten(string url)
{
try
{
var uri = new Uri(url);
var path = uri.AbsolutePath;
if (path.StartsWith("/auth/cachedlogin/forplatformid/", StringComparison.OrdinalIgnoreCase))
return "/auth/cachedlogin/forplatformid/{redacted}";
return path + (string.IsNullOrEmpty(uri.Query) ? string.Empty : "?" + uri.Query.Length + " chars");
}
catch
{
return "<unparsable>";
}
}
}