Hi!
This commit is contained in:
parent
20d7158784
commit
23433635ae
15 changed files with 994 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target/
|
424
Cargo.lock
generated
Normal file
424
Cargo.lock
generated
Normal file
|
@ -0,0 +1,424 @@
|
|||
# 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.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
|
||||
|
||||
[[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 = "indexmap"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "launcher"
|
||||
version = "0.0.1"
|
||||
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.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"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"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yanagi"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"ilhook",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
"windows",
|
||||
]
|
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
|||
[workspace]
|
||||
members = ["launcher", "yanagi"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.1"
|
||||
|
||||
[workspace.dependencies]
|
||||
windows = "0.58.0"
|
||||
ilhook = "2.1.1"
|
||||
thiserror = "1.0.64"
|
||||
num_enum = "0.7.3"
|
14
launcher/Cargo.toml
Normal file
14
launcher/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "launcher"
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
windows = { workspace = true, features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_Memory",
|
||||
"Win32_System_Threading",
|
||||
"Win32_Security",
|
||||
] }
|
102
launcher/src/main.rs
Normal file
102
launcher/src/main.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
use std::ffi::CString;
|
||||
|
||||
use std::ptr::null_mut;
|
||||
use windows::core::{s, PCSTR, PSTR};
|
||||
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::{
|
||||
VirtualAllocEx, VirtualFreeEx, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE,
|
||||
};
|
||||
use windows::Win32::System::Threading::{
|
||||
CreateProcessA, CreateRemoteThread, ResumeThread, WaitForSingleObject, CREATE_SUSPENDED,
|
||||
PROCESS_INFORMATION, STARTUPINFOA,
|
||||
};
|
||||
|
||||
const GAME_EXECUTABLE: PCSTR = s!("ZenlessZoneZeroBeta.exe");
|
||||
const INJECT_DLL: &str = "ext.dll";
|
||||
|
||||
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!("VirtualAllocEx failed. Last error: {:?}", 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(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(INJECT_DLL);
|
||||
if !dll_path.is_file() {
|
||||
println!("{INJECT_DLL} not found");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut proc_info = PROCESS_INFORMATION::default();
|
||||
let mut startup_info = STARTUPINFOA::default();
|
||||
|
||||
unsafe {
|
||||
CreateProcessA(
|
||||
GAME_EXECUTABLE,
|
||||
PSTR(null_mut()),
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
CREATE_SUSPENDED,
|
||||
None,
|
||||
None,
|
||||
&mut 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();
|
||||
}
|
||||
}
|
2
rust-toolchain.toml
Normal file
2
rust-toolchain.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[toolchain]
|
||||
channel = "nightly"
|
21
yanagi/Cargo.toml
Normal file
21
yanagi/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "yanagi"
|
||||
edition = "2021"
|
||||
version.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "yanagi"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
ilhook.workspace = true
|
||||
thiserror.workspace = true
|
||||
num_enum.workspace = true
|
||||
windows = { workspace = true, features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_Console",
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_Memory",
|
||||
] }
|
1
yanagi/sdk_public_key.xml
Normal file
1
yanagi/sdk_public_key.xml
Normal file
|
@ -0,0 +1 @@
|
|||
<RSAKeyValue><Exponent>AQAB</Exponent><Modulus>hEegnKISgDas5VTuRBUlixB+bvmPvXKa3kVO22UEZjPGMUFLmIl3DhH+dsZo7qJn/GfJCUkP1FA0MJ5Bj8PX8IatLJKIJ9dMCNdnAlkXTlMg86QQAhHZN83vP4swj5ILcrGNKl3YAZ49fvzo7nheuTt0/40f0HkHdNa1dUHECBs=</Modulus></RSAKeyValue>
|
8
yanagi/server_public_key.xml
Normal file
8
yanagi/server_public_key.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<RSAKeyValue>
|
||||
<Modulus>
|
||||
d8zyiJhwWK1Gocou1iynAKbH9f27uAtqFWec+Rbr6G9JFzyAsqH2G7iKqPV60lItLgJ/jvcVyzPeE9eQ1h6Fjw==
|
||||
</Modulus>
|
||||
<Exponent>
|
||||
AQAB
|
||||
</Exponent>
|
||||
</RSAKeyValue>
|
42
yanagi/src/interceptor.rs
Normal file
42
yanagi/src/interceptor.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use ilhook::x64::{
|
||||
CallbackOption, HookFlags, HookPoint, HookType, Hooker, JmpBackRoutine, RetnRoutine,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interceptor {
|
||||
hooks: Vec<HookPoint>,
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, ilhook::HookError>;
|
||||
impl Interceptor {
|
||||
pub unsafe 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 = hooker.hook()?;
|
||||
self.hooks.push(hook_point);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub unsafe 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 = hooker.hook()?;
|
||||
self.hooks.push(hook_point);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
56
yanagi/src/lib.rs
Normal file
56
yanagi/src/lib.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
#![feature(str_from_utf16_endian)]
|
||||
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
use interceptor::Interceptor;
|
||||
use modules::{
|
||||
crypto::{
|
||||
initialize_rsa_public_key, monitor_network_state, replace_sdk_public_key_string_literal,
|
||||
},
|
||||
network::Network,
|
||||
NapModuleManager,
|
||||
};
|
||||
use windows::{
|
||||
core::s,
|
||||
Win32::{
|
||||
Foundation::HINSTANCE,
|
||||
System::{Console, LibraryLoader::GetModuleHandleA, SystemServices::DLL_PROCESS_ATTACH},
|
||||
},
|
||||
};
|
||||
|
||||
mod interceptor;
|
||||
mod modules;
|
||||
mod util;
|
||||
|
||||
unsafe fn thread_fn() {
|
||||
let _ = Console::AllocConsole();
|
||||
|
||||
while GetModuleHandleA(s!("GameAssembly.dll")).is_err() {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_secs(5));
|
||||
util::disable_memory_protection();
|
||||
|
||||
let mut module_manager = NapModuleManager::default();
|
||||
module_manager.add::<Network>();
|
||||
module_manager.init().expect("failed to initialize modules");
|
||||
|
||||
initialize_rsa_public_key();
|
||||
replace_sdk_public_key_string_literal();
|
||||
|
||||
let mut interceptor = Interceptor::default();
|
||||
monitor_network_state(&mut interceptor);
|
||||
|
||||
thread::sleep(Duration::from_secs(u64::MAX));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) -> bool {
|
||||
if call_reason == DLL_PROCESS_ATTACH {
|
||||
thread::spawn(|| thread_fn());
|
||||
}
|
||||
|
||||
true
|
||||
}
|
101
yanagi/src/modules/crypto.rs
Normal file
101
yanagi/src/modules/crypto.rs
Normal file
|
@ -0,0 +1,101 @@
|
|||
use std::ffi::CString;
|
||||
|
||||
use ilhook::x64::Registers;
|
||||
|
||||
use crate::{
|
||||
interceptor::Interceptor,
|
||||
util::{import, read_csharp_string, GAME_ASSEMBLY_BASE},
|
||||
};
|
||||
|
||||
import!(rsa_create() -> usize = 0x163AEC10);
|
||||
import!(rsa_from_xml_string(instance: usize, xml_string: usize) -> usize = 0x163AEE50);
|
||||
import!(il2cpp_string_new(cstr: *const u8) -> usize = 0x72540);
|
||||
|
||||
pub unsafe fn initialize_rsa_public_key() {
|
||||
const SERVER_PUBLIC_KEY: &str = include_str!("../../server_public_key.xml");
|
||||
let rsa_public_key_backdoor_field =
|
||||
((*(GAME_ASSEMBLY_BASE.wrapping_add(0x44949B0) as *const usize)) + 204776) as *mut usize;
|
||||
|
||||
let rsa = rsa_create();
|
||||
rsa_from_xml_string(
|
||||
rsa,
|
||||
il2cpp_string_new(
|
||||
CString::new(SERVER_PUBLIC_KEY)
|
||||
.unwrap()
|
||||
.to_bytes_with_nul()
|
||||
.as_ptr(),
|
||||
),
|
||||
);
|
||||
|
||||
*rsa_public_key_backdoor_field = rsa;
|
||||
}
|
||||
|
||||
pub unsafe fn replace_sdk_public_key_string_literal() {
|
||||
const SDK_PUBLIC_KEY: &str = include_str!("../../sdk_public_key.xml");
|
||||
|
||||
*(GAME_ASSEMBLY_BASE.wrapping_add(0x475FB40) as *mut usize) = il2cpp_string_new(
|
||||
CString::new(SDK_PUBLIC_KEY)
|
||||
.unwrap()
|
||||
.to_bytes_with_nul()
|
||||
.as_ptr(),
|
||||
) as usize;
|
||||
}
|
||||
|
||||
pub unsafe fn monitor_network_state(interceptor: &mut Interceptor) {
|
||||
interceptor
|
||||
.attach(
|
||||
GAME_ASSEMBLY_BASE.wrapping_add(0xA27D650),
|
||||
on_network_state_change,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
interceptor
|
||||
.attach(
|
||||
GAME_ASSEMBLY_BASE.wrapping_add(0x97DA670),
|
||||
download_data_slave,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
unsafe extern "win64" fn download_data_slave(reg: *mut Registers, _: usize) {
|
||||
let data = read_csharp_string((*reg).rcx as usize);
|
||||
println!("{data}");
|
||||
}
|
||||
|
||||
unsafe extern "win64" fn on_network_state_change(reg: *mut Registers, _: usize) {
|
||||
let net_state = NetworkState::from((*reg).rcx);
|
||||
println!("network state change: {net_state:?}");
|
||||
|
||||
if net_state == NetworkState::PlayerLoginCsReq {
|
||||
// public key rsa gets reset to null after successful PlayerGetTokenScRsp
|
||||
initialize_rsa_public_key();
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u64)]
|
||||
#[derive(num_enum::FromPrimitive, Debug, Default, PartialEq)]
|
||||
pub enum NetworkState {
|
||||
CloudCmdLine = 21,
|
||||
CloudDispatch = 20,
|
||||
StartBasicsReq = 17,
|
||||
LoadShaderEnd = 9,
|
||||
PlayerLoginCsReq = 15,
|
||||
EndBasicsReq = 18,
|
||||
LoadResourcesEnd = 10,
|
||||
GlobalDispatch = 1,
|
||||
ConnectGameServer = 12,
|
||||
ChooseServer = 2,
|
||||
DoFileVerifyEnd = 7,
|
||||
PlayerLoginScRsp = 16,
|
||||
DispatchResult = 4,
|
||||
PlayerGetTokenScRsp = 14,
|
||||
DownloadResourcesEnd = 6,
|
||||
AccountLogin = 3,
|
||||
LoadAssetEnd = 8,
|
||||
StartEnterGameWorld = 11,
|
||||
#[default]
|
||||
None = 0,
|
||||
EnterWorldScRsp = 19,
|
||||
PlayerGetTokenCsReq = 13,
|
||||
StartDownLoad = 5,
|
||||
}
|
56
yanagi/src/modules/mod.rs
Normal file
56
yanagi/src/modules/mod.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{interceptor::Interceptor, util};
|
||||
|
||||
pub mod crypto;
|
||||
pub mod network;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ModuleInitError {
|
||||
#[error("{0}")]
|
||||
HookFail(#[from] ilhook::HookError),
|
||||
}
|
||||
|
||||
pub struct NapModuleContext<T> {
|
||||
base: usize,
|
||||
interceptor: Interceptor,
|
||||
_module_type: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> NapModuleContext<T> {
|
||||
fn new(base: usize) -> Self {
|
||||
Self {
|
||||
base,
|
||||
interceptor: Interceptor::default(),
|
||||
_module_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NapModule {
|
||||
unsafe fn init(&mut self) -> Result<(), ModuleInitError>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct NapModuleManager {
|
||||
modules: Vec<Box<dyn NapModule>>,
|
||||
}
|
||||
|
||||
impl NapModuleManager {
|
||||
pub fn add<T: 'static>(&mut self)
|
||||
where
|
||||
NapModuleContext<T>: NapModule,
|
||||
{
|
||||
self.modules.push(Box::new(NapModuleContext::<T>::new(
|
||||
*util::GAME_ASSEMBLY_BASE,
|
||||
)));
|
||||
}
|
||||
|
||||
pub unsafe fn init(&mut self) -> Result<(), ModuleInitError> {
|
||||
for module in self.modules.iter_mut() {
|
||||
module.init()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
79
yanagi/src/modules/network.rs
Normal file
79
yanagi/src/modules/network.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
use std::ffi::CString;
|
||||
|
||||
use ilhook::x64::Registers;
|
||||
|
||||
use crate::util::{self, import, read_csharp_string};
|
||||
|
||||
use super::{ModuleInitError, NapModule, NapModuleContext};
|
||||
|
||||
const MAKE_INITIAL_URL: usize = 0x605A190;
|
||||
|
||||
pub struct Network;
|
||||
|
||||
impl NapModule for NapModuleContext<Network> {
|
||||
unsafe fn init(&mut self) -> Result<(), ModuleInitError> {
|
||||
self.interceptor.attach(
|
||||
self.base.wrapping_add(MAKE_INITIAL_URL),
|
||||
Network::on_make_initial_url,
|
||||
)?;
|
||||
|
||||
self.interceptor
|
||||
.attach(self.base.wrapping_add(0x17627E10), on_set_url)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "win64" fn on_set_url(reg: *mut Registers, _: usize) {
|
||||
let s = read_csharp_string((*reg).rcx as usize);
|
||||
if s.contains("StandaloneWindows64/cn/") {
|
||||
let s = s.replace("StandaloneWindows64/cn/", "StandaloneWindows64/oversea/");
|
||||
println!("replaced: {s}");
|
||||
(*reg).rcx =
|
||||
il2cpp_string_new(CString::new(s).unwrap().to_bytes_with_nul().as_ptr()) as u64;
|
||||
}
|
||||
}
|
||||
|
||||
import!(il2cpp_string_new(cstr: *const u8) -> usize = 0x72540);
|
||||
|
||||
impl Network {
|
||||
const SDK_URL: &str = "http://127.0.0.1:10001";
|
||||
const DISPATCH_URL: &str = "http://127.0.0.1:10002";
|
||||
const REDIRECT_SDK: bool = true;
|
||||
const REDIRECT_DISPATCH: bool = true;
|
||||
|
||||
unsafe extern "win64" fn on_make_initial_url(reg: *mut Registers, _: usize) {
|
||||
let url = util::read_csharp_string((*reg).rcx as usize);
|
||||
|
||||
let mut new_url = match url.as_str() {
|
||||
s if (s.contains("mihoyo.com") || s.contains("hoyoverse.com"))
|
||||
&& Self::REDIRECT_SDK =>
|
||||
{
|
||||
Self::SDK_URL.to_string()
|
||||
}
|
||||
s if (s.contains("globaldp-prod-os01.zenlesszonezero.com")
|
||||
|| s.contains("globaldp-prod-cn01.juequling.com"))
|
||||
&& Self::REDIRECT_DISPATCH =>
|
||||
{
|
||||
Self::DISPATCH_URL.to_string()
|
||||
}
|
||||
s => {
|
||||
println!("Leaving request as-is: {s}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
url.split('/').skip(3).for_each(|s| {
|
||||
new_url.push_str("/");
|
||||
new_url.push_str(s);
|
||||
});
|
||||
|
||||
println!("UnityWebRequest: \"{url}\", replacing with \"{new_url}\"");
|
||||
(*reg).rcx = il2cpp_string_new(
|
||||
CString::new(new_url.as_str())
|
||||
.unwrap()
|
||||
.to_bytes_with_nul()
|
||||
.as_ptr(),
|
||||
) as u64;
|
||||
}
|
||||
}
|
75
yanagi/src/util.rs
Normal file
75
yanagi/src/util.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use std::{ffi::c_void, sync::LazyLock};
|
||||
|
||||
use windows::{
|
||||
core::s,
|
||||
Win32::System::{
|
||||
LibraryLoader::{GetModuleHandleA, GetProcAddress},
|
||||
Memory,
|
||||
},
|
||||
};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! c {
|
||||
($cstr:expr) => {
|
||||
unsafe {
|
||||
std::ffi::CStr::from_ptr(concat!($cstr, "\0").as_ptr() as *const std::os::raw::c_char)
|
||||
.to_bytes_with_nul()
|
||||
.as_ptr()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! import {
|
||||
($name:ident($($arg_name:ident: $arg_type:ty),*) -> $ret_type:ty = $rva:expr) => {
|
||||
pub unsafe fn $name($($arg_name: $arg_type,)*) -> $ret_type {
|
||||
static PROC: ::std::sync::LazyLock<usize> = ::std::sync::LazyLock::new(|| *crate::util::GAME_ASSEMBLY_BASE + $rva);
|
||||
|
||||
type FuncType = unsafe extern "fastcall" fn($($arg_type,)*) -> $ret_type;
|
||||
::std::mem::transmute::<usize, FuncType>(*PROC)($($arg_name,)*)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use import;
|
||||
|
||||
pub static GAME_ASSEMBLY_BASE: LazyLock<usize> =
|
||||
LazyLock::new(|| unsafe { GetModuleHandleA(s!("GameAssembly.dll")).unwrap().0 as usize });
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn read_csharp_string(s: usize) -> String {
|
||||
let str_length = *(s.wrapping_add(16) as *const u32);
|
||||
let str_ptr = s.wrapping_add(20) as *const u8;
|
||||
|
||||
String::from_utf16le_lossy(std::slice::from_raw_parts(
|
||||
str_ptr,
|
||||
(str_length * 2) as usize,
|
||||
))
|
||||
}
|
||||
|
||||
pub unsafe fn disable_memory_protection() {
|
||||
let ntdll = GetModuleHandleA(s!("ntdll.dll")).unwrap();
|
||||
let proc_addr = GetProcAddress(ntdll, s!("NtProtectVirtualMemory")).unwrap();
|
||||
|
||||
let nt_func = if GetProcAddress(ntdll, s!("wine_get_version")).is_some() {
|
||||
GetProcAddress(ntdll, s!("NtPulseEvent")).unwrap()
|
||||
} else {
|
||||
GetProcAddress(ntdll, s!("NtQuerySection")).unwrap()
|
||||
};
|
||||
|
||||
let mut prot = Memory::PAGE_EXECUTE_READWRITE;
|
||||
Memory::VirtualProtect(proc_addr as *const usize as *mut c_void, 1, prot, &mut prot).unwrap();
|
||||
|
||||
let routine = nt_func as *mut u32;
|
||||
let routine_val = *(routine as *const usize);
|
||||
|
||||
let lower_bits_mask = !(0xFFu64 << 32);
|
||||
let lower_bits = routine_val & lower_bits_mask as usize;
|
||||
|
||||
let offset_val = *((routine as usize + 4) as *const u32);
|
||||
let upper_bits = ((offset_val as usize).wrapping_sub(1) as usize) << 32;
|
||||
|
||||
let result = lower_bits | upper_bits;
|
||||
|
||||
*(proc_addr as *mut usize) = result;
|
||||
Memory::VirtualProtect(proc_addr as *const usize as *mut c_void, 1, prot, &mut prot).unwrap();
|
||||
}
|
Loading…
Reference in a new issue