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}