From 8861b07cb8872713f1bcbe8cf6bda0d2d23a8151 Mon Sep 17 00:00:00 2001 From: amizing25 Date: Fri, 14 Mar 2025 14:49:05 +0700 Subject: [PATCH] initial commit --- .gitignore | 2 + Cargo.lock | 332 ++++++++++++++++++++++++++ Cargo.toml | 27 +++ README.md | 10 + ext/Cargo.toml | 12 + ext/src/lib.rs | 9 + hkrpg/Cargo.toml | 9 + hkrpg/src/addr.rs | 117 +++++++++ hkrpg/src/il2cpp_string.rs | 43 ++++ hkrpg/src/interceptor.rs | 41 ++++ hkrpg/src/lib.rs | 41 ++++ hkrpg/src/modules/censorship_patch.rs | 43 ++++ hkrpg/src/modules/hk_check.rs | 30 +++ hkrpg/src/modules/mod.rs | 51 ++++ hkrpg/src/modules/network.rs | 60 +++++ hkrpg/src/util.rs | 86 +++++++ launcher/Cargo.toml | 7 + launcher/src/main.rs | 106 ++++++++ mhypbase/Cargo.toml | 12 + mhypbase/build.rs | 7 + mhypbase/mhypbase.def | 3 + mhypbase/src/lib.rs | 27 +++ 22 files changed, 1075 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 ext/Cargo.toml create mode 100644 ext/src/lib.rs create mode 100644 hkrpg/Cargo.toml create mode 100644 hkrpg/src/addr.rs create mode 100644 hkrpg/src/il2cpp_string.rs create mode 100644 hkrpg/src/interceptor.rs create mode 100644 hkrpg/src/lib.rs create mode 100644 hkrpg/src/modules/censorship_patch.rs create mode 100644 hkrpg/src/modules/hk_check.rs create mode 100644 hkrpg/src/modules/mod.rs create mode 100644 hkrpg/src/modules/network.rs create mode 100644 hkrpg/src/util.rs create mode 100644 launcher/Cargo.toml create mode 100644 launcher/src/main.rs create mode 100644 mhypbase/Cargo.toml create mode 100644 mhypbase/build.rs create mode 100644 mhypbase/mhypbase.def create mode 100644 mhypbase/src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ccb5166 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +.vscode \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d483f8b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,332 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "ext" +version = "0.1.0" +dependencies = [ + "hkrpg", + "windows", +] + +[[package]] +name = "hkrpg" +version = "0.1.0" +dependencies = [ + "ilhook", + "patternscan", + "windows", +] + +[[package]] +name = "iced-x86" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "ilhook" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7900295ca4c0c37e0325ddbf4b2b78cecabdb36d75d02712c31fb7d777e658f6" +dependencies = [ + "bitflags", + "iced-x86", + "lazy_static", + "libc", + "regex", + "thiserror", + "windows-sys", +] + +[[package]] +name = "launcher" +version = "0.1.0" +dependencies = [ + "windows", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mhypbase" +version = "0.1.0" +dependencies = [ + "hkrpg", + "windows", +] + +[[package]] +name = "patternscan" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf9ac94ae7c3d7f743ec57e0b6b05077631c1a90c6cea9b162a69efa6d6bbde" + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..fd6e973 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,27 @@ +[workspace] +members = ["hkrpg", "launcher", "mhypbase", "ext"] + +resolver = "2" + +[workspace.package] +version = "0.1.0" + +[workspace.dependencies] +windows = { version = "0.54.0", features = [ + "Win32_Foundation", + "Win32_System_SystemServices", + "Win32_System_LibraryLoader", + "Win32_System_Console", + "Win32_System_Threading", + "Win32_System_Memory", + "Win32_System_Diagnostics", + "Win32_Security", + "Win32_System_Diagnostics_Debug", + "Win32_System_ProcessStatus", + "Win32_System_SystemInformation", +] } +ilhook = "2.1.1" +patternscan = "1.2.0" + +# Local crates +hkrpg = { path = "hkrpg/" } diff --git a/README.md b/README.md new file mode 100644 index 0000000..08fcbad --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +redirect HTTP requests & remove censorship! + +currently, this has only been tested on CNBETAWin3.1.53 and may require an update for future versions. + +note: if you plan to use `mhypbase.dll`, please make a copy of the original first in case something breaks. Otherwise, simply copy `hkrpg.dll` and `launcher.exe` into the game folder and run `launcher.exe` as an administrator. + +Sources: + +- [trigger-patch by xeondev](https://git.xeondev.com/ObolSquad/trigger-patch) +- [hk4e-patch-universal by oureveryday](https://github.com/oureveryday/hk4e-patch-universal) diff --git a/ext/Cargo.toml b/ext/Cargo.toml new file mode 100644 index 0000000..89085e4 --- /dev/null +++ b/ext/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ext" +edition = "2024" +version.workspace = true + +[lib] +name = "hkrpg" +crate-type = ["cdylib"] + +[dependencies] +windows.workspace = true +hkrpg.workspace = true diff --git a/ext/src/lib.rs b/ext/src/lib.rs new file mode 100644 index 0000000..5d3dd8b --- /dev/null +++ b/ext/src/lib.rs @@ -0,0 +1,9 @@ +use windows::Win32::{Foundation::HINSTANCE, System::SystemServices::DLL_PROCESS_ATTACH}; + +#[allow(non_snake_case)] +#[unsafe(no_mangle)] +unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) { + if call_reason == DLL_PROCESS_ATTACH { + std::thread::spawn(hkrpg::main); + } +} diff --git a/hkrpg/Cargo.toml b/hkrpg/Cargo.toml new file mode 100644 index 0000000..3b493dd --- /dev/null +++ b/hkrpg/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hkrpg" +edition = "2024" +version.workspace = true + +[dependencies] +windows.workspace = true +ilhook.workspace = true +patternscan.workspace = true \ No newline at end of file diff --git a/hkrpg/src/addr.rs b/hkrpg/src/addr.rs new file mode 100644 index 0000000..2638c16 --- /dev/null +++ b/hkrpg/src/addr.rs @@ -0,0 +1,117 @@ +use std::sync::{LazyLock, OnceLock}; + +use windows::{Win32::System::LibraryLoader::GetModuleHandleA, core::s}; + +use crate::util::{scan_il2cpp_section, scan_unity_player_section}; + +const PTR_TO_STRING_ANSI: &str = "E8 ? ? ? ? 48 ? ? 48 85 C0 75 ? 48 8D 4C 24"; +const MAKE_INITIAL_URL: &str = "55 41 56 56 57 53 48 83 EC ? 48 8D 6C 24 ? 48 C7 45 ? ? ? ? ? 48 89 D6 48 89 CF E8 ? ? ? ? 84 C0"; // TODO +const SET_ELEVATION_DITHER: &str = "E9 ? ? ? ? 0F 28 74 24 ? 48 83 C4 ? 5B 5F 5E 41 5E 41 5F C3 31 F6"; // TODO +const SET_DISTANCE_DITHER: &str = "E8 ? ? ? ? 49 8B 46 ? 48 85 C0 0F 84 ? ? ? ? 48 8B 4D"; // TODO +const SET_DITHER_ALPHA: &str = "56 57 48 83 EC ? 0F 29 74 24 ? 44 89 C6 0F 28 F1 48 89 CF 80 3D ? ? ? ? ? 75 ? 80 7F"; // TODO +const SET_DITHER_ALPHA_ANIM: &str = "56 57 55 53 48 83 EC ? 44 0F 29 44 24 ? 0F 29 7C 24 ? 0F 29 74 24 ? 44 0F 28 C3 0F 28 F2 0F 28 F9"; // TODO +const HK_CHECK1: &str = "55 41 56 56 57 53 48 81 EC 00 01 00 00 48 8D AC 24 80 00 00 00 C7 45 7C 00 00 00 00"; +const HK_CHECK2: &str = "55 41 57 41 56 41 55 41 54 56 57 53 48 81 EC B8 02 00 00"; + +#[derive(Default)] +pub struct RVAConfig { + pub ptr_to_string_ansi: usize, + pub make_initial_url: usize, + pub set_elevation_dither: usize, + pub set_distance_dither: usize, + pub set_dither_alpha: usize, + pub set_dither_alpha_anim: usize, + pub hk_check1: usize, + pub hk_check2: usize, +} + +#[allow(static_mut_refs)] +pub fn rva_config() -> &'static mut RVAConfig { + static mut RVA_CONFIG: OnceLock = OnceLock::new(); + unsafe { RVA_CONFIG.get_mut_or_init(RVAConfig::default) } +} + +pub static GAME_ASSEMBLY_BASE: LazyLock = + LazyLock::new(|| unsafe { GetModuleHandleA(s!("GameAssembly.dll")).unwrap().0 as usize }); + +pub static UNITY_PLAYER_BASE: LazyLock = + LazyLock::new(|| unsafe { GetModuleHandleA(s!("UnityPlayer.dll")).unwrap().0 as usize }); + +macro_rules! set_rva { + ($config:ident, $field:ident, $scan_fn:ident, $rva_pat:expr, $fallback:expr) => { + if let Some(addr) = unsafe { $scan_fn($rva_pat) } { + $config.$field = addr - *GAME_ASSEMBLY_BASE; + println!( + "[hkrpg::addr::set_rva] Found relative address for {} -> 0x{:X}", + stringify!($field), + $config.$field + ); + } else { + eprintln!( + "[hkrpg::addr::set_rva] Failed to find pattern for {} using {}", + stringify!($field), + stringify!($scan_fn) + ); + + $config.$field = $fallback + } + }; +} + +pub unsafe fn init_rvas() { + let config = rva_config(); + + // ptr_to_string_ansi + set_rva!( + config, + ptr_to_string_ansi, + scan_il2cpp_section, + PTR_TO_STRING_ANSI, + 0x0 + ); + + // make_initial_url + set_rva!( + config, + make_initial_url, + scan_il2cpp_section, + MAKE_INITIAL_URL, + 0x0 + ); + + // set_elevation_dither + set_rva!( + config, + set_elevation_dither, + scan_il2cpp_section, + SET_ELEVATION_DITHER, + 0x0 + ); + // set_distance_dither + set_rva!( + config, + set_distance_dither, + scan_il2cpp_section, + SET_DISTANCE_DITHER, + 0x0 + ); + // set_dither_alpha + set_rva!( + config, + set_dither_alpha, + scan_il2cpp_section, + SET_DITHER_ALPHA, + 0x0 + ); + // set_dither_alpha_anim + set_rva!( + config, + set_dither_alpha_anim, + scan_il2cpp_section, + SET_DITHER_ALPHA_ANIM, + 0x0 + ); + + set_rva!(config, hk_check1, scan_unity_player_section, HK_CHECK1, 0x0); + set_rva!(config, hk_check2, scan_unity_player_section, HK_CHECK2, 0x0); +} diff --git a/hkrpg/src/il2cpp_string.rs b/hkrpg/src/il2cpp_string.rs new file mode 100644 index 0000000..5ddec1d --- /dev/null +++ b/hkrpg/src/il2cpp_string.rs @@ -0,0 +1,43 @@ +use std::{ffi::CString, fmt::Display}; + +use crate::addr::{GAME_ASSEMBLY_BASE, rva_config}; + +#[repr(transparent)] +pub struct Il2cppString(usize); + +impl From for Il2cppString { + fn from(value: u64) -> Self { + Self(value as usize) + } +} + +impl Il2cppString { + pub fn new(string: &str) -> Self { + let func = unsafe { + std::mem::transmute:: usize>( + *GAME_ASSEMBLY_BASE + rva_config().ptr_to_string_ansi, + ) + }; + let len = string.len(); + let string = CString::new(string).unwrap(); + let string = string.as_c_str(); + Self(func(string.to_bytes_with_nul().as_ptr(), len)) + } + + pub fn raw(&self) -> u64 { + self.0 as u64 + } +} + +impl Display for Il2cppString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str_length = unsafe { *(self.0.wrapping_add(16) as *const u32) }; + let str_ptr = self.0.wrapping_add(20) as *const u8; + let slice = unsafe { std::slice::from_raw_parts(str_ptr, (str_length * 2) as usize) }; + write!( + f, + "{}", + String::from_utf16le(slice).map_err(|_| std::fmt::Error)? + ) + } +} diff --git a/hkrpg/src/interceptor.rs b/hkrpg/src/interceptor.rs new file mode 100644 index 0000000..e7124a4 --- /dev/null +++ b/hkrpg/src/interceptor.rs @@ -0,0 +1,41 @@ +use ilhook::x64::{ + CallbackOption, HookFlags, HookPoint, HookType, Hooker, JmpBackRoutine, RetnRoutine, +}; + +#[derive(Default)] +pub struct Interceptor { + hooks: Vec, +} + +type Result = std::result::Result; +impl Interceptor { + pub fn attach(&mut self, addr: usize, routine: JmpBackRoutine) -> Result<()> { + let hooker = Hooker::new( + addr, + HookType::JmpBack(routine), + CallbackOption::None, + 0, + HookFlags::empty(), + ); + + let hook_point = unsafe { hooker.hook() }?; + self.hooks.push(hook_point); + + Ok(()) + } + + pub fn replace(&mut self, addr: usize, routine: RetnRoutine) -> Result<()> { + let hooker = Hooker::new( + addr, + HookType::Retn(routine), + CallbackOption::None, + 0, + HookFlags::empty(), + ); + + let hook_point = unsafe { hooker.hook() }?; + self.hooks.push(hook_point); + + Ok(()) + } +} diff --git a/hkrpg/src/lib.rs b/hkrpg/src/lib.rs new file mode 100644 index 0000000..cf0c8fd --- /dev/null +++ b/hkrpg/src/lib.rs @@ -0,0 +1,41 @@ +#![feature(str_from_utf16_endian, once_cell_get_mut)] + +use std::{thread, time::Duration}; + +use modules::{ + HkrpgModuleManager, censorship_patch::CensorshipPatch, hk_check::HkCheck, network::Network, +}; +use windows::{ + Win32::System::{Console, LibraryLoader::GetModuleHandleA}, + core::s, +}; + +mod addr; +mod il2cpp_string; +mod interceptor; +mod modules; +mod util; + +pub fn main() { + unsafe { + let _ = Console::AllocConsole(); + + println!("[hkrpg::main] init"); + + while GetModuleHandleA(s!("GameAssembly.dll")).is_err() { + thread::sleep(Duration::from_millis(200)); + } + + addr::init_rvas(); + + let mut module_manager = HkrpgModuleManager::default(); + module_manager.add::(); + module_manager.add::(); + module_manager.add::(); + module_manager + .init() + .expect("[hkrpg::main] failed to initialize modules"); + + thread::sleep(Duration::from_secs(u64::MAX)); + } +} diff --git a/hkrpg/src/modules/censorship_patch.rs b/hkrpg/src/modules/censorship_patch.rs new file mode 100644 index 0000000..f8a6725 --- /dev/null +++ b/hkrpg/src/modules/censorship_patch.rs @@ -0,0 +1,43 @@ +use ilhook::x64::Registers; + +use crate::addr::rva_config; + +use super::{HkrpgModule, HkrpgModuleContext}; + +pub struct CensorshipPatch; + +macro_rules! replace { + ($self:ident, $config:ident, $($field:ident),*) => { + $( + if $config.$field != 0 { + $self.interceptor.replace( + $self.base.wrapping_add($config.$field), + CensorshipPatch::on_set_dither, + )?; + } else { + println!("[censorship_patch::init] pattern is outdated! disabling dither patch for {}", stringify!($field)); + } + )* + }; +} + +impl HkrpgModule for HkrpgModuleContext { + unsafe fn init(&mut self) -> Result<(), ilhook::HookError> { + let config = rva_config(); + replace!( + self, + config, + set_distance_dither, + set_elevation_dither, + set_dither_alpha, + set_dither_alpha_anim + ); + Ok(()) + } +} + +impl CensorshipPatch { + pub unsafe extern "win64" fn on_set_dither(_: *mut Registers, _: usize, _: usize) -> usize { + 0 + } +} diff --git a/hkrpg/src/modules/hk_check.rs b/hkrpg/src/modules/hk_check.rs new file mode 100644 index 0000000..22a926c --- /dev/null +++ b/hkrpg/src/modules/hk_check.rs @@ -0,0 +1,30 @@ +use ilhook::x64::Registers; + +use crate::addr::rva_config; + +use super::{HkrpgModule, HkrpgModuleContext}; + +pub struct HkCheck; + +impl HkrpgModule for HkrpgModuleContext { + unsafe fn init(&mut self) -> Result<(), ilhook::HookError> { + let config = rva_config(); + if config.hk_check1 != 0 && config.hk_check2 != 0 { + self.interceptor.replace( + self.base.wrapping_add(config.hk_check1), + HkCheck::replacement, + )?; + self.interceptor.replace( + self.base.wrapping_add(config.hk_check2), + HkCheck::replacement, + )?; + } + Ok(()) + } +} + +impl HkCheck { + extern "win64" fn replacement(_: *mut Registers, _: usize, _: usize) -> usize { + 0 + } +} diff --git a/hkrpg/src/modules/mod.rs b/hkrpg/src/modules/mod.rs new file mode 100644 index 0000000..57d179a --- /dev/null +++ b/hkrpg/src/modules/mod.rs @@ -0,0 +1,51 @@ +use std::marker::PhantomData; + +use crate::{addr, interceptor::Interceptor}; + +pub mod censorship_patch; +pub mod hk_check; +pub mod network; + +pub struct HkrpgModuleContext { + base: usize, + interceptor: Interceptor, + _module_type: PhantomData, +} + +impl HkrpgModuleContext { + fn new(base: usize) -> Self { + Self { + base, + interceptor: Interceptor::default(), + _module_type: PhantomData, + } + } +} + +pub trait HkrpgModule { + unsafe fn init(&mut self) -> Result<(), ilhook::HookError>; +} + +#[derive(Default)] +pub struct HkrpgModuleManager { + modules: Vec>, +} + +impl HkrpgModuleManager { + pub fn add(&mut self) + where + HkrpgModuleContext: HkrpgModule, + { + self.modules.push(Box::new(HkrpgModuleContext::::new( + *addr::GAME_ASSEMBLY_BASE, + ))); + } + + pub unsafe fn init(&mut self) -> Result<(), ilhook::HookError> { + for module in self.modules.iter_mut() { + unsafe { module.init() }?; + } + + Ok(()) + } +} diff --git a/hkrpg/src/modules/network.rs b/hkrpg/src/modules/network.rs new file mode 100644 index 0000000..e57ead9 --- /dev/null +++ b/hkrpg/src/modules/network.rs @@ -0,0 +1,60 @@ +use ilhook::x64::Registers; + +use crate::{addr::rva_config, il2cpp_string::Il2cppString}; + +use super::{HkrpgModule, HkrpgModuleContext}; + +pub struct Network; + +impl HkrpgModule for HkrpgModuleContext { + unsafe fn init(&mut self) -> Result<(), ilhook::HookError> { + let config = rva_config(); + if config.make_initial_url != 0 && config.ptr_to_string_ansi != 0 { + self.interceptor.attach( + self.base.wrapping_add(config.make_initial_url), + Network::on_make_initial_url, + )?; + } else { + println!("[network::init] pattern is outdated! disabling http redirection") + } + Ok(()) + } +} + +impl Network { + const SDK_URL: &str = "http://127.0.0.1:21000"; + // const DISPATCH_URL: &str = "http://127.0.0.1:21000"; + const REDIRECT_SDK: bool = true; + const REDIRECT_DISPATCH: bool = true; + + extern "win64" fn on_make_initial_url(reg: *mut Registers, _: usize) { + let url = unsafe { Il2cppString::from((*reg).rcx).to_string() }; + + let mut new_url = match &url { + s if (s.contains("mihoyo.com") || s.contains("hoyoverse.com")) + && Self::REDIRECT_SDK => + { + Self::SDK_URL.to_string() + } + s if (s.contains("bhsr.com") || s.contains("starrails.com")) + && Self::REDIRECT_DISPATCH => + { + Self::SDK_URL.to_string() + } + s => { + println!("Leaving request as-is: {s}"); + return; + } + }; + + url.split('/').skip(3).for_each(|s| { + new_url.push('/'); + new_url.push_str(s); + }); + + println!("UnityWebRequest: \"{url}\", replacing with \"{new_url}\""); + unsafe { + (*reg).rcx = Il2cppString::new(&new_url).raw() as u64; + } + } +} diff --git a/hkrpg/src/util.rs b/hkrpg/src/util.rs new file mode 100644 index 0000000..bcde408 --- /dev/null +++ b/hkrpg/src/util.rs @@ -0,0 +1,86 @@ +use std::cell::OnceCell; + +use patternscan::scan_first_match; +use windows::{ + Win32::System::{ + LibraryLoader::GetModuleHandleA, + ProcessStatus::{GetModuleInformation, MODULEINFO}, + Threading::GetCurrentProcess, + }, + core::s, +}; + +use crate::addr::{GAME_ASSEMBLY_BASE, UNITY_PLAYER_BASE}; + +#[allow(static_mut_refs)] +unsafe fn game_assembly_slice() -> &'static [u8] { + static mut SLICE: OnceCell<&[u8]> = OnceCell::new(); + unsafe { + SLICE.get_or_init(|| { + let module = GetModuleHandleA(s!("GameAssembly.dll")).unwrap(); + let mut module_info = MODULEINFO { + lpBaseOfDll: std::ptr::null_mut(), + SizeOfImage: 0, + EntryPoint: std::ptr::null_mut(), + }; + GetModuleInformation( + GetCurrentProcess(), + module, + &mut module_info, + std::mem::size_of::() as u32, + ) + .unwrap(); + std::slice::from_raw_parts( + module.0 as *const u8, + module_info.SizeOfImage.try_into().unwrap(), + ) + }) + } +} + +#[allow(static_mut_refs)] +unsafe fn unity_player_slice() -> &'static [u8] { + static mut SLICE: OnceCell<&[u8]> = OnceCell::new(); + unsafe { + SLICE.get_or_init(|| { + let module = GetModuleHandleA(s!("UnityPlayer.dll")).unwrap(); + let mut module_info = MODULEINFO { + lpBaseOfDll: std::ptr::null_mut(), + SizeOfImage: 0, + EntryPoint: std::ptr::null_mut(), + }; + GetModuleInformation( + GetCurrentProcess(), + module, + &mut module_info, + std::mem::size_of::() as u32, + ) + .unwrap(); + std::slice::from_raw_parts( + module.0 as *const u8, + module_info.SizeOfImage.try_into().unwrap(), + ) + }) + } +} + +pub unsafe fn scan_il2cpp_section(pat: &str) -> Option { + let mut slice = unsafe { game_assembly_slice() }; + scan_first_match(&mut slice, pat).unwrap().map(|address| { + let slice = unsafe { game_assembly_slice() }; + let instruction = &slice[address..address + 1][0]; + if *instruction == 0xE8 { + let offset = i32::from_le_bytes((&slice[address + 1..address + 1 + 4]).try_into().unwrap()); + let pointer = offset as usize + 5 + address; + return GAME_ASSEMBLY_BASE.wrapping_add(pointer); + } + GAME_ASSEMBLY_BASE.wrapping_add(address) + }) +} + +pub unsafe fn scan_unity_player_section(pat: &str) -> Option { + let mut slice = unsafe { unity_player_slice() }; + scan_first_match(&mut slice, pat) + .unwrap() + .map(|loc| UNITY_PLAYER_BASE.wrapping_add(loc)) +} diff --git a/launcher/Cargo.toml b/launcher/Cargo.toml new file mode 100644 index 0000000..2d96329 --- /dev/null +++ b/launcher/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "launcher" +edition = "2024" +version.workspace = true + +[dependencies] +windows.workspace = true \ No newline at end of file diff --git a/launcher/src/main.rs b/launcher/src/main.rs new file mode 100644 index 0000000..23828e0 --- /dev/null +++ b/launcher/src/main.rs @@ -0,0 +1,106 @@ +// Source: https://git.xeondev.com/NewEriduPubSec/JaneDoe-Patch/src/branch/master/launcher/src/main.rs + +use std::ffi::CString; + +use std::ptr::null_mut; +use windows::Win32::Foundation::{CloseHandle, GetLastError, HANDLE}; +use windows::Win32::System::Diagnostics::Debug::WriteProcessMemory; +use windows::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress}; +use windows::Win32::System::Memory::{ + MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, VirtualAllocEx, VirtualFreeEx, +}; +use windows::Win32::System::Threading::{ + CREATE_SUSPENDED, CreateProcessA, CreateRemoteThread, PROCESS_INFORMATION, ResumeThread, + STARTUPINFOA, WaitForSingleObject, +}; +use windows::core::{PSTR, s}; + +fn inject_standard(h_target: HANDLE, dll_path: &str) -> bool { + unsafe { + let loadlib = GetProcAddress( + GetModuleHandleA(s!("kernel32.dll")).unwrap(), + s!("LoadLibraryA"), + ) + .unwrap(); + + let dll_path_cstr = CString::new(dll_path).unwrap(); + let dll_path_addr = VirtualAllocEx( + h_target, + None, + dll_path_cstr.to_bytes_with_nul().len(), + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE, + ); + if dll_path_addr.is_null() { + println!( + "Failed allocating memory in the target process. GetLastError(): {:?}", + GetLastError() + ); + return false; + } + + WriteProcessMemory( + h_target, + dll_path_addr, + dll_path_cstr.as_ptr() as _, + dll_path_cstr.to_bytes_with_nul().len(), + None, + ) + .unwrap(); + + let h_thread = CreateRemoteThread( + h_target, + None, + 0, + Some(std::mem::transmute::< + unsafe extern "system" fn() -> isize, + unsafe extern "system" fn(*mut std::ffi::c_void) -> u32, + >(loadlib)), + Some(dll_path_addr), + 0, + None, + ) + .unwrap(); + + WaitForSingleObject(h_thread, 0xFFFFFFFF); + + VirtualFreeEx(h_target, dll_path_addr, 0, MEM_RELEASE).unwrap(); + CloseHandle(h_thread).unwrap(); + true + } +} + +fn main() { + let current_dir = std::env::current_dir().unwrap(); + let dll_path = current_dir.join("hkrpg.dll"); + if !dll_path.is_file() { + println!("hkrpg.dll not found"); + return; + } + + let mut proc_info = PROCESS_INFORMATION::default(); + let startup_info = STARTUPINFOA::default(); + + unsafe { + CreateProcessA( + s!("StarRail.exe"), + PSTR(null_mut()), + None, + None, + false, + CREATE_SUSPENDED, + None, + None, + &startup_info, + &mut proc_info, + ) + .unwrap(); + + if inject_standard(proc_info.hProcess, dll_path.to_str().unwrap()) { + ResumeThread(proc_info.hThread); + } + + CloseHandle(proc_info.hThread).unwrap(); + CloseHandle(proc_info.hProcess).unwrap(); + } +} diff --git a/mhypbase/Cargo.toml b/mhypbase/Cargo.toml new file mode 100644 index 0000000..211775c --- /dev/null +++ b/mhypbase/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "mhypbase" +edition = "2024" +version.workspace = true + +[lib] +name = "mhypbase" +crate-type = ["cdylib"] + +[dependencies] +windows.workspace = true +hkrpg.workspace = true diff --git a/mhypbase/build.rs b/mhypbase/build.rs new file mode 100644 index 0000000..a6b1f5b --- /dev/null +++ b/mhypbase/build.rs @@ -0,0 +1,7 @@ +fn main() { + println!( + "cargo:rustc-link-search=native={}", + std::env::var("OUT_DIR").unwrap() + ); + println!("cargo:rustc-link-arg=/DEF:mhypbase/mhypbase.def"); +} diff --git a/mhypbase/mhypbase.def b/mhypbase/mhypbase.def new file mode 100644 index 0000000..e60fc26 --- /dev/null +++ b/mhypbase/mhypbase.def @@ -0,0 +1,3 @@ +LIBRARY MHYPBASE +EXPORTS + Initialize @1 diff --git a/mhypbase/src/lib.rs b/mhypbase/src/lib.rs new file mode 100644 index 0000000..22c3983 --- /dev/null +++ b/mhypbase/src/lib.rs @@ -0,0 +1,27 @@ +use windows::Win32::{ + Foundation::HINSTANCE, + System::{ + SystemServices::DLL_PROCESS_ATTACH, + Threading::{GetCurrentThread, TerminateThread}, + }, +}; + +#[unsafe(no_mangle)] +#[allow(non_snake_case, unused_variables)] +extern "cdecl" fn Initialize() -> bool { + std::thread::sleep(std::time::Duration::from_secs(2)); + + unsafe { + TerminateThread(GetCurrentThread(), 0).unwrap(); + } + + false +} + +#[allow(non_snake_case)] +#[unsafe(no_mangle)] +unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) { + if call_reason == DLL_PROCESS_ATTACH { + std::thread::spawn(hkrpg::main); + } +}