Compare commits

..

No commits in common. "master" and "3.1.5x" have entirely different histories.

15 changed files with 125 additions and 271 deletions

View File

@ -1,7 +1,4 @@
features: redirect HTTP requests & remove censorship!
- 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. currently, this has only been tested on CNBETAWin3.1.53 and may require an update for future versions.

View File

@ -1 +0,0 @@
<RSAKeyValue><Exponent>AQAB</Exponent><Modulus>hEegnKISgDas5VTuRBUlixB+bvmPvXKa3kVO22UEZjPGMUFLmIl3DhH+dsZo7qJn/GfJCUkP1FA0MJ5Bj8PX8IatLJKIJ9dMCNdnAlkXTlMg86QQAhHZN83vP4swj5ILcrGNKl3YAZ49fvzo7nheuTt0/40f0HkHdNa1dUHECBs=</Modulus></RSAKeyValue>

View File

@ -2,24 +2,25 @@ use std::sync::{LazyLock, OnceLock};
use windows::{Win32::System::LibraryLoader::GetModuleHandleA, core::s}; use windows::{Win32::System::LibraryLoader::GetModuleHandleA, core::s};
use crate::util::scan_il2cpp_section; use crate::util::{scan_il2cpp_section, scan_unity_player_section};
const IL2CPP_STRING_NEW_LEN: &str = const PTR_TO_STRING_ANSI: &str = "E8 ? ? ? ? 48 ? ? 48 85 C0 75 ? 48 8D 4C 24";
"E8 ? ? ? ? EB ? 31 C0 48 89 06 48 8B 47 ? 48 89 46 ? F2 0F 10 47"; 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 MAKE_INITIAL_URL: &str = const SET_ELEVATION_DITHER: &str = "E9 ? ? ? ? 0F 28 74 24 ? 48 83 C4 ? 5B 5F 5E 41 5E 41 5F C3 31 F6"; // TODO
"E8 ? ? ? ? 48 89 D9 48 89 C2 E8 ? ? ? ? 48 89 D9 4C 89 FA E8 ? ? ? ? 49 89 5D"; // TODO const SET_DISTANCE_DITHER: &str = "E8 ? ? ? ? 49 8B 46 ? 48 85 C0 0F 84 ? ? ? ? 48 8B 4D"; // TODO
const SET_DITHER: &str = "E8 ? ? ? ? 84 C0 75 ? C7 43"; 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 SDK_PUBLIC_KEY_LITERAL: &str = 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
"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_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 HK_CHECK2: &str = "55 41 57 41 56 41 55 41 54 56 57 53 48 81 EC B8 02 00 00";
#[derive(Default)] #[derive(Default)]
pub struct RVAConfig { pub struct RVAConfig {
pub il2cpp_string_new_len: usize, pub ptr_to_string_ansi: usize,
pub make_initial_url: usize, pub make_initial_url: usize,
pub set_dither: usize, pub set_elevation_dither: usize,
pub sdk_public_key: usize, pub set_distance_dither: usize,
pub set_dither_alpha: usize,
pub set_dither_alpha_anim: usize,
pub hk_check1: usize, pub hk_check1: usize,
pub hk_check2: usize, pub hk_check2: usize,
} }
@ -33,24 +34,22 @@ pub fn rva_config() -> &'static mut RVAConfig {
pub static GAME_ASSEMBLY_BASE: LazyLock<usize> = pub static GAME_ASSEMBLY_BASE: LazyLock<usize> =
LazyLock::new(|| unsafe { GetModuleHandleA(s!("GameAssembly.dll")).unwrap().0 as usize }); LazyLock::new(|| unsafe { GetModuleHandleA(s!("GameAssembly.dll")).unwrap().0 as usize });
// pub static UNITY_PLAYER_BASE: LazyLock<usize> = pub static UNITY_PLAYER_BASE: LazyLock<usize> =
// LazyLock::new(|| unsafe { GetModuleHandleA(s!("UnityPlayer.dll")).unwrap().0 as usize }); LazyLock::new(|| unsafe { GetModuleHandleA(s!("UnityPlayer.dll")).unwrap().0 as usize });
macro_rules! set_rva { macro_rules! set_rva {
($base:ident, $config:ident, $field:ident, $scan_fn:ident, $rva_pat:expr, $fallback:expr) => { ($config:ident, $field:ident, $scan_fn:ident, $rva_pat:expr, $fallback:expr) => {
if let Some(addr) = unsafe { $scan_fn($rva_pat) } { if let Some(addr) = unsafe { $scan_fn($rva_pat) } {
$config.$field = addr; $config.$field = addr - *GAME_ASSEMBLY_BASE;
println!( println!(
"[hkrpg::addr::set_rva] Found relative address for {} [{}] -> 0x{:X}", "[hkrpg::addr::set_rva] Found relative address for {} -> 0x{:X}",
stringify!($field), stringify!($field),
stringify!($base), $config.$field
$config.$field - *$base
); );
} else { } else {
eprintln!( eprintln!(
"[hkrpg::addr::set_rva] Failed to find pattern for {} [{}] using {}", "[hkrpg::addr::set_rva] Failed to find pattern for {} using {}",
stringify!($field), stringify!($field),
stringify!($base),
stringify!($scan_fn) stringify!($scan_fn)
); );
@ -62,19 +61,17 @@ macro_rules! set_rva {
pub unsafe fn init_rvas() { pub unsafe fn init_rvas() {
let config = rva_config(); let config = rva_config();
// il2cpp_string_new_len // ptr_to_string_ansi
set_rva!( set_rva!(
GAME_ASSEMBLY_BASE,
config, config,
il2cpp_string_new_len, ptr_to_string_ansi,
scan_il2cpp_section, scan_il2cpp_section,
IL2CPP_STRING_NEW_LEN, PTR_TO_STRING_ANSI,
0x0 0x0
); );
// make_initial_url // make_initial_url
set_rva!( set_rva!(
GAME_ASSEMBLY_BASE,
config, config,
make_initial_url, make_initial_url,
scan_il2cpp_section, scan_il2cpp_section,
@ -82,40 +79,39 @@ pub unsafe fn init_rvas() {
0x0 0x0
); );
// set_dither // set_elevation_dither
set_rva!( set_rva!(
GAME_ASSEMBLY_BASE,
config, config,
set_dither, set_elevation_dither,
scan_il2cpp_section, scan_il2cpp_section,
SET_DITHER, 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 0x0
); );
// sdk_public_key_literal set_rva!(config, hk_check1, scan_unity_player_section, HK_CHECK1, 0x0);
set_rva!( set_rva!(config, hk_check2, scan_unity_player_section, HK_CHECK2, 0x0);
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
// );
} }

View File

@ -1,6 +1,6 @@
use std::{ffi::CString, fmt::Display}; use std::{ffi::CString, fmt::Display};
use crate::addr::rva_config; use crate::addr::{GAME_ASSEMBLY_BASE, rva_config};
#[repr(transparent)] #[repr(transparent)]
pub struct Il2cppString(usize); pub struct Il2cppString(usize);
@ -15,7 +15,7 @@ impl Il2cppString {
pub fn new(string: &str) -> Self { pub fn new(string: &str) -> Self {
let func = unsafe { let func = unsafe {
std::mem::transmute::<usize, fn(*const u8, usize) -> usize>( std::mem::transmute::<usize, fn(*const u8, usize) -> usize>(
rva_config().il2cpp_string_new_len, *GAME_ASSEMBLY_BASE + rva_config().ptr_to_string_ansi,
) )
}; };
let len = string.len(); let len = string.len();

View File

@ -2,16 +2,13 @@ use ilhook::x64::{
CallbackOption, HookFlags, HookPoint, HookType, Hooker, JmpBackRoutine, RetnRoutine, CallbackOption, HookFlags, HookPoint, HookType, Hooker, JmpBackRoutine, RetnRoutine,
}; };
#[derive(Default)]
pub struct Interceptor { pub struct Interceptor {
hooks: Vec<HookPoint>, hooks: Vec<HookPoint>,
} }
type Result<T> = std::result::Result<T, ilhook::HookError>; type Result<T> = std::result::Result<T, ilhook::HookError>;
impl Interceptor { impl Interceptor {
pub const fn new() -> Self {
Interceptor { hooks: Vec::new() }
}
pub fn attach(&mut self, addr: usize, routine: JmpBackRoutine) -> Result<()> { pub fn attach(&mut self, addr: usize, routine: JmpBackRoutine) -> Result<()> {
let hooker = Hooker::new( let hooker = Hooker::new(
addr, addr,

View File

@ -3,8 +3,7 @@
use std::{thread, time::Duration}; use std::{thread, time::Duration};
use modules::{ use modules::{
HkrpgModuleManager, censorship_patch::CensorshipPatch, crypto::Crypto, hk_check::HkCheck, HkrpgModuleManager, censorship_patch::CensorshipPatch, hk_check::HkCheck, network::Network,
misc::Misc, network::Network,
}; };
use windows::{ use windows::{
Win32::System::{Console, LibraryLoader::GetModuleHandleA}, Win32::System::{Console, LibraryLoader::GetModuleHandleA},
@ -27,17 +26,11 @@ pub fn main() {
thread::sleep(Duration::from_millis(200)); 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(); addr::init_rvas();
let mut module_manager = HkrpgModuleManager::default(); let mut module_manager = HkrpgModuleManager::default();
module_manager.add::<HkCheck>(); module_manager.add::<HkCheck>();
module_manager.add::<Network>(); module_manager.add::<Network>();
module_manager.add::<Crypto>();
module_manager.add::<CensorshipPatch>(); module_manager.add::<CensorshipPatch>();
module_manager module_manager
.init() .init()

View File

@ -11,7 +11,7 @@ macro_rules! replace {
$( $(
if $config.$field != 0 { if $config.$field != 0 {
$self.interceptor.replace( $self.interceptor.replace(
$config.$field, $self.base.wrapping_add($config.$field),
CensorshipPatch::on_set_dither, CensorshipPatch::on_set_dither,
)?; )?;
} else { } else {
@ -24,7 +24,14 @@ macro_rules! replace {
impl HkrpgModule for HkrpgModuleContext<CensorshipPatch> { impl HkrpgModule for HkrpgModuleContext<CensorshipPatch> {
unsafe fn init(&mut self) -> Result<(), ilhook::HookError> { unsafe fn init(&mut self) -> Result<(), ilhook::HookError> {
let config = rva_config(); let config = rva_config();
replace!(self, config, set_dither); replace!(
self,
config,
set_distance_dither,
set_elevation_dither,
set_dither_alpha,
set_dither_alpha_anim
);
Ok(()) Ok(())
} }
} }

View File

@ -1,23 +0,0 @@
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(())
}
}

View File

@ -10,11 +10,14 @@ impl HkrpgModule for HkrpgModuleContext<HkCheck> {
unsafe fn init(&mut self) -> Result<(), ilhook::HookError> { unsafe fn init(&mut self) -> Result<(), ilhook::HookError> {
let config = rva_config(); let config = rva_config();
if config.hk_check1 != 0 && config.hk_check2 != 0 { if config.hk_check1 != 0 && config.hk_check2 != 0 {
self.interceptor self.interceptor.replace(
.replace(config.hk_check1, HkCheck::replacement)?; self.base.wrapping_add(config.hk_check1),
self.interceptor HkCheck::replacement,
.replace(config.hk_check2, HkCheck::replacement)?; )?;
println!("[hk_check::init] hk_check bypassed") self.interceptor.replace(
self.base.wrapping_add(config.hk_check2),
HkCheck::replacement,
)?;
} }
Ok(()) Ok(())
} }

View File

@ -1,39 +0,0 @@
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);
}
}
}
}

View File

@ -3,13 +3,11 @@ use std::marker::PhantomData;
use crate::{addr, interceptor::Interceptor}; use crate::{addr, interceptor::Interceptor};
pub mod censorship_patch; pub mod censorship_patch;
pub mod crypto;
pub mod hk_check; pub mod hk_check;
pub mod network; pub mod network;
pub mod misc;
pub struct HkrpgModuleContext<T> { pub struct HkrpgModuleContext<T> {
_base: usize, base: usize,
interceptor: Interceptor, interceptor: Interceptor,
_module_type: PhantomData<T>, _module_type: PhantomData<T>,
} }
@ -17,8 +15,8 @@ pub struct HkrpgModuleContext<T> {
impl<T> HkrpgModuleContext<T> { impl<T> HkrpgModuleContext<T> {
fn new(base: usize) -> Self { fn new(base: usize) -> Self {
Self { Self {
_base: base, base,
interceptor: Interceptor::new(), interceptor: Interceptor::default(),
_module_type: PhantomData, _module_type: PhantomData,
} }
} }

View File

@ -9,10 +9,11 @@ pub struct Network;
impl HkrpgModule for HkrpgModuleContext<Network> { impl HkrpgModule for HkrpgModuleContext<Network> {
unsafe fn init(&mut self) -> Result<(), ilhook::HookError> { unsafe fn init(&mut self) -> Result<(), ilhook::HookError> {
let config = rva_config(); let config = rva_config();
if config.make_initial_url != 0 && config.il2cpp_string_new_len != 0 { if config.make_initial_url != 0 && config.ptr_to_string_ansi != 0 {
self.interceptor self.interceptor.attach(
.attach(config.make_initial_url, Network::on_make_initial_url)?; self.base.wrapping_add(config.make_initial_url),
println!("[network::init] network patch enabled") Network::on_make_initial_url,
)?;
} else { } else {
println!("[network::init] pattern is outdated! disabling http redirection") println!("[network::init] pattern is outdated! disabling http redirection")
} }

View File

@ -10,7 +10,7 @@ use windows::{
core::s, core::s,
}; };
use crate::addr::GAME_ASSEMBLY_BASE; use crate::addr::{GAME_ASSEMBLY_BASE, UNITY_PLAYER_BASE};
#[allow(static_mut_refs)] #[allow(static_mut_refs)]
unsafe fn game_assembly_slice() -> &'static [u8] { unsafe fn game_assembly_slice() -> &'static [u8] {
@ -38,78 +38,49 @@ 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> { pub unsafe fn scan_il2cpp_section(pat: &str) -> Option<usize> {
let mut slice = unsafe { game_assembly_slice() }; let mut slice = unsafe { game_assembly_slice() };
scan_first_match(&mut slice, pat).unwrap().map(|address| { scan_first_match(&mut slice, pat).unwrap().map(|address| {
let slice = unsafe { game_assembly_slice() }; let slice = unsafe { game_assembly_slice() };
match slice.get(address) { let instruction = &slice[address..address + 1][0];
// jmp sub_xxxxxxx if *instruction == 0xE8 {
Some(&0xE8) => { let offset = i32::from_le_bytes((&slice[address + 1..address + 1 + 4]).try_into().unwrap());
let offset = let pointer = offset as usize + 5 + address;
i32::from_le_bytes(slice[address + 1..address + 5].try_into().unwrap()); return GAME_ASSEMBLY_BASE.wrapping_add(pointer);
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)
}) })
} }
// #[allow(static_mut_refs)] pub unsafe fn scan_unity_player_section(pat: &str) -> Option<usize> {
// unsafe fn unity_player_slice() -> &'static [u8] { let mut slice = unsafe { unity_player_slice() };
// static mut SLICE: OnceCell<&[u8]> = OnceCell::new(); scan_first_match(&mut slice, pat)
// unsafe { .unwrap()
// SLICE.get_or_init(|| { .map(|loc| UNITY_PLAYER_BASE.wrapping_add(loc))
// 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),
// }
// })
// }

View File

@ -1,4 +0,0 @@
fn main() {
println!("cargo:rustc-link-arg-bin=launcher=/MANIFEST:EMBED");
println!("cargo:rustc-link-arg-bin=launcher=/MANIFESTUAC:level=\'requireAdministrator\'");
}

View File

@ -4,17 +4,16 @@ use std::ffi::CString;
use std::ptr::null_mut; use std::ptr::null_mut;
use windows::Win32::Foundation::{CloseHandle, GetLastError, HANDLE}; 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::Diagnostics::Debug::WriteProcessMemory;
use windows::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress}; use windows::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress};
use windows::Win32::System::Memory::{ use windows::Win32::System::Memory::{
MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, VirtualAllocEx, VirtualFreeEx, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_READWRITE, VirtualAllocEx, VirtualFreeEx,
}; };
use windows::Win32::System::Threading::{ use windows::Win32::System::Threading::{
CREATE_SUSPENDED, CreateProcessA, CreateRemoteThread, OpenProcessToken, PROCESS_INFORMATION, CREATE_SUSPENDED, CreateProcessA, CreateRemoteThread, PROCESS_INFORMATION, ResumeThread,
ResumeThread, STARTUPINFOA, WaitForSingleObject, STARTUPINFOA, WaitForSingleObject,
}; };
use windows::core::{Error, PSTR, s}; use windows::core::{PSTR, s};
fn inject_standard(h_target: HANDLE, dll_path: &str) -> bool { fn inject_standard(h_target: HANDLE, dll_path: &str) -> bool {
unsafe { unsafe {
@ -71,48 +70,7 @@ 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() { 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 current_dir = std::env::current_dir().unwrap();
let dll_path = current_dir.join("hkrpg.dll"); let dll_path = current_dir.join("hkrpg.dll");
if !dll_path.is_file() { if !dll_path.is_file() {