feat: add AccountPlatNative patch for CN SDK auth
This commit is contained in:
Generated
+88
@@ -17,6 +17,32 @@ version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "6.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"hashbrown",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ext"
|
||||
version = "0.1.0"
|
||||
@@ -25,10 +51,17 @@ dependencies = [
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hkrpg"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"ilhook",
|
||||
"patternscan",
|
||||
"windows",
|
||||
@@ -77,6 +110,15 @@ version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@@ -91,6 +133,25 @@ dependencies = [
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "patternscan"
|
||||
version = "1.2.0"
|
||||
@@ -115,6 +176,15 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
@@ -144,6 +214,18 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
@@ -201,6 +283,12 @@ dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
|
||||
@@ -22,6 +22,7 @@ windows = { version = "0.54.0", features = [
|
||||
] }
|
||||
ilhook = "2.1.1"
|
||||
patternscan = "1.2.0"
|
||||
dashmap = "6.1.0"
|
||||
|
||||
# Local crates
|
||||
hkrpg = { path = "hkrpg/" }
|
||||
|
||||
+2
-1
@@ -6,4 +6,5 @@ version.workspace = true
|
||||
[dependencies]
|
||||
windows.workspace = true
|
||||
ilhook.workspace = true
|
||||
patternscan.workspace = true
|
||||
patternscan.workspace = true
|
||||
dashmap.workspace = true
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAudOyZJDKXjYQdUS+wN7d
|
||||
lKBP2XkhkDO/sx6pttn719o+rJ8y8XOO3rftSoRasvw1nzidDQqEnHl1Aw5+a90D
|
||||
OQvlgBaIda3npqVmi4X2sEzswR7EH5BOJizx7LAxixcoby3jOQathdpl44wQ04XR
|
||||
+SIkukvxcL1jTepfuc0Pp+DD+4MU5O4/38b9v+ryizU+1CdwzukV27rkMvOtA6ok
|
||||
Is6Vkb5ubcAC/W3vCIP5gv+QRdYB6ihzLhs5WI/9Ex2PrLpdpxr7gClvEFxkHcLy
|
||||
LCvSfp9pvt/tnsYsk1tct0HKEr8tlaJ6t1zEGEvFQZRpBsahl/lhpT15vyM8iyiD
|
||||
DwIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
+3
-2
@@ -3,8 +3,8 @@
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
use modules::{
|
||||
HkrpgModuleManager, censorship_patch::CensorshipPatch, crypto::Crypto, hk_check::HkCheck,
|
||||
misc::Misc, network::Network,
|
||||
HkrpgModuleManager, apn::ApnPatch, censorship_patch::CensorshipPatch, crypto::Crypto,
|
||||
hk_check::HkCheck, misc::Misc, network::Network,
|
||||
};
|
||||
use windows::{
|
||||
Win32::System::{Console, LibraryLoader::GetModuleHandleA},
|
||||
@@ -35,6 +35,7 @@ pub fn main() {
|
||||
addr::init_rvas();
|
||||
|
||||
let mut module_manager = HkrpgModuleManager::default();
|
||||
module_manager.add::<ApnPatch>();
|
||||
module_manager.add::<HkCheck>();
|
||||
module_manager.add::<Network>();
|
||||
module_manager.add::<Crypto>();
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
use dashmap::DashMap;
|
||||
use ilhook::x64::Registers;
|
||||
use patternscan::scan_first_match;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
ffi::{CStr, CString},
|
||||
path::Path,
|
||||
sync::{LazyLock, OnceLock},
|
||||
};
|
||||
use windows::{
|
||||
Win32::System::{
|
||||
LibraryLoader::{GetModuleHandleW, LoadLibraryW},
|
||||
ProcessStatus::{GetModuleInformation, MODULEINFO},
|
||||
Threading::GetCurrentProcess,
|
||||
},
|
||||
core::{PCWSTR, w},
|
||||
};
|
||||
|
||||
use crate::modules::{HkrpgModule, HkrpgModuleContext};
|
||||
|
||||
pub struct ApnPatch;
|
||||
|
||||
impl HkrpgModule for HkrpgModuleContext<ApnPatch> {
|
||||
unsafe fn init(&mut self) -> Result<(), ilhook::HookError> {
|
||||
if !load_apn_dll() {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let base;
|
||||
loop {
|
||||
if let Ok(module) = unsafe { GetModuleHandleW(w!("AccountPlatNative.dll")) } {
|
||||
base = module.0 as usize;
|
||||
println!("AccountPlatNative.dll: 0x{base:X}");
|
||||
break;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
}
|
||||
|
||||
let Some(string_alloc_rva) = scan_apn("E8 ? ? ? ? 41 89 BF") else {
|
||||
println!("[AccountPlatNative] failed to scan string_alloc rva. patch disabled");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
self.interceptor
|
||||
.attach(base + string_alloc_rva, on_string_alloc)
|
||||
.expect("Failed to hook AccountPlatNative string alloc");
|
||||
|
||||
println!("[AccountPlatNative] patch enabled");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
extern "win64" fn on_string_alloc(reg: *mut Registers, _: usize) {
|
||||
const SDK_PUBLIC_KEY: &str = include_str!("../../sdk_public_key.pem");
|
||||
static STRING_CACHE_MAP: LazyLock<DashMap<Cow<'static, str>, CString>> =
|
||||
LazyLock::new(DashMap::new);
|
||||
|
||||
unsafe {
|
||||
let content = CStr::from_ptr((*reg).rdx as *const i8).to_string_lossy();
|
||||
let size = (*reg).r8;
|
||||
|
||||
if let Some(cstring) = STRING_CACHE_MAP.get(&content) {
|
||||
(*reg).rdx = cstring.as_ptr() as u64;
|
||||
(*reg).r8 = cstring.count_bytes() as u64;
|
||||
return;
|
||||
}
|
||||
|
||||
// URL string alloc
|
||||
if content.starts_with("https://") && content.contains(".mihoyo.com") {
|
||||
let mut new_url = String::from("http://127.0.0.1:21000");
|
||||
content.split('/').skip(3).for_each(|s| {
|
||||
new_url.push('/');
|
||||
new_url.push_str(s);
|
||||
});
|
||||
|
||||
let cstring = STRING_CACHE_MAP
|
||||
.entry(content.clone())
|
||||
.or_insert_with(|| CString::new(&*new_url).expect("Failed to create CString"));
|
||||
|
||||
(*reg).rdx = cstring.as_ptr() as u64;
|
||||
(*reg).r8 = new_url.len() as u64;
|
||||
|
||||
println!("[AccountPlatNative] url {content} replaced to {new_url}");
|
||||
}
|
||||
// RSA public key string alloc
|
||||
else if size == 268 && content.starts_with("-----BEGIN PUBLIC KEY-----") {
|
||||
let cstring = STRING_CACHE_MAP
|
||||
.entry(content.clone())
|
||||
.or_insert_with(|| CString::new(SDK_PUBLIC_KEY).expect("Failed to create CString"));
|
||||
|
||||
(*reg).rdx = cstring.as_ptr() as u64;
|
||||
(*reg).r8 = SDK_PUBLIC_KEY.len() as u64;
|
||||
println!("[AccountPlatNative] sdk public key replaced! ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_apn_dll() -> bool {
|
||||
let dll_path = "./StarRail_Data/Plugins/x86_64/AccountPlatNative.dll";
|
||||
|
||||
if !Path::new(dll_path).exists() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let wide_dll_path: Vec<u16> = dll_path.encode_utf16().chain(std::iter::once(0)).collect();
|
||||
let ptr = wide_dll_path.as_ptr();
|
||||
|
||||
if let Err(err) = unsafe { LoadLibraryW(PCWSTR::from_raw(ptr)) } {
|
||||
println!("[AccountPlatNative] Failed to inject {dll_path}. Error: {err:#?}",);
|
||||
};
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn scan_apn(pat: &str) -> Option<usize> {
|
||||
let mut slice = apn_slice();
|
||||
scan_first_match(&mut slice, pat).unwrap().map(|address| {
|
||||
let slice = apn_slice();
|
||||
match slice.get(address) {
|
||||
// jmp sub_xxxxxxx
|
||||
Some(&0xE8) => {
|
||||
let offset =
|
||||
i32::from_le_bytes(slice[address + 1..address + 5].try_into().unwrap());
|
||||
address + 5 + offset as usize
|
||||
}
|
||||
// mov REGISTER, [rip + offset] (0x48 0x8B 0x0D XXXXXXXX)
|
||||
Some(&0x48) if slice.get(address + 1) == Some(&0x8B) => {
|
||||
let offset =
|
||||
i32::from_le_bytes(slice[address + 3..address + 7].try_into().unwrap());
|
||||
address + 7 + offset as usize
|
||||
}
|
||||
_ => address,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn apn_slice() -> &'static [u8] {
|
||||
static SLICE: OnceLock<&[u8]> = OnceLock::new();
|
||||
unsafe {
|
||||
SLICE.get_or_init(|| {
|
||||
let module = GetModuleHandleW(w!("AccountPlatNative.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::<MODULEINFO>() as u32,
|
||||
)
|
||||
.unwrap();
|
||||
std::slice::from_raw_parts(
|
||||
module.0 as *const u8,
|
||||
module_info.SizeOfImage.try_into().unwrap(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@ use std::marker::PhantomData;
|
||||
|
||||
use crate::{addr, interceptor::Interceptor};
|
||||
|
||||
pub mod apn;
|
||||
pub mod censorship_patch;
|
||||
pub mod crypto;
|
||||
pub mod hk_check;
|
||||
pub mod network;
|
||||
pub mod misc;
|
||||
pub mod network;
|
||||
|
||||
pub struct HkrpgModuleContext<T> {
|
||||
_base: usize,
|
||||
|
||||
Reference in New Issue
Block a user