Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate to patternsleuth image scanning
Browse files Browse the repository at this point in the history
trumank committed Nov 26, 2023
1 parent 1fecce1 commit 89c38cc
Showing 3 changed files with 153 additions and 70 deletions.
88 changes: 84 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions hook/Cargo.toml
Original file line number Diff line number Diff line change
@@ -9,15 +9,12 @@ crate-type = ["cdylib"]

[dependencies]
anyhow = "1.0.75"
patternsleuth_scanner = { git = "https://github.com/trumank/patternsleuth", version = "0.1.0" }
patternsleuth = { git = "https://github.com/trumank/patternsleuth", features = ["process-internal"] }
retour = { version = "0.3.1", features = ["static-detour"] }
windows = { version = "0.52.0", features = [
"Win32_Foundation",
"Win32_System_SystemServices",
"Win32_UI_WindowsAndMessaging",
"Win32_System_LibraryLoader",
"Win32_System_Memory",
"Win32_System_Threading",
"Win32_Security",
"Win32_System_ProcessStatus",
] }
130 changes: 68 additions & 62 deletions hook/src/lib.rs
Original file line number Diff line number Diff line change
@@ -4,15 +4,13 @@ use std::{
};

use anyhow::{bail, Context, Result};
use patternsleuth::{resolvers::resolve_self, scanner::Pattern, PatternConfig};
use retour::static_detour;
use windows::Win32::{
Foundation::HMODULE,
System::{
LibraryLoader::GetModuleHandleA,
Memory::{VirtualProtect, PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS},
ProcessStatus::{GetModuleInformation, MODULEINFO},
SystemServices::*,
Threading::GetCurrentProcess,
Threading::{GetCurrentThread, QueueUserAPC},
},
};
@@ -91,25 +89,7 @@ unsafe fn patch() -> Result<()> {

let installation_type = DRGInstallationType::from_exe_path()?;

let module = GetModuleHandleA(None).context("could not find main module")?;
let process = GetCurrentProcess();

let mut mod_info = MODULEINFO::default();
GetModuleInformation(
process,
module,
&mut mod_info as *mut _,
std::mem::size_of::<MODULEINFO>() as u32,
)?;

let module_addr = mod_info.lpBaseOfDll;

let memory = std::slice::from_raw_parts_mut(
mod_info.lpBaseOfDll as *mut u8,
mod_info.SizeOfImage as usize,
);

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[derive(Debug, PartialEq)]
enum Sig {
GetServerName,
Disable,
@@ -120,32 +100,55 @@ unsafe fn patch() -> Result<()> {
}

let patterns = [
(Sig::GetServerName, "48 89 5C 24 10 48 89 6C 24 18 48 89 74 24 20 57 41 56 41 57 48 83 EC 30 45 33 FF 4C 8B F2 48 8B D9 44 89 7C 24 50 41 8B FF"),
(Sig::Disable, "4C 8B B4 24 48 01 00 00 0F 84"),
(Sig::SaveGameToSlot, "48 89 5c 24 08 48 89 74 24 10 57 48 83 ec 40 48 8b da 33 f6 48 8d 54 24 30 48 89 74 24 30 48 89 74 24 38 41 8b f8"),
(Sig::LoadGameFromMemory, "40 55 48 8d ac 24 00 ff ff ff 48 81 ec 00 02 00 00 83 79 08 00"),
(Sig::LoadGameFromSlot, "48 8b c4 55 57 48 8d a8 d8 fe ff ff 48 81 ec 18 02 00 00"),
(Sig::DoesSaveGameExist, "48 89 5C 24 08 57 48 83 EC 20 8B FA 48 8B D9 E8 ?? ?? ?? ?? 48 8B C8 4C 8B 00 41 FF 50 40 48 8B C8 48 85 C0 74 38 83 7B 08 00 74 17 48 8B 00 44 8B C7 48 8B 13 48 8B 5C 24 30 48 83 C4 20 5F 48 FF 60 08 48 8B 00 48 8D ?? ?? ?? ?? ?? 44 8B C7 48 8B 5C 24 30 48 83 C4 20 5F 48 FF 60 08 48 8B 5C 24 30 48 83 C4 20 5F C3"),
].iter().map(|(name, pattern)| Ok((name, patternsleuth_scanner::Pattern::new(pattern)?))).collect::<Result<Vec<_>>>()?;
let pattern_refs = patterns
.iter()
.map(|(name, pattern)| (name, pattern))
.collect::<Vec<_>>();

let results = patternsleuth_scanner::scan_memchr_lookup(&pattern_refs, 0, memory);

let get_sig = |sig: Sig| {
results
.iter()
.find_map(|(s, addr)| (***s == sig).then_some(*addr))
};

if let Some(rva) = get_sig(Sig::GetServerName) {
let address = module_addr.add(rva);

Resize16 = Some(std::mem::transmute(address.add(53 + 4).offset(
i32::from_le_bytes(memory[rva + 53..rva + 53 + 4].try_into().unwrap()) as isize,
)));
PatternConfig::new(Sig::GetServerName,
"GetServerName".to_string(),
None,
Pattern::new("48 89 5C 24 10 48 89 6C 24 18 48 89 74 24 20 57 41 56 41 57 48 83 EC 30 45 33 FF 4C 8B F2 48 8B D9 44 89 7C 24 50 41 8B FF")?,
resolve_self,
),
PatternConfig::new(Sig::Disable,
"Disable".to_string(),
None,
Pattern::new("4C 8B B4 24 48 01 00 00 0F 84")?,
resolve_self,
),
PatternConfig::new(Sig::SaveGameToSlot,
"SaveGameToSlot".to_string(),
None,
Pattern::new("48 89 5c 24 08 48 89 74 24 10 57 48 83 ec 40 48 8b da 33 f6 48 8d 54 24 30 48 89 74 24 30 48 89 74 24 38 41 8b f8")?,
resolve_self,
),
PatternConfig::new(Sig::LoadGameFromMemory,
"LoadGameFromMemory".to_string(),
None,
Pattern::new("40 55 48 8d ac 24 00 ff ff ff 48 81 ec 00 02 00 00 83 79 08 00")?,
resolve_self,
),
PatternConfig::new(Sig::LoadGameFromSlot,
"LoadGameFromSlot".to_string(),
None,
Pattern::new("48 8b c4 55 57 48 8d a8 d8 fe ff ff 48 81 ec 18 02 00 00")?,
resolve_self,
),
PatternConfig::new(Sig::DoesSaveGameExist,
"DoesSaveGameExist".to_string(),
None,
Pattern::new("48 89 5C 24 08 57 48 83 EC 20 8B FA 48 8B D9 E8 ?? ?? ?? ?? 48 8B C8 4C 8B 00 41 FF 50 40 48 8B C8 48 85 C0 74 38 83 7B 08 00 74 17 48 8B 00 44 8B C7 48 8B 13 48 8B 5C 24 30 48 83 C4 20 5F 48 FF 60 08 48 8B 00 48 8D ?? ?? ?? ?? ?? 44 8B C7 48 8B 5C 24 30 48 83 C4 20 5F 48 FF 60 08 48 8B 5C 24 30 48 83 C4 20 5F C3")?,
resolve_self,
),
];

let scan = patternsleuth::process::internal::read_image()?.scan(&patterns)?;

if let Ok(address) = scan.get_unique_sig_address(Sig::GetServerName) {
let address = address as *const c_void;

let resize_rip = address.add(53);
Resize16 = Some(std::mem::transmute(
resize_rip
.add(4)
.offset((resize_rip as *const i32).read_unaligned() as isize),
));

let target: FnGetServerName = std::mem::transmute(address);
GetServerName
@@ -154,11 +157,11 @@ unsafe fn patch() -> Result<()> {
}

if matches!(installation_type, DRGInstallationType::Steam) {
if let Some(rva) = get_sig(Sig::Disable) {
if let Ok(address) = scan.get_unique_sig_address(Sig::Disable) {
let address = (address as *mut u8).add(29);
let patch = [0xB8, 0x01, 0x00, 0x00, 0x00];

let rva = rva + 29;
let patch_mem = &mut memory[rva..rva + 5];
let patch_mem = std::slice::from_raw_parts_mut(address, patch.len());

let mut old: PAGE_PROTECTION_FLAGS = Default::default();
VirtualProtect(
@@ -191,25 +194,28 @@ unsafe fn patch() -> Result<()> {
.join("SaveGames"),
);

if let Some(rva) = get_sig(Sig::SaveGameToSlot) {
let address = module_addr.add(rva);
if let Ok(address) = scan.get_unique_sig_address(Sig::SaveGameToSlot) {
let address = address as *const c_void;

SaveGameToMemory = Some(std::mem::transmute(address.add(39 + 4).offset(
i32::from_le_bytes(memory[rva + 39..rva + 39 + 4].try_into().unwrap()) as isize,
)));
let save_rip = address.add(39);
SaveGameToMemory = Some(std::mem::transmute(
save_rip
.add(4)
.offset((save_rip as *const i32).read_unaligned() as isize),
));

let target: FnSaveGameToSlot = std::mem::transmute(address);
SaveGameToSlot
.initialize(target, save_game_to_slot_detour)?
.enable()?;
}

if let Some(rva) = get_sig(Sig::LoadGameFromMemory) {
let address = module_addr.add(rva);
if let Ok(address) = scan.get_unique_sig_address(Sig::LoadGameFromMemory) {
let address = address as *const c_void;
LoadGameFromMemory = Some(std::mem::transmute(address));

if let Some(rva) = get_sig(Sig::LoadGameFromSlot) {
let address = module_addr.add(rva);
if let Ok(address) = scan.get_unique_sig_address(Sig::LoadGameFromSlot) {
let address = address as *const c_void;

let target: FnLoadGameFromSlot = std::mem::transmute(address);
LoadGameFromSlot
@@ -218,8 +224,8 @@ unsafe fn patch() -> Result<()> {
}
}

if let Some(rva) = get_sig(Sig::DoesSaveGameExist) {
let address = module_addr.add(rva);
if let Ok(address) = scan.get_unique_sig_address(Sig::DoesSaveGameExist) {
let address = address as *const c_void;

let target: FnDoesSaveGameExist = std::mem::transmute(address);
DoesSaveGameExist

0 comments on commit 89c38cc

Please sign in to comment.