mirror of
https://git.xeondev.com/LR/C.git
synced 2026-02-04 07:05:04 +01:00
Release 1.0.14
This commit is contained in:
183
src/root.zig
Normal file
183
src/root.zig
Normal file
@@ -0,0 +1,183 @@
|
||||
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 {};
|
||||
}
|
||||
Reference in New Issue
Block a user