mirror of
https://git.xeondev.com/LR/C.git
synced 2026-02-03 22:55:19 +01:00
184 lines
7.8 KiB
Zig
184 lines
7.8 KiB
Zig
const std = @import("std");
|
|
const interceptor = @import("interceptor.zig");
|
|
const Il2cpp = @import("Il2cpp.zig");
|
|
const proxy_exports = @import("proxy_exports.zig");
|
|
|
|
const windows = std.os.windows;
|
|
const unicode = std.unicode;
|
|
const Io = std.Io;
|
|
|
|
const DLL_PROCESS_ATTACH = 1;
|
|
|
|
extern "kernel32" fn AllocConsole() callconv(.winapi) void;
|
|
extern "kernel32" fn FreeConsole() callconv(.winapi) void;
|
|
|
|
const gameassembly_name = unicode.utf8ToUtf16LeStringLiteral("GameAssembly.dll");
|
|
var base: usize = 0;
|
|
var il2cpp: Il2cpp = undefined;
|
|
|
|
pub const std_options: std.Options = .{
|
|
.logFn = colorlessLog,
|
|
};
|
|
|
|
fn onAttach() void {
|
|
const log = std.log.scoped(.lr);
|
|
|
|
FreeConsole();
|
|
AllocConsole();
|
|
|
|
std.debug.print(
|
|
\\ @
|
|
\\ #:@ @@@
|
|
\\ #@::#@ @:@%
|
|
\\ ##@::::@ @=::@%@
|
|
\\ *##@-:::::@ @##::::::::::==@ @@@%::::::@%%@
|
|
\\ @###@=:::@@#::::::::::-@*#%=::@::::::@@%%@
|
|
\\ @#####@==*@@%#########@@@:#*+=::@@@##@%%%@
|
|
\\ %####@%%@#%%#:=:=::#%%%%@@:@#@::@**@%%%@
|
|
\\ *##@%%%@%%:@#@#+**@@@%%:%@#%%%@-:@@%%%%
|
|
\\ @@+*#@:#%%%%:@##@@@@@@#@:%@*%%%%%%%@@%@@*##@@
|
|
\\ @+*##@@@#%#@*@########%%@%%%%%%%@@#@-@##++##@
|
|
\\ @@%#@*##@@#+++***********@%%%@@@*####@#@*+*##@
|
|
\\ @==+@@*##@*++@++++++++++++++*@#%-@**##@=@@*++@@
|
|
\\ @===%+:@##@-****@=++++++++++*#++***@---*##=-@#@##*++*@@@
|
|
\\ **@@@:-@==##%@@@@====+++++**.+++++*@--=*##+-@....@**++@
|
|
\\ @@---=--@#@#@@ #@@......-@@@@@@=..%@:-=##@-=@..@####@
|
|
\\ @--@+--=@+@:@#######@.......@@@@@.@.@+#@:#:--=@@@##@@
|
|
\\ @:----=*@::::#--###@.......@ .###%..++**#@---=@=-@#**@
|
|
\\ @@==@-=@#=@::::::%@@@.........@######@@++***:----===-@#*++@
|
|
\\@===**##*==@::::::....@.........#--##@:@++***#@:----=@###++++@
|
|
\\ @@%#@**=++@::::......@@@@@@....:@+:::::@**###@:---@@@##*++++@
|
|
\\ @++@==++**@:................:::::::@ %**##@*#@@#*# %#**+@
|
|
\\ ++@==++**@@ @@@............:#@ @+***@#*******@
|
|
\\ @++===++**@ @+***###*******@
|
|
\\ @++@===+***#@ ++****#%##******@
|
|
\\ @++++*@%=+**@@ @++***##@###*****@
|
|
\\ @@@@@@@ *++*####%@###**@
|
|
\\ @@@@@##@ @@@
|
|
\\
|
|
, .{});
|
|
|
|
var threaded: Io.Threaded = .init_single_threaded;
|
|
defer threaded.deinit();
|
|
const io = threaded.ioBasic();
|
|
|
|
log.info("Successfully injected. Waiting for the game startup.", .{});
|
|
|
|
while (base == 0) : (base = @intFromPtr(windows.kernel32.GetModuleHandleW(gameassembly_name))) {
|
|
io.sleep(.fromNanoseconds(200 * std.time.ns_per_ms), .awake) catch {};
|
|
} else {
|
|
io.sleep(.fromSeconds(2), .awake) catch {};
|
|
}
|
|
|
|
log.info("GameAssembly: {X}", .{base});
|
|
|
|
il2cpp = Il2cpp.link(@ptrFromInt(base)) catch |err| {
|
|
log.err("failed to link il2cpp symbols: {t}", .{err});
|
|
return;
|
|
};
|
|
|
|
const domain = il2cpp.domain_get();
|
|
const uwr_module = il2cpp.assembly_get_image(il2cpp.domain_assembly_open(domain, "UnityEngine.UnityWebRequestModule.dll").?);
|
|
const web_request_utils = il2cpp.class_from_name(uwr_module, "UnityEngineInternal", "WebRequestUtils").?;
|
|
const unity_web_request = il2cpp.class_from_name(uwr_module, "UnityEngine.Networking", "UnityWebRequest").?;
|
|
|
|
const make_initial_url = il2cpp.class_get_method_from_name(web_request_utils, "MakeInitialUrl", 2).?;
|
|
const internal_set_url = il2cpp.class_get_method_from_name(unity_web_request, "InternalSetUrl", 1).?;
|
|
const set_url = il2cpp.class_get_method_from_name(unity_web_request, "set_url", 1).?;
|
|
|
|
const gameplay_module = il2cpp.assembly_get_image(il2cpp.domain_assembly_open(domain, "Gameplay.Beyond.dll").?);
|
|
const camera_mono = il2cpp.class_from_name(gameplay_module, "Beyond.Gameplay.View", "CameraMono").?;
|
|
const evaluate_all_touched_entities = il2cpp.class_get_method_from_name(camera_mono, "EvaluateAllTouchedEntities", 0).?;
|
|
|
|
WebRequestPatch.init(set_url.address, make_initial_url.address, internal_set_url.address);
|
|
SloppyRSAPatch.init();
|
|
interceptor.write(evaluate_all_touched_entities.address, &.{0xC3}); // Dither
|
|
|
|
log.info("Successfully initialized! Time to play Endfield!", .{});
|
|
}
|
|
|
|
// Patch out the SRSA (Sloppy RSA)
|
|
const SloppyRSAPatch = struct {
|
|
const write_srsa_check: usize = 0xA20ABFF;
|
|
const read_srsa_check: usize = 0xA20B354;
|
|
|
|
pub fn init() void {
|
|
interceptor.write(base + write_srsa_check, &.{ 0x90, 0x90 });
|
|
interceptor.write(base + read_srsa_check, &.{ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 });
|
|
}
|
|
};
|
|
|
|
const WebRequestPatch = struct {
|
|
const log = std.log.scoped(.uwr);
|
|
const https_prefix = "https://";
|
|
|
|
var uwrInternalSetUrl: *const fn (uwr: *anyopaque, url: *Il2cpp.String) callconv(.c) void = undefined;
|
|
var makeInitialUrl: *const fn (target: *Il2cpp.String, local: *Il2cpp.String) callconv(.c) *Il2cpp.String = undefined;
|
|
|
|
pub fn init(uwr_set_url: usize, make_initial_url: usize, uwr_internal_set_url: usize) void {
|
|
makeInitialUrl = @ptrFromInt(make_initial_url);
|
|
uwrInternalSetUrl = @ptrFromInt(uwr_internal_set_url);
|
|
|
|
interceptor.replace(uwr_set_url, onUwrSetUrl);
|
|
}
|
|
|
|
fn onUwrSetUrl(uwr: *anyopaque, url_string: *Il2cpp.String) callconv(.c) void {
|
|
var utf8_conversion_buf: [8192]u8 = undefined;
|
|
var replacement_buf: [8192]u8 = undefined;
|
|
const localhost = il2cpp.string_new("http://localhost/");
|
|
|
|
const url = url_string.toUtf8(&utf8_conversion_buf) catch |err| {
|
|
log.err("failed to convert URL to utf8: {t}", .{err});
|
|
return uwrInternalSetUrl(uwr, makeInitialUrl(url_string, localhost));
|
|
};
|
|
|
|
log.debug("{s}", .{url});
|
|
|
|
if (std.mem.startsWith(u8, url, https_prefix)) {
|
|
if (std.mem.findScalar(u8, url[https_prefix.len..], '/')) |i| {
|
|
const replacement = std.fmt.bufPrintSentinel(
|
|
&replacement_buf,
|
|
"{s}/{s}",
|
|
.{ "http://127.0.0.1:10001", url[https_prefix.len + i + 1 ..] },
|
|
0,
|
|
) catch |err| {
|
|
log.err("failed to replace url: {t} (url: {s})", .{ err, url });
|
|
return uwrInternalSetUrl(uwr, makeInitialUrl(url_string, localhost));
|
|
};
|
|
|
|
log.debug("replacement: {s}", .{replacement});
|
|
return uwrInternalSetUrl(uwr, makeInitialUrl(il2cpp.string_new(replacement), localhost));
|
|
}
|
|
}
|
|
|
|
uwrInternalSetUrl(uwr, makeInitialUrl(url_string, localhost));
|
|
}
|
|
};
|
|
|
|
pub export fn DllMain(_: windows.HINSTANCE, reason: windows.DWORD, _: windows.LPVOID) callconv(.winapi) windows.BOOL {
|
|
if (reason == DLL_PROCESS_ATTACH) {
|
|
if (windows.kernel32.LoadLibraryW(unicode.utf8ToUtf16LeStringLiteral("gfsdk_original.dll"))) |lib| {
|
|
proxy_exports.link(lib);
|
|
}
|
|
|
|
const thread = std.Thread.spawn(.{}, onAttach, .{}) catch unreachable;
|
|
thread.detach();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
fn colorlessLog(
|
|
comptime level: std.log.Level,
|
|
comptime scope: @EnumLiteral(),
|
|
comptime format: []const u8,
|
|
args: anytype,
|
|
) void {
|
|
var buffer: [64]u8 = undefined;
|
|
var stderr = std.debug.lockStderr(&buffer).terminal();
|
|
defer std.debug.unlockStderr();
|
|
|
|
stderr.mode = .no_color;
|
|
return std.log.defaultLogFileTerminal(level, scope, format, args, stderr) catch {};
|
|
}
|