forked from reversedrooms/hk4e-patch
Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
c78470e82b | |||
458b3d75f5 | |||
38e0c1d28f | |||
4603f68722 | |||
67bc2a2aaa | |||
6d5a9f2098 |
12 changed files with 180 additions and 166 deletions
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "version"
|
name = "ext"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
# hk4e-patch
|
# hk4e-patch
|
||||||
|
|
||||||
Genshin Impact encryption patch (4.6.0)
|
Genshin Impact encryption patch (5.0.0)
|
||||||
|
|
1
sdk_public_key.xml
Normal file
1
sdk_public_key.xml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<RSAKeyValue><Exponent>AQAB</Exponent><Modulus>hEegnKISgDas5VTuRBUlixB+bvmPvXKa3kVO22UEZjPGMUFLmIl3DhH+dsZo7qJn/GfJCUkP1FA0MJ5Bj8PX8IatLJKIJ9dMCNdnAlkXTlMg86QQAhHZN83vP4swj5ILcrGNKl3YAZ49fvzo7nheuTt0/40f0HkHdNa1dUHECBs=</Modulus></RSAKeyValue>
|
32
src/lib.rs
32
src/lib.rs
|
@ -3,57 +3,49 @@
|
||||||
use std::{sync::RwLock, time::Duration};
|
use std::{sync::RwLock, time::Duration};
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use util::try_get_base_address;
|
use modules::{CcpBlocker, Misc};
|
||||||
use windows::Win32::Foundation::HINSTANCE;
|
use windows::core::PCSTR;
|
||||||
use windows::Win32::System::Console;
|
use windows::Win32::System::Console;
|
||||||
use windows::Win32::System::SystemServices::DLL_PROCESS_ATTACH;
|
use windows::Win32::System::SystemServices::DLL_PROCESS_ATTACH;
|
||||||
|
use windows::Win32::{Foundation::HINSTANCE, System::LibraryLoader::GetModuleHandleA};
|
||||||
|
|
||||||
mod interceptor;
|
mod interceptor;
|
||||||
mod marshal;
|
mod marshal;
|
||||||
mod modules;
|
mod modules;
|
||||||
mod util;
|
mod util;
|
||||||
mod version;
|
|
||||||
use version::VersionDllProxy;
|
|
||||||
|
|
||||||
use crate::modules::{Http, MhyContext, ModuleManager, Security};
|
use crate::modules::{Http, MhyContext, ModuleManager, Security};
|
||||||
|
|
||||||
unsafe fn thread_func() {
|
unsafe fn thread_func() {
|
||||||
let base = loop {
|
let base = GetModuleHandleA(PCSTR::null()).unwrap().0 as usize;
|
||||||
if let Some(base) = try_get_base_address("UserAssembly.dll") {
|
let mut module_manager = MODULE_MANAGER.write().unwrap();
|
||||||
break base;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread::sleep(Duration::from_millis(500));
|
// Block query_security_file ASAP
|
||||||
};
|
module_manager.enable(MhyContext::<CcpBlocker>::new(base));
|
||||||
|
|
||||||
std::thread::sleep(Duration::from_secs(7));
|
std::thread::sleep(Duration::from_secs(14));
|
||||||
|
|
||||||
util::disable_memprotect_guard();
|
util::disable_memprotect_guard();
|
||||||
Console::AllocConsole().unwrap();
|
Console::AllocConsole().unwrap();
|
||||||
|
|
||||||
println!("Genshin Impact encryption patch\nMade by xeondev\nTo work with NaviaImpact: git.xeondev.com/reversedrooms/NaviaImpact");
|
println!("Genshin Impact encryption patch\nMade by xeondev\nTo work with sakura-rs: git.xeondev.com/sakura-rs/sakura-rs");
|
||||||
println!("UserAssembly: {:X}", base);
|
println!("Base: {:X}", base);
|
||||||
|
|
||||||
let mut module_manager = MODULE_MANAGER.write().unwrap();
|
|
||||||
module_manager.enable(MhyContext::<Http>::new(base));
|
module_manager.enable(MhyContext::<Http>::new(base));
|
||||||
module_manager.enable(MhyContext::<Security>::new(base));
|
module_manager.enable(MhyContext::<Security>::new(base));
|
||||||
|
module_manager.enable(MhyContext::<Misc>::new(base));
|
||||||
|
|
||||||
println!("Successfully initialized!");
|
println!("Successfully initialized!");
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref VERSION_DLL_PROXY: version::VersionDllProxy =
|
|
||||||
VersionDllProxy::new().expect("Failed to load version.dll");
|
|
||||||
static ref MODULE_MANAGER: RwLock<ModuleManager> = RwLock::new(ModuleManager::default());
|
static ref MODULE_MANAGER: RwLock<ModuleManager> = RwLock::new(ModuleManager::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) -> bool {
|
unsafe extern "system" fn DllMain(_: HINSTANCE, call_reason: u32, _: *mut ()) -> bool {
|
||||||
if call_reason == DLL_PROCESS_ATTACH {
|
if call_reason == DLL_PROCESS_ATTACH {
|
||||||
VERSION_DLL_PROXY
|
|
||||||
.load_functions()
|
|
||||||
.expect("Failed to load functions from version.dll");
|
|
||||||
|
|
||||||
std::thread::spawn(|| thread_func());
|
std::thread::spawn(|| thread_func());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
use crate::util;
|
use windows::{core::PCSTR, Win32::System::LibraryLoader::GetModuleHandleA};
|
||||||
|
|
||||||
const PTR_TO_STRING_ANSI: usize = 0xCF7CE50;
|
const PTR_TO_STRING_ANSI: usize = 0xF85E020;
|
||||||
type MarshalPtrToStringAnsi = unsafe extern "fastcall" fn(*const u8) -> *const u8;
|
type MarshalPtrToStringAnsi = unsafe extern "fastcall" fn(*const u8) -> *const u8;
|
||||||
|
|
||||||
pub unsafe fn ptr_to_string_ansi(content: &CStr) -> *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 {
|
unsafe fn base() -> usize {
|
||||||
util::try_get_base_address("UserAssembly.dll").unwrap()
|
GetModuleHandleA(PCSTR::null()).unwrap().0 as usize
|
||||||
}
|
}
|
||||||
|
|
38
src/modules/ccp_blocker.rs
Normal file
38
src/modules/ccp_blocker.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
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,16 +5,20 @@ use crate::marshal;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ilhook::x64::Registers;
|
use ilhook::x64::Registers;
|
||||||
|
|
||||||
const UNITY_WEB_REQUEST_SET_URL: usize = 0xD9442D0;
|
const WEB_REQUEST_UTILS_MAKE_INITIAL_URL: usize = 0x10421E00;
|
||||||
|
const BROWSER_LOAD_URL: usize = 0x10222B20;
|
||||||
|
|
||||||
pub struct Http;
|
pub struct Http;
|
||||||
|
|
||||||
impl MhyModule for MhyContext<Http> {
|
impl MhyModule for MhyContext<Http> {
|
||||||
unsafe fn init(&mut self) -> Result<()> {
|
unsafe fn init(&mut self) -> Result<()> {
|
||||||
self.interceptor.attach(
|
self.interceptor.attach(
|
||||||
self.assembly_base + UNITY_WEB_REQUEST_SET_URL,
|
self.assembly_base + WEB_REQUEST_UTILS_MAKE_INITIAL_URL,
|
||||||
on_uwr_set_url,
|
on_make_initial_url,
|
||||||
)
|
)?;
|
||||||
|
|
||||||
|
self.interceptor
|
||||||
|
.attach(self.assembly_base + BROWSER_LOAD_URL, on_browser_load_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn de_init(&mut self) -> Result<()> {
|
unsafe fn de_init(&mut self) -> Result<()> {
|
||||||
|
@ -26,7 +30,32 @@ impl MhyModule for MhyContext<Http> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "win64" fn on_uwr_set_url(reg: *mut Registers, _: usize) {
|
unsafe extern "win64" fn on_make_initial_url(reg: *mut Registers, _: usize) {
|
||||||
|
let str_length = *((*reg).rcx.wrapping_add(16) as *const u32);
|
||||||
|
let str_ptr = (*reg).rcx.wrapping_add(20) as *const u8;
|
||||||
|
|
||||||
|
let slice = std::slice::from_raw_parts(str_ptr, (str_length * 2) as usize);
|
||||||
|
let url = String::from_utf16le(slice).unwrap();
|
||||||
|
|
||||||
|
let mut new_url = if url.contains("/query_region_list") {
|
||||||
|
String::from("http://127.0.0.1:21041")
|
||||||
|
} else {
|
||||||
|
String::from("http://127.0.0.1:21000")
|
||||||
|
};
|
||||||
|
|
||||||
|
url.split('/').skip(3).for_each(|s| {
|
||||||
|
new_url.push_str("/");
|
||||||
|
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);
|
let str_length = *((*reg).rdx.wrapping_add(16) as *const u32);
|
||||||
let str_ptr = (*reg).rdx.wrapping_add(20) as *const u8;
|
let str_ptr = (*reg).rdx.wrapping_add(20) as *const u8;
|
||||||
|
|
||||||
|
@ -39,7 +68,8 @@ unsafe extern "win64" fn on_uwr_set_url(reg: *mut Registers, _: usize) {
|
||||||
new_url.push_str(s);
|
new_url.push_str(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
println!("Redirect: {url} -> {new_url}");
|
println!("Browser::LoadURL: {url} -> {new_url}");
|
||||||
|
|
||||||
(*reg).rdx =
|
(*reg).rdx =
|
||||||
marshal::ptr_to_string_ansi(CString::new(new_url.as_str()).unwrap().as_c_str()) as u64;
|
marshal::ptr_to_string_ansi(CString::new(new_url.as_str()).unwrap().as_c_str()) as u64;
|
||||||
}
|
}
|
||||||
|
|
33
src/modules/misc.rs
Normal file
33
src/modules/misc.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
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,10 +4,14 @@ use anyhow::Result;
|
||||||
|
|
||||||
use crate::interceptor::Interceptor;
|
use crate::interceptor::Interceptor;
|
||||||
|
|
||||||
|
mod ccp_blocker;
|
||||||
mod http;
|
mod http;
|
||||||
|
mod misc;
|
||||||
mod security;
|
mod security;
|
||||||
|
|
||||||
|
pub use ccp_blocker::CcpBlocker;
|
||||||
pub use http::Http;
|
pub use http::Http;
|
||||||
|
pub use misc::Misc;
|
||||||
pub use security::Security;
|
pub use security::Security;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -38,6 +42,8 @@ impl ModuleManager {
|
||||||
pub enum ModuleType {
|
pub enum ModuleType {
|
||||||
Http,
|
Http,
|
||||||
Security,
|
Security,
|
||||||
|
Misc,
|
||||||
|
CcpBlocker,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MhyModule {
|
pub trait MhyModule {
|
||||||
|
|
|
@ -1,25 +1,35 @@
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
use crate::marshal;
|
||||||
|
|
||||||
use super::{MhyContext, MhyModule, ModuleType};
|
use super::{MhyContext, MhyModule, ModuleType};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use ilhook::x64::Registers;
|
use ilhook::x64::Registers;
|
||||||
|
|
||||||
const IL2CPP_ARRAY_NEW: usize = 0x553C10;
|
const MHYRSA_PERFORM_CRYPTO_ACTION: usize = 0x95ED88;
|
||||||
const KEY_SIGN_CHECK: usize = 0x41C5;
|
const KEY_SIGN_CHECK: usize = 0x960C7C;
|
||||||
|
const SDK_UTIL_RSA_ENCRYPT: usize = 0xFC0CC30;
|
||||||
|
|
||||||
const KEY_SIZE: u64 = 272;
|
const KEY_SIZE: usize = 268;
|
||||||
const KEY_PREFIX: u64 = 0x0D700010182020A01;
|
|
||||||
static SERVER_PUBLIC_KEY: &[u8] = include_bytes!("../../server_public_key.bin");
|
static SERVER_PUBLIC_KEY: &[u8] = include_bytes!("../../server_public_key.bin");
|
||||||
type Il2cppArrayNew = unsafe extern "fastcall" fn(u64, u64) -> *const u8;
|
static SDK_PUBLIC_KEY: &str = include_str!("../../sdk_public_key.xml");
|
||||||
|
|
||||||
pub struct Security;
|
pub struct Security;
|
||||||
|
|
||||||
impl MhyModule for MhyContext<Security> {
|
impl MhyModule for MhyContext<Security> {
|
||||||
unsafe fn init(&mut self) -> Result<()> {
|
unsafe fn init(&mut self) -> Result<()> {
|
||||||
self.interceptor.replace(
|
self.interceptor.attach(
|
||||||
self.assembly_base + IL2CPP_ARRAY_NEW,
|
self.assembly_base + MHYRSA_PERFORM_CRYPTO_ACTION,
|
||||||
il2cpp_array_new_replacement,
|
on_mhy_rsa,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.interceptor
|
self.interceptor
|
||||||
.attach(self.assembly_base + KEY_SIGN_CHECK, after_key_sign_check)
|
.attach(self.assembly_base + KEY_SIGN_CHECK, after_key_sign_check)?;
|
||||||
|
|
||||||
|
self.interceptor.attach(
|
||||||
|
self.assembly_base + SDK_UTIL_RSA_ENCRYPT,
|
||||||
|
on_sdk_util_rsa_encrypt,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn de_init(&mut self) -> Result<()> {
|
unsafe fn de_init(&mut self) -> Result<()> {
|
||||||
|
@ -31,36 +41,28 @@ impl MhyModule for MhyContext<Security> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign check of rsa key that we just replaced.
|
|
||||||
unsafe extern "win64" fn after_key_sign_check(reg: *mut Registers, _: usize) {
|
unsafe extern "win64" fn after_key_sign_check(reg: *mut Registers, _: usize) {
|
||||||
|
println!("key sign check!");
|
||||||
(*reg).rax = 1
|
(*reg).rax = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut KEY_PTR: Option<*mut u8> = None;
|
unsafe extern "win64" fn on_mhy_rsa(reg: *mut Registers, _: usize) {
|
||||||
unsafe extern "win64" fn il2cpp_array_new_replacement(
|
println!("key: {:X}", *((*reg).rdx as *const u64));
|
||||||
reg: *mut Registers,
|
println!("len: {:X}", (*reg).r8);
|
||||||
actual_func: usize,
|
|
||||||
_: usize,
|
if (*reg).r8 as usize == KEY_SIZE {
|
||||||
) -> usize {
|
println!("[*] key replaced");
|
||||||
let il2cpp_array_new = std::mem::transmute::<usize, Il2cppArrayNew>(actual_func);
|
|
||||||
let ret_val = il2cpp_array_new((*reg).rcx, (*reg).rdx) as usize;
|
|
||||||
|
|
||||||
let rdx = (*reg).rdx;
|
|
||||||
if rdx == KEY_SIZE {
|
|
||||||
KEY_PTR = Some(ret_val as *mut u8);
|
|
||||||
} else {
|
|
||||||
if let Some(key_ptr) = KEY_PTR {
|
|
||||||
if *(key_ptr.wrapping_add(32) as *const u64) == KEY_PREFIX {
|
|
||||||
std::ptr::copy_nonoverlapping(
|
std::ptr::copy_nonoverlapping(
|
||||||
SERVER_PUBLIC_KEY.as_ptr(),
|
SERVER_PUBLIC_KEY.as_ptr(),
|
||||||
key_ptr.wrapping_add(32),
|
(*reg).rdx as *mut u8,
|
||||||
SERVER_PUBLIC_KEY.len(),
|
SERVER_PUBLIC_KEY.len(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KEY_PTR = None;
|
unsafe extern "win64" fn on_sdk_util_rsa_encrypt(reg: *mut Registers, _: usize) {
|
||||||
}
|
println!("[*] SDK RSA: key replaced");
|
||||||
|
(*reg).rcx =
|
||||||
ret_val
|
marshal::ptr_to_string_ansi(CString::new(SDK_PUBLIC_KEY).unwrap().as_c_str()) as u64;
|
||||||
}
|
}
|
||||||
|
|
26
src/util.rs
26
src/util.rs
|
@ -2,23 +2,14 @@ use core::iter::once;
|
||||||
use std::ffi::{c_void, OsStr};
|
use std::ffi::{c_void, OsStr};
|
||||||
|
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use windows::Win32::System::LibraryLoader::{GetProcAddress, GetModuleHandleW};
|
use windows::Win32::System::LibraryLoader::{GetModuleHandleA, GetModuleHandleW, GetProcAddress};
|
||||||
use windows::Win32::System::Memory::{PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS, VirtualProtect};
|
use windows::Win32::System::Memory::{PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS, VirtualProtect};
|
||||||
use windows::core::{PCSTR, PCWSTR};
|
use windows::core::{s, PCSTR, PCWSTR};
|
||||||
|
|
||||||
pub fn wide_str(value: &str) -> Vec<u16> {
|
pub fn wide_str(value: &str) -> Vec<u16> {
|
||||||
OsStr::new(value).encode_wide().chain(once(0)).collect()
|
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
|
// VMProtect hooks NtProtectVirtualMemory to prevent changing protection of executable segments
|
||||||
// We use this trick to remove hook
|
// We use this trick to remove hook
|
||||||
pub unsafe fn disable_memprotect_guard() {
|
pub unsafe fn disable_memprotect_guard() {
|
||||||
|
@ -29,7 +20,12 @@ pub unsafe fn disable_memprotect_guard() {
|
||||||
PCSTR::from_raw(c"NtProtectVirtualMemory".to_bytes_with_nul().as_ptr()),
|
PCSTR::from_raw(c"NtProtectVirtualMemory".to_bytes_with_nul().as_ptr()),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let nt_query = GetProcAddress(ntdll, PCSTR::from_raw(c"NtQuerySection".to_bytes_with_nul().as_ptr())).unwrap();
|
|
||||||
|
let routine = if is_wine() {
|
||||||
|
GetProcAddress(ntdll, s!("NtPulseEvent")).unwrap()
|
||||||
|
} else {
|
||||||
|
GetProcAddress(ntdll, s!("NtQuerySection")).unwrap()
|
||||||
|
} as *mut u32;
|
||||||
|
|
||||||
let mut old_prot = PAGE_PROTECTION_FLAGS(0);
|
let mut old_prot = PAGE_PROTECTION_FLAGS(0);
|
||||||
VirtualProtect(
|
VirtualProtect(
|
||||||
|
@ -40,7 +36,6 @@ pub unsafe fn disable_memprotect_guard() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let routine = nt_query as *mut u32;
|
|
||||||
let routine_val = *(routine as *const usize);
|
let routine_val = *(routine as *const usize);
|
||||||
|
|
||||||
let lower_bits_mask = !(0xFFu64 << 32);
|
let lower_bits_mask = !(0xFFu64 << 32);
|
||||||
|
@ -61,3 +56,8 @@ pub unsafe fn disable_memprotect_guard() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn is_wine() -> bool {
|
||||||
|
let module = GetModuleHandleA(s!("ntdll.dll")).unwrap();
|
||||||
|
GetProcAddress(module, s!("wine_get_version")).is_some()
|
||||||
|
}
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
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