Compare commits
8 Commits
3.1.5x
...
7ab400507e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ab400507e | ||
|
|
d66398b9b8 | ||
|
|
ee7fa339fb | ||
|
|
cc2f1865fc | ||
|
|
0c87252394 | ||
|
|
61928b9269 | ||
|
|
3f6933c096 | ||
|
|
bc651397e6 |
@@ -1,4 +1,7 @@
|
||||
redirect HTTP requests & remove censorship!
|
||||
features:
|
||||
- redirect HTTP requests
|
||||
- remove censorship
|
||||
- replace AccountRSAKey into custom public key (by default, compatible with [hoyo-sdk by xeondev](https://git.xeondev.com/reversedrooms/hoyo-sdk))
|
||||
|
||||
currently, this has only been tested on CNBETAWin3.1.53 and may require an update for future versions.
|
||||
|
||||
|
||||
1
hkrpg/sdk_public_key.xml
Normal file
1
hkrpg/sdk_public_key.xml
Normal file
@@ -0,0 +1 @@
|
||||
<RSAKeyValue><Exponent>AQAB</Exponent><Modulus>hEegnKISgDas5VTuRBUlixB+bvmPvXKa3kVO22UEZjPGMUFLmIl3DhH+dsZo7qJn/GfJCUkP1FA0MJ5Bj8PX8IatLJKIJ9dMCNdnAlkXTlMg86QQAhHZN83vP4swj5ILcrGNKl3YAZ49fvzo7nheuTt0/40f0HkHdNa1dUHECBs=</Modulus></RSAKeyValue>
|
||||
@@ -2,25 +2,24 @@ use std::sync::{LazyLock, OnceLock};
|
||||
|
||||
use windows::{Win32::System::LibraryLoader::GetModuleHandleA, core::s};
|
||||
|
||||
use crate::util::{scan_il2cpp_section, scan_unity_player_section};
|
||||
use crate::util::scan_il2cpp_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";
|
||||
const IL2CPP_STRING_NEW_LEN: &str =
|
||||
"E8 ? ? ? ? EB ? 31 C0 48 89 06 48 8B 47 ? 48 89 46 ? F2 0F 10 47";
|
||||
const MAKE_INITIAL_URL: &str =
|
||||
"E8 ? ? ? ? 48 89 D9 48 89 C2 E8 ? ? ? ? 48 89 D9 4C 89 FA E8 ? ? ? ? 49 89 5D"; // TODO
|
||||
const SET_DITHER: &str = "E8 ? ? ? ? 84 C0 75 ? C7 43";
|
||||
const SDK_PUBLIC_KEY_LITERAL: &str =
|
||||
"48 8B 0D ? ? ? ? 4C 89 E2 E8 ? ? ? ? 48 89 C6 48 8B 0D ? ? ? ? E8 ? ? ? ? 48 89 C7 48 8B 0D";
|
||||
// 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 il2cpp_string_new_len: 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 set_dither: usize,
|
||||
pub sdk_public_key: usize,
|
||||
pub hk_check1: usize,
|
||||
pub hk_check2: usize,
|
||||
}
|
||||
@@ -34,22 +33,24 @@ pub fn rva_config() -> &'static mut RVAConfig {
|
||||
pub static GAME_ASSEMBLY_BASE: LazyLock<usize> =
|
||||
LazyLock::new(|| unsafe { GetModuleHandleA(s!("GameAssembly.dll")).unwrap().0 as usize });
|
||||
|
||||
pub static UNITY_PLAYER_BASE: LazyLock<usize> =
|
||||
LazyLock::new(|| unsafe { GetModuleHandleA(s!("UnityPlayer.dll")).unwrap().0 as usize });
|
||||
// pub static UNITY_PLAYER_BASE: LazyLock<usize> =
|
||||
// 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) => {
|
||||
($base:ident, $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;
|
||||
$config.$field = addr;
|
||||
println!(
|
||||
"[hkrpg::addr::set_rva] Found relative address for {} -> 0x{:X}",
|
||||
"[hkrpg::addr::set_rva] Found relative address for {} [{}] -> 0x{:X}",
|
||||
stringify!($field),
|
||||
$config.$field
|
||||
stringify!($base),
|
||||
$config.$field - *$base
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"[hkrpg::addr::set_rva] Failed to find pattern for {} using {}",
|
||||
"[hkrpg::addr::set_rva] Failed to find pattern for {} [{}] using {}",
|
||||
stringify!($field),
|
||||
stringify!($base),
|
||||
stringify!($scan_fn)
|
||||
);
|
||||
|
||||
@@ -61,17 +62,19 @@ macro_rules! set_rva {
|
||||
pub unsafe fn init_rvas() {
|
||||
let config = rva_config();
|
||||
|
||||
// ptr_to_string_ansi
|
||||
// il2cpp_string_new_len
|
||||
set_rva!(
|
||||
GAME_ASSEMBLY_BASE,
|
||||
config,
|
||||
ptr_to_string_ansi,
|
||||
il2cpp_string_new_len,
|
||||
scan_il2cpp_section,
|
||||
PTR_TO_STRING_ANSI,
|
||||
IL2CPP_STRING_NEW_LEN,
|
||||
0x0
|
||||
);
|
||||
|
||||
// make_initial_url
|
||||
set_rva!(
|
||||
GAME_ASSEMBLY_BASE,
|
||||
config,
|
||||
make_initial_url,
|
||||
scan_il2cpp_section,
|
||||
@@ -79,39 +82,40 @@ pub unsafe fn init_rvas() {
|
||||
0x0
|
||||
);
|
||||
|
||||
// set_elevation_dither
|
||||
// set_dither
|
||||
set_rva!(
|
||||
GAME_ASSEMBLY_BASE,
|
||||
config,
|
||||
set_elevation_dither,
|
||||
set_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,
|
||||
SET_DITHER,
|
||||
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);
|
||||
// sdk_public_key_literal
|
||||
set_rva!(
|
||||
GAME_ASSEMBLY_BASE,
|
||||
config,
|
||||
sdk_public_key,
|
||||
scan_il2cpp_section,
|
||||
SDK_PUBLIC_KEY_LITERAL,
|
||||
0x0
|
||||
)
|
||||
|
||||
// set_rva!(
|
||||
// UNITY_PLAYER_BASE,
|
||||
// config,
|
||||
// hk_check1,
|
||||
// scan_unity_player_section,
|
||||
// HK_CHECK1,
|
||||
// 0x0
|
||||
// );
|
||||
// set_rva!(
|
||||
// UNITY_PLAYER_BASE,
|
||||
// config,
|
||||
// hk_check2,
|
||||
// scan_unity_player_section,
|
||||
// HK_CHECK2,
|
||||
// 0x0
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{ffi::CString, fmt::Display};
|
||||
|
||||
use crate::addr::{GAME_ASSEMBLY_BASE, rva_config};
|
||||
use crate::addr::rva_config;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct Il2cppString(usize);
|
||||
@@ -15,7 +15,7 @@ impl Il2cppString {
|
||||
pub fn new(string: &str) -> Self {
|
||||
let func = unsafe {
|
||||
std::mem::transmute::<usize, fn(*const u8, usize) -> usize>(
|
||||
*GAME_ASSEMBLY_BASE + rva_config().ptr_to_string_ansi,
|
||||
rva_config().il2cpp_string_new_len,
|
||||
)
|
||||
};
|
||||
let len = string.len();
|
||||
|
||||
@@ -2,13 +2,16 @@ 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 const fn new() -> Self {
|
||||
Interceptor { hooks: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn attach(&mut self, addr: usize, routine: JmpBackRoutine) -> Result<()> {
|
||||
let hooker = Hooker::new(
|
||||
addr,
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
use std::{thread, time::Duration};
|
||||
|
||||
use modules::{
|
||||
HkrpgModuleManager, censorship_patch::CensorshipPatch, hk_check::HkCheck, network::Network,
|
||||
HkrpgModuleManager, censorship_patch::CensorshipPatch, crypto::Crypto, hk_check::HkCheck,
|
||||
misc::Misc, network::Network,
|
||||
};
|
||||
use windows::{
|
||||
Win32::System::{Console, LibraryLoader::GetModuleHandleA},
|
||||
@@ -26,11 +27,17 @@ pub fn main() {
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
}
|
||||
|
||||
let mut mm1 = HkrpgModuleManager::default();
|
||||
mm1.add::<Misc>();
|
||||
mm1.init()
|
||||
.expect("[hkrpg::main] failed to initialize module (Misc)");
|
||||
|
||||
addr::init_rvas();
|
||||
|
||||
let mut module_manager = HkrpgModuleManager::default();
|
||||
module_manager.add::<HkCheck>();
|
||||
module_manager.add::<Network>();
|
||||
module_manager.add::<Crypto>();
|
||||
module_manager.add::<CensorshipPatch>();
|
||||
module_manager
|
||||
.init()
|
||||
|
||||
@@ -11,7 +11,7 @@ macro_rules! replace {
|
||||
$(
|
||||
if $config.$field != 0 {
|
||||
$self.interceptor.replace(
|
||||
$self.base.wrapping_add($config.$field),
|
||||
$config.$field,
|
||||
CensorshipPatch::on_set_dither,
|
||||
)?;
|
||||
} else {
|
||||
@@ -24,14 +24,7 @@ macro_rules! replace {
|
||||
impl HkrpgModule for HkrpgModuleContext<CensorshipPatch> {
|
||||
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
|
||||
);
|
||||
replace!(self, config, set_dither);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
23
hkrpg/src/modules/crypto.rs
Normal file
23
hkrpg/src/modules/crypto.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use crate::{addr::rva_config, il2cpp_string::Il2cppString};
|
||||
|
||||
use super::{HkrpgModule, HkrpgModuleContext};
|
||||
|
||||
pub struct Crypto;
|
||||
|
||||
const ACCOUNT_RSA_KEY_REPLACEMENT: &str = include_str!("../../sdk_public_key.xml");
|
||||
|
||||
impl HkrpgModule for HkrpgModuleContext<Crypto> {
|
||||
unsafe fn init(&mut self) -> Result<(), ilhook::HookError> {
|
||||
let config = rva_config();
|
||||
if config.sdk_public_key != 0 {
|
||||
unsafe {
|
||||
*(config.sdk_public_key as *mut Il2cppString) =
|
||||
Il2cppString::new(ACCOUNT_RSA_KEY_REPLACEMENT)
|
||||
}
|
||||
println!("[crypto::init] AccountRSAKey replaced")
|
||||
} else {
|
||||
println!("[crypto::init] pattern is outdated! disabling AccountRSAKey replacement")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,11 @@ impl HkrpgModule for HkrpgModuleContext<HkCheck> {
|
||||
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,
|
||||
)?;
|
||||
self.interceptor
|
||||
.replace(config.hk_check1, HkCheck::replacement)?;
|
||||
self.interceptor
|
||||
.replace(config.hk_check2, HkCheck::replacement)?;
|
||||
println!("[hk_check::init] hk_check bypassed")
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
39
hkrpg/src/modules/misc.rs
Normal file
39
hkrpg/src/modules/misc.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use crate::modules::{HkrpgModule, HkrpgModuleContext};
|
||||
use ilhook::x64::Registers;
|
||||
use std::ffi::CStr;
|
||||
use windows::{
|
||||
Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress},
|
||||
core::s,
|
||||
};
|
||||
|
||||
pub struct Misc;
|
||||
|
||||
impl HkrpgModule for HkrpgModuleContext<Misc> {
|
||||
unsafe fn init(&mut self) -> Result<(), ilhook::HookError> {
|
||||
unsafe {
|
||||
let ws32 = GetModuleHandleA(s!("Ws2_32.dll")).unwrap();
|
||||
let get_addr_info = GetProcAddress(ws32, s!("getaddrinfo")).unwrap();
|
||||
self.interceptor
|
||||
.attach(get_addr_info as usize, Misc::on_get_addr_info)?;
|
||||
|
||||
println!("[misc::init] initialized")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Misc {
|
||||
pub unsafe extern "win64" fn on_get_addr_info(reg: *mut Registers, _: usize) {
|
||||
unsafe {
|
||||
let host = CStr::from_ptr((*reg).rcx as *const i8).to_string_lossy();
|
||||
|
||||
if host.contains("globaldp-")
|
||||
&& (host.contains("bhsr.com") || host.contains("starrails.com"))
|
||||
{
|
||||
println!("[*] [on_get_addr_info] {host} -> 0.0.0.0");
|
||||
std::ptr::copy_nonoverlapping(c"0.0.0.0".as_ptr(), (*reg).rcx as *mut i8, 9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,13 @@ use std::marker::PhantomData;
|
||||
use crate::{addr, interceptor::Interceptor};
|
||||
|
||||
pub mod censorship_patch;
|
||||
pub mod crypto;
|
||||
pub mod hk_check;
|
||||
pub mod network;
|
||||
pub mod misc;
|
||||
|
||||
pub struct HkrpgModuleContext<T> {
|
||||
base: usize,
|
||||
_base: usize,
|
||||
interceptor: Interceptor,
|
||||
_module_type: PhantomData<T>,
|
||||
}
|
||||
@@ -15,8 +17,8 @@ pub struct HkrpgModuleContext<T> {
|
||||
impl<T> HkrpgModuleContext<T> {
|
||||
fn new(base: usize) -> Self {
|
||||
Self {
|
||||
base,
|
||||
interceptor: Interceptor::default(),
|
||||
_base: base,
|
||||
interceptor: Interceptor::new(),
|
||||
_module_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,10 @@ pub struct Network;
|
||||
impl HkrpgModule for HkrpgModuleContext<Network> {
|
||||
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,
|
||||
)?;
|
||||
if config.make_initial_url != 0 && config.il2cpp_string_new_len != 0 {
|
||||
self.interceptor
|
||||
.attach(config.make_initial_url, Network::on_make_initial_url)?;
|
||||
println!("[network::init] network patch enabled")
|
||||
} else {
|
||||
println!("[network::init] pattern is outdated! disabling http redirection")
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use windows::{
|
||||
core::s,
|
||||
};
|
||||
|
||||
use crate::addr::{GAME_ASSEMBLY_BASE, UNITY_PLAYER_BASE};
|
||||
use crate::addr::GAME_ASSEMBLY_BASE;
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe fn game_assembly_slice() -> &'static [u8] {
|
||||
@@ -38,49 +38,78 @@ unsafe fn game_assembly_slice() -> &'static [u8] {
|
||||
}
|
||||
}
|
||||
|
||||
#[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::<MODULEINFO>() 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<usize> {
|
||||
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);
|
||||
match slice.get(address) {
|
||||
// jmp sub_xxxxxxx
|
||||
Some(&0xE8) => {
|
||||
let offset =
|
||||
i32::from_le_bytes(slice[address + 1..address + 5].try_into().unwrap());
|
||||
GAME_ASSEMBLY_BASE.wrapping_add(address + 5 + offset as usize)
|
||||
}
|
||||
// mov rcx, [rip + offset] (0x48 0x8B 0x0D XXXXXXXX)
|
||||
Some(&0x48)
|
||||
if slice.get(address + 1) == Some(&0x8B)
|
||||
&& slice.get(address + 2) == Some(&0x0D) =>
|
||||
{
|
||||
let offset =
|
||||
i32::from_le_bytes(slice[address + 3..address + 7].try_into().unwrap());
|
||||
GAME_ASSEMBLY_BASE.wrapping_add(address + 7 + offset as usize)
|
||||
}
|
||||
_ => GAME_ASSEMBLY_BASE.wrapping_add(address),
|
||||
}
|
||||
GAME_ASSEMBLY_BASE.wrapping_add(address)
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn scan_unity_player_section(pat: &str) -> Option<usize> {
|
||||
let mut slice = unsafe { unity_player_slice() };
|
||||
scan_first_match(&mut slice, pat)
|
||||
.unwrap()
|
||||
.map(|loc| UNITY_PLAYER_BASE.wrapping_add(loc))
|
||||
}
|
||||
// #[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::<MODULEINFO>() as u32,
|
||||
// )
|
||||
// .unwrap();
|
||||
// std::slice::from_raw_parts(
|
||||
// module.0 as *const u8,
|
||||
// module_info.SizeOfImage.try_into().unwrap(),
|
||||
// )
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub unsafe fn scan_unity_player_section(pat: &str) -> Option<usize> {
|
||||
// let mut slice = unsafe { unity_player_slice() };
|
||||
// scan_first_match(&mut slice, pat).unwrap().map(|address| {
|
||||
// let slice = unsafe { unity_player_slice() };
|
||||
// match slice.get(address) {
|
||||
// // jmp sub_xxxxxxx
|
||||
// Some(&0xE8) => {
|
||||
// let offset =
|
||||
// i32::from_le_bytes(slice[address + 1..address + 5].try_into().unwrap());
|
||||
// UNITY_PLAYER_BASE.wrapping_add(address + 5 + offset as usize)
|
||||
// }
|
||||
// // mov rcx, [rip + offset] (0x48 0x8B 0x0D XXXXXXXX)
|
||||
// Some(&0x48)
|
||||
// if slice.get(address + 1) == Some(&0x8B)
|
||||
// && slice.get(address + 2) == Some(&0x0D) =>
|
||||
// {
|
||||
// let offset =
|
||||
// i32::from_le_bytes(slice[address + 3..address + 7].try_into().unwrap());
|
||||
// UNITY_PLAYER_BASE.wrapping_add(address + 7 + offset as usize)
|
||||
// }
|
||||
// _ => UNITY_PLAYER_BASE.wrapping_add(address),
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
@@ -4,16 +4,17 @@ use std::ffi::CString;
|
||||
|
||||
use std::ptr::null_mut;
|
||||
use windows::Win32::Foundation::{CloseHandle, GetLastError, HANDLE};
|
||||
use windows::Win32::Security::{GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation};
|
||||
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,
|
||||
CREATE_SUSPENDED, CreateProcessA, CreateRemoteThread, OpenProcessToken, PROCESS_INFORMATION,
|
||||
ResumeThread, STARTUPINFOA, WaitForSingleObject,
|
||||
};
|
||||
use windows::core::{PSTR, s};
|
||||
use windows::core::{Error, PSTR, s};
|
||||
|
||||
fn inject_standard(h_target: HANDLE, dll_path: &str) -> bool {
|
||||
unsafe {
|
||||
@@ -70,7 +71,48 @@ fn inject_standard(h_target: HANDLE, dll_path: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_running_as_admin() -> Result<bool, Error> {
|
||||
unsafe {
|
||||
let mut token_handle = HANDLE::default();
|
||||
let current_process = windows::Win32::System::Threading::GetCurrentProcess();
|
||||
|
||||
if OpenProcessToken(current_process, TOKEN_QUERY, &mut token_handle).is_err() {
|
||||
return Err(windows::core::Error::from_win32());
|
||||
}
|
||||
|
||||
let mut elevation = TOKEN_ELEVATION::default();
|
||||
let mut size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
||||
|
||||
let success = GetTokenInformation(
|
||||
token_handle,
|
||||
TokenElevation,
|
||||
Some(&mut elevation as *mut _ as *mut _),
|
||||
size,
|
||||
&mut size,
|
||||
);
|
||||
|
||||
let _ = CloseHandle(token_handle);
|
||||
|
||||
if success.is_ok() {
|
||||
Ok(elevation.TokenIsElevated != 0)
|
||||
} else {
|
||||
Err(windows::core::Error::from_win32())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_exit() {
|
||||
println!("Press any key to exit...");
|
||||
let mut input = String::new();
|
||||
std::io::stdin().read_line(&mut input).unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if !is_running_as_admin().unwrap_or_default() {
|
||||
println!("launcher need to be launched as admin");
|
||||
wait_exit();
|
||||
}
|
||||
|
||||
let current_dir = std::env::current_dir().unwrap();
|
||||
let dll_path = current_dir.join("hkrpg.dll");
|
||||
if !dll_path.is_file() {
|
||||
|
||||
Reference in New Issue
Block a user