Compare commits
No commits in common. "master" and "0.1.1" have entirely different histories.
11 changed files with 116 additions and 104 deletions
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "ext"
|
||||
name = "version"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# hk4e-patch
|
||||
|
||||
Genshin Impact encryption patch (5.0.0)
|
||||
Genshin Impact encryption patch (4.8.50)
|
||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -3,11 +3,10 @@
|
|||
use std::{sync::RwLock, time::Duration};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use modules::{CcpBlocker, Misc};
|
||||
use windows::core::PCSTR;
|
||||
use util::try_get_base_address;
|
||||
use windows::Win32::Foundation::HINSTANCE;
|
||||
use windows::Win32::System::Console;
|
||||
use windows::Win32::System::SystemServices::DLL_PROCESS_ATTACH;
|
||||
use windows::Win32::{Foundation::HINSTANCE, System::LibraryLoader::GetModuleHandleA};
|
||||
|
||||
mod interceptor;
|
||||
mod marshal;
|
||||
|
@ -17,23 +16,19 @@ mod util;
|
|||
use crate::modules::{Http, MhyContext, ModuleManager, Security};
|
||||
|
||||
unsafe fn thread_func() {
|
||||
let base = GetModuleHandleA(PCSTR::null()).unwrap().0 as usize;
|
||||
let mut module_manager = MODULE_MANAGER.write().unwrap();
|
||||
let base = try_get_base_address("GenshinImpact.exe").unwrap();
|
||||
|
||||
// Block query_security_file ASAP
|
||||
module_manager.enable(MhyContext::<CcpBlocker>::new(base));
|
||||
|
||||
std::thread::sleep(Duration::from_secs(14));
|
||||
std::thread::sleep(Duration::from_secs(12));
|
||||
|
||||
util::disable_memprotect_guard();
|
||||
Console::AllocConsole().unwrap();
|
||||
|
||||
println!("Genshin Impact encryption patch\nMade by xeondev\nTo work with sakura-rs: git.xeondev.com/sakura-rs/sakura-rs");
|
||||
println!("Genshin Impact encryption patch\nMade by xeondev\nTo work with MualaniImpact: git.xeondev.com/reversedrooms/MualaniImpact");
|
||||
println!("Base: {:X}", base);
|
||||
|
||||
let mut module_manager = MODULE_MANAGER.write().unwrap();
|
||||
module_manager.enable(MhyContext::<Http>::new(base));
|
||||
module_manager.enable(MhyContext::<Security>::new(base));
|
||||
module_manager.enable(MhyContext::<Misc>::new(base));
|
||||
|
||||
println!("Successfully initialized!");
|
||||
}
|
||||
|
@ -43,7 +38,6 @@ lazy_static! {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) -> bool {
|
||||
if call_reason == DLL_PROCESS_ATTACH {
|
||||
std::thread::spawn(|| thread_func());
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::ffi::CStr;
|
||||
|
||||
use windows::{core::PCSTR, Win32::System::LibraryLoader::GetModuleHandleA};
|
||||
use crate::util;
|
||||
|
||||
const PTR_TO_STRING_ANSI: usize = 0xF85E020;
|
||||
const PTR_TO_STRING_ANSI: usize = 0x104F80F0;
|
||||
type MarshalPtrToStringAnsi = unsafe extern "fastcall" fn(*const u8) -> *const u8;
|
||||
|
||||
pub unsafe fn ptr_to_string_ansi(content: &CStr) -> *const u8 {
|
||||
|
@ -11,5 +11,5 @@ pub unsafe fn ptr_to_string_ansi(content: &CStr) -> *const u8 {
|
|||
}
|
||||
|
||||
unsafe fn base() -> usize {
|
||||
GetModuleHandleA(PCSTR::null()).unwrap().0 as usize
|
||||
util::try_get_base_address("GenshinImpact.exe").unwrap()
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
use std::ffi::CStr;
|
||||
|
||||
use super::{MhyContext, MhyModule, ModuleType};
|
||||
use anyhow::Result;
|
||||
use ilhook::x64::Registers;
|
||||
use windows::{
|
||||
core::s,
|
||||
Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress},
|
||||
};
|
||||
|
||||
pub struct CcpBlocker;
|
||||
|
||||
impl MhyModule for MhyContext<CcpBlocker> {
|
||||
unsafe fn init(&mut self) -> Result<()> {
|
||||
let winsock2 = GetModuleHandleA(s!("Ws2_32.dll")).unwrap();
|
||||
let getaddrinfo = GetProcAddress(winsock2, s!("getaddrinfo")).unwrap();
|
||||
|
||||
self.interceptor
|
||||
.attach(getaddrinfo as usize, on_getaddrinfo)
|
||||
}
|
||||
|
||||
unsafe fn de_init(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_module_type(&self) -> super::ModuleType {
|
||||
ModuleType::CcpBlocker
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "win64" fn on_getaddrinfo(reg: *mut Registers, _: usize) {
|
||||
let host_ptr = (*reg).rcx as *const i8;
|
||||
let host = CStr::from_ptr(host_ptr).to_string_lossy();
|
||||
|
||||
if host == "dispatchosglobal.yuanshen.com" || host == "dispatchcnglobal.yuanshen.com" {
|
||||
std::ptr::copy_nonoverlapping(c"0.0.0.0".as_ptr(), (*reg).rcx as *mut i8, 9);
|
||||
}
|
||||
}
|
|
@ -5,8 +5,8 @@ use crate::marshal;
|
|||
use anyhow::Result;
|
||||
use ilhook::x64::Registers;
|
||||
|
||||
const WEB_REQUEST_UTILS_MAKE_INITIAL_URL: usize = 0x10421E00;
|
||||
const BROWSER_LOAD_URL: usize = 0x10222B20;
|
||||
const WEB_REQUEST_UTILS_MAKE_INITIAL_URL: usize = 0x1119FF40;
|
||||
const BROWSER_LOAD_URL: usize = 0x10FD8450;
|
||||
|
||||
pub struct Http;
|
||||
|
||||
|
@ -48,12 +48,10 @@ unsafe extern "win64" fn on_make_initial_url(reg: *mut Registers, _: usize) {
|
|||
new_url.push_str(s);
|
||||
});
|
||||
|
||||
if !url.contains("/query_cur_region") {
|
||||
println!("Redirect: {url} -> {new_url}");
|
||||
(*reg).rcx =
|
||||
marshal::ptr_to_string_ansi(CString::new(new_url.as_str()).unwrap().as_c_str()) as u64;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "win64" fn on_browser_load_url(reg: *mut Registers, _: usize) {
|
||||
let str_length = *((*reg).rdx.wrapping_add(16) as *const u32);
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
use super::{MhyContext, MhyModule, ModuleType};
|
||||
use anyhow::Result;
|
||||
use ilhook::x64::Registers;
|
||||
|
||||
pub struct Misc;
|
||||
|
||||
const SET_CUSTOM_PROPERTY_FLOAT: usize = 0x12199F0;
|
||||
|
||||
impl MhyModule for MhyContext<Misc> {
|
||||
unsafe fn init(&mut self) -> Result<()> {
|
||||
// Dither
|
||||
self.interceptor.replace(
|
||||
self.assembly_base + SET_CUSTOM_PROPERTY_FLOAT,
|
||||
set_custom_property_float_replacement,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn de_init(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_module_type(&self) -> super::ModuleType {
|
||||
ModuleType::Misc
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "win64" fn set_custom_property_float_replacement(
|
||||
_: *mut Registers,
|
||||
_: usize,
|
||||
_: usize,
|
||||
) -> usize {
|
||||
0
|
||||
}
|
|
@ -4,14 +4,10 @@ use anyhow::Result;
|
|||
|
||||
use crate::interceptor::Interceptor;
|
||||
|
||||
mod ccp_blocker;
|
||||
mod http;
|
||||
mod misc;
|
||||
mod security;
|
||||
|
||||
pub use ccp_blocker::CcpBlocker;
|
||||
pub use http::Http;
|
||||
pub use misc::Misc;
|
||||
pub use security::Security;
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -42,8 +38,6 @@ impl ModuleManager {
|
|||
pub enum ModuleType {
|
||||
Http,
|
||||
Security,
|
||||
Misc,
|
||||
CcpBlocker,
|
||||
}
|
||||
|
||||
pub trait MhyModule {
|
||||
|
|
|
@ -6,9 +6,9 @@ use super::{MhyContext, MhyModule, ModuleType};
|
|||
use anyhow::Result;
|
||||
use ilhook::x64::Registers;
|
||||
|
||||
const MHYRSA_PERFORM_CRYPTO_ACTION: usize = 0x95ED88;
|
||||
const KEY_SIGN_CHECK: usize = 0x960C7C;
|
||||
const SDK_UTIL_RSA_ENCRYPT: usize = 0xFC0CC30;
|
||||
const MHYRSA_PERFORM_CRYPTO_ACTION: usize = 0xC3DEDB;
|
||||
const KEY_SIGN_CHECK: usize = 0xC4236D;
|
||||
const SDK_UTIL_RSA_ENCRYPT: usize = 0x10A02A60;
|
||||
|
||||
const KEY_SIZE: usize = 268;
|
||||
static SERVER_PUBLIC_KEY: &[u8] = include_bytes!("../../server_public_key.bin");
|
||||
|
|
|
@ -10,6 +10,15 @@ pub fn wide_str(value: &str) -> Vec<u16> {
|
|||
OsStr::new(value).encode_wide().chain(once(0)).collect()
|
||||
}
|
||||
|
||||
pub unsafe fn try_get_base_address(module_name: &str) -> Option<usize> {
|
||||
let w_module_name = wide_str(module_name);
|
||||
|
||||
match GetModuleHandleW(PCWSTR::from_raw(w_module_name.as_ptr())) {
|
||||
Ok(module) => Some(module.0 as usize),
|
||||
Err(_) => None
|
||||
}
|
||||
}
|
||||
|
||||
// VMProtect hooks NtProtectVirtualMemory to prevent changing protection of executable segments
|
||||
// We use this trick to remove hook
|
||||
pub unsafe fn disable_memprotect_guard() {
|
||||
|
|
88
src/version.rs
Normal file
88
src/version.rs
Normal file
|
@ -0,0 +1,88 @@
|
|||
use libloading::{Error, Library, Symbol};
|
||||
use std::arch::asm;
|
||||
use std::env;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
pub struct VersionDllProxy {
|
||||
library: Library,
|
||||
}
|
||||
|
||||
impl VersionDllProxy {
|
||||
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let system_directory = env::var("windir")? + ("\\System32\\");
|
||||
let dll_path = system_directory + "version.dll";
|
||||
let library = unsafe { Library::new(dll_path) }?;
|
||||
Ok(Self { library })
|
||||
}
|
||||
|
||||
fn get_function<T>(&self, func_name: &CStr) -> Result<Symbol<T>, Error> {
|
||||
unsafe { self.library.get(func_name.to_bytes_with_nul()) }
|
||||
}
|
||||
|
||||
pub fn load_functions(&self) -> Result<(), Error> {
|
||||
for (i, &name) in FUNCTION_NAMES.iter().enumerate() {
|
||||
let fn_ptr = self.get_function::<Symbol<*mut usize>>(name)?;
|
||||
unsafe { ORIGINAL_FUNCTIONS[i] = **fn_ptr };
|
||||
println!("Loaded function {}@{:p}", name.to_str().unwrap(), unsafe {
|
||||
ORIGINAL_FUNCTIONS[i]
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! count_exprs {
|
||||
() => {0usize};
|
||||
($head:expr, $($tail:expr,)*) => {1usize + count_exprs!($($tail,)*)};
|
||||
}
|
||||
|
||||
macro_rules! version_dll_proxy {
|
||||
($($fn_name:ident),*) => {
|
||||
static FUNCTION_NAMES: &[&CStr] = &[
|
||||
$(
|
||||
unsafe { CStr::from_bytes_with_nul_unchecked(concat!(stringify!($fn_name), "\0").as_bytes()) }
|
||||
),*,
|
||||
];
|
||||
|
||||
#[no_mangle]
|
||||
static mut ORIGINAL_FUNCTIONS: [*const usize; count_exprs!($($fn_name,)*)] = [0 as *const usize; count_exprs!($($fn_name,)*)];
|
||||
|
||||
$(
|
||||
#[no_mangle]
|
||||
extern "C" fn $fn_name() {
|
||||
let function_name = FUNCTION_NAMES
|
||||
.iter()
|
||||
.position(|&name| name == CString::new(stringify!($fn_name)).unwrap().as_ref())
|
||||
.unwrap();
|
||||
let fn_addr = unsafe { ORIGINAL_FUNCTIONS[function_name] };
|
||||
unsafe {
|
||||
asm! {
|
||||
"call {tmp}",
|
||||
tmp = in(reg) fn_addr,
|
||||
clobber_abi("C")
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
version_dll_proxy! {
|
||||
GetFileVersionInfoA,
|
||||
GetFileVersionInfoByHandle,
|
||||
GetFileVersionInfoExA,
|
||||
GetFileVersionInfoExW,
|
||||
GetFileVersionInfoSizeA,
|
||||
GetFileVersionInfoSizeExA,
|
||||
GetFileVersionInfoSizeExW,
|
||||
GetFileVersionInfoSizeW,
|
||||
GetFileVersionInfoW,
|
||||
VerFindFileA,
|
||||
VerFindFileW,
|
||||
VerInstallFileA,
|
||||
VerInstallFileW,
|
||||
VerLanguageNameA,
|
||||
VerLanguageNameW,
|
||||
VerQueryValueA,
|
||||
VerQueryValueW
|
||||
}
|
Loading…
Reference in a new issue