fromsoftware_shared/arxan.rs
1/// guardIT code restoration neuter utils.
2///
3/// This is my rust take on a cpp version made by tremwil. Yui noticed the original pattern to this.
4use std::error::Error;
5
6use pelite::pattern::Atom;
7use pelite::pe64::Pe;
8
9use crate::program::Program;
10
11const CODE_RESTORATION_PATTERN: &[Atom] =
12 pelite::pattern!("B9 ? ? ? ? E8 ? ? ? ? F3 0F 11 05 ? ? ? ? [0-128] ' 72 ? 48 8D ? ? ? ? ?");
13
14/// Returns the RVAs of the arxan code restoration routines.
15/// This is useful for hooking the memory image of the game.
16///
17/// You probably need to change the protection of the memory page to PAGE_EXECUTE_READWRITE
18/// because there is no guarantee that arxan will change it before this function is called.
19pub fn get_arxan_code_restoration_rvas(program: &Program) -> Vec<u32> {
20 let mut result = Vec::new();
21 let mut matches = program.scanner().matches_code(CODE_RESTORATION_PATTERN);
22 let mut captures: [u32; 2] = [0; 2];
23
24 while matches.next(&mut captures) {
25 result.push(captures[1]);
26 }
27
28 result
29}
30
31/// Disables the arxan code restoration routine at the given RVA.
32///
33/// # Safety
34/// Caller must ensure that:
35/// - Specified program/module has not unloaded.
36/// - The RVA is a valid conditional jump like we see with arxans code restoration routines.
37/// - The RVA points to writeable memory (ala VirtualProtect).
38/// - Nothing else is writing to the memory at specified RVA.
39pub unsafe fn disable_code_restoration_at(
40 program: &Program,
41 rva: u32,
42) -> Result<(), Box<dyn Error>> {
43 let jb_ptr = program.rva_to_va(rva)? as *mut u8;
44
45 unsafe {
46 std::ptr::write(jb_ptr, 0xEB);
47 }
48
49 Ok(())
50}
51
52/// Disables most instances of the arxan code restoration routines.
53///
54/// Avoid using this unless you absolutely have to hook the games memory image and you are
55/// absolutely certain the game is removing your hooks. Prefer using the task runtime over hooking
56/// the memory image where ever you can.
57///
58/// # Safety
59/// Caller must ensure that:
60/// - Specified program/module has not unloaded.
61/// - The memory image is writeable.
62/// - The code restoration checks are not mutated during runtime.
63pub unsafe fn disable_code_restoration(program: &Program) -> Result<(), Box<dyn Error>> {
64 let rvas = get_arxan_code_restoration_rvas(program);
65 for rva in rvas {
66 unsafe {
67 disable_code_restoration_at(program, rva)?;
68 }
69 }
70 Ok(())
71}