memory-rs 0.2.6

Library for game hacking in Windows.
Documentation
#![allow(non_upper_case_globals)]
use memory_rs::internal::injections::*;
use memory_rs::internal::memory::*;
use memory_rs::internal::memory_region::*;
use memory_rs::internal::process_info::ProcessInfo;

static TO_BE_WRITTEN: [u8; 8] = [0xDE, 0xAD, 0xBE, 0xEF, 0xC0, 0xFF, 0xEE, 0x00];
static SEARCH_ARRAY: [u8; 10] = [0xDE, 0xAD, 0xBE, 0xEF, 0xC0, 0xFF, 0xEE, 0xC0, 0xCA, 0xDA];

#[test]
fn test_write_aob() {
    let new_array = vec![0xAA, 0xBB, 0xCC];
    let pointer = TO_BE_WRITTEN.as_ptr() as *const u8 as usize;

    unsafe { write_aob(pointer, &new_array).unwrap() };

    let result_array: [u8; 8] = [0xAA, 0xBB, 0xCC, 0xEF, 0xC0, 0xFF, 0xEE, 0x00];

    let equality = TO_BE_WRITTEN.iter().eq(result_array.iter());

    assert!(
        equality,
        "Left: {:x?}, Right: {:x?}",
        &TO_BE_WRITTEN[..],
        &result_array[..]
    );
}

#[test]
fn test_generate_aob_pattern() {
    let mp = memory_rs::generate_aob_pattern![0xAA, _, 0xBB, _];
    let arr = [0xAA, 0xBB, 0xBB, 0xEE];

    assert_eq!(mp.size, 4);
    assert!(mp.scan(&arr));
}

#[test]
fn test_scan_aob() {
    let p = &SEARCH_ARRAY as *const u8 as usize;
    let arr_len = SEARCH_ARRAY.len();
    let mp = memory_rs::generate_aob_pattern![0xFF, _, 0xC0];
    let reg = MemoryRegion::new(p, arr_len, true).unwrap();

    let addr = reg.scan_aob(&mp).unwrap();

    assert_eq!(Some(p + 5), addr);
}

#[test]
fn test_scan_aob_all_matches() {
    let p: [u8; 10] = [0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xFF, 0xCC, 0xAA, 0xEE, 0xCC];
    let arr_len = p.len();
    let mp = memory_rs::generate_aob_pattern![0xAA, _, 0xCC];
    let reg = MemoryRegion::new(p.as_ptr() as usize, arr_len, true).unwrap();

    let addr = reg.scan_aob_all_matches(&mp).unwrap();

    // Recreate the original array since the pattern repeats every 3 bytes.
    let mut v = vec![];
    for a in addr {
        let a_ = unsafe { std::slice::from_raw_parts(a as *const u8, 3) };
        v.extend_from_slice(a_);
    }

    assert_eq!(
        &[0xAA, 0xBB, 0xCC, 0xAA, 0xFF, 0xCC, 0xAA, 0xEE, 0xCC],
        &v[..]
    );
}

#[test]
fn test_scan_aob_all_matches_aligned() {
    let p: [u8; 12] = [
        0xAA, 0xBB, 0xCC, 0xDD, 0xAA, 0xFF, 0xCC, 0x00, 0xAA, 0xEE, 0xCC, 0x00,
    ];
    let arr_len = p.len();
    let mp = memory_rs::generate_aob_pattern![0xAA, _, 0xCC];
    let region = MemoryRegion::new(&p as *const u8 as _, arr_len, true).unwrap();

    let addr = region.scan_aob_all_matches_aligned(&mp, None).unwrap();

    let ptr = &p as *const u8 as usize;
    let results = [ptr, ptr + 4, ptr + 8];

    assert_eq!(&addr, &results);
}

#[test]
fn test_scan_aob_not_valid_memory() {
    use memory_rs::error;

    let p = 0x12345678;
    let len = 0xFFFF;
    let _mp = memory_rs::generate_aob_pattern![0xAA, 0xBB, 0xCC, 0xDD];
    let reg = MemoryRegion::new(p, len, false);

    if let Err(e) = reg {
        let e: error::Error = e.downcast().unwrap();
        assert_eq!(e.kind(), error::ErrorType::Internal);
        assert_eq!(e.msg(), "The region to scan is invalid".to_string());
    } else {
        panic!("Should have get an error");
    }
}

#[test]
fn test_scan_aob_out_of_bounds() {
    use memory_rs::error;

    let p = &SEARCH_ARRAY as *const u8 as usize;
    let len = 0xFFFFF;
    let _mp = memory_rs::generate_aob_pattern![0xAA, 0xBB, 0xCC, 0xDD];
    let reg = MemoryRegion::new(p, len, false);

    if let Err(e) = reg {
        let e: error::Error = e.downcast().unwrap();
        assert_eq!(e.kind(), error::ErrorType::Internal);
        assert_eq!(e.msg(), "The region to scan is invalid".to_string());
    } else {
        panic!("Should have get an error");
    }
}

fn dummy_function() -> &'static str {
    println!("I'm `dummy_function`");

    return "I'm the original function";
}

fn injected_function() -> &'static str {
    println!("I'm `injected_function`");
    return "I'm an imposter!";
}

#[test]
fn test_injection() {
    let original_function = dummy_function as *mut u8 as usize;
    let new_function = injected_function as *mut u8 as usize;

    let res = dummy_function();

    assert_eq!("I'm the original function", res);

    let mut det = Detour::new(original_function, 14, new_function, None);
    det.inject();

    let res = dummy_function();

    assert_eq!(res, "I'm an imposter!");

    det.remove_injection();

    let res = dummy_function();

    assert_eq!(res, "I'm the original function");
}

#[test]
fn test_drop_injection() {
    static arr: [u8; 5] = [0xE7, 0x9A, 0x00, 0x9A, 0x9B];

    {
        let mut injection = Injection::new(arr.as_ptr() as usize + 1, vec![0xAA, 0xBB, 0xCC]);

        assert_eq!(&arr, &[0xE7, 0x9A, 0x00, 0x9A, 0x9B]);

        injection.inject();

        assert_eq!(&arr, &[0xE7, 0xAA, 0xBB, 0xCC, 0x9B]);
    }

    assert_eq!(&arr, &[0xE7, 0x9A, 0x00, 0x9A, 0x9B]);
}

#[test]
fn test_scan_aligned_value() {
    let vals: [u32; 4] = [0xC0FFEE, 0x1337, 0xB00BA, 0xC0FFEE];
    let reg = MemoryRegion::new(vals.as_ptr() as *const u32 as usize, 16, true).unwrap();

    let result = reg.scan_aligned_value(0xC0FFEE_u32).unwrap();

    assert_eq!(
        &result,
        &[
            (&vals[0]) as *const u32 as usize,
            (&vals[3]) as *const u32 as usize
        ]
    );
}

#[test]
fn test_hashmap() {
    use std::collections::HashMap;
    static arr: [u8; 4] = [0xAA, 0xBB, 0xCC, 0xDD];

    let mut hash = HashMap::new();
    hash.insert(
        "first_index",
        Injection::new(arr.as_ptr() as usize, vec![0xFF]),
    );

    unsafe {
        hash.insert(
            "second_index",
            Injection::new(arr.as_ptr().offset(1) as usize, vec![0xFA]),
        );
    }
    hash.values_mut().for_each(|x| x.inject());

    assert_eq!(&arr[..2], &[0xFF, 0xFA]);

    hash.get_mut("first_index").unwrap().remove_injection();

    assert_eq!(&arr[..2], &[0xAA, 0xFA]);
}

#[test]
fn test_slice() {
    static arr: [u8; 4] = [0xAA, 0xBB, 0xCC, 0xDD];

    let mut injections = [
        Injection::new(arr.as_ptr() as _, vec![32]),
        Injection::new(unsafe { arr.as_ptr().offset(1) as _ }, vec![42]),
    ];

    injections.iter_mut().inject();

    assert_eq!(arr, [32_u8, 42, 0xCC, 0xDD]);
}

#[test]
fn test_vector() {
    static arr: [u8; 4] = [0xAA, 0xBB, 0xCC, 0xDD];

    let mut injections = vec![
        Injection::new(arr.as_ptr() as _, vec![32]),
        Injection::new(unsafe { arr.as_ptr().offset(1) as _ }, vec![42]),
    ];

    injections.iter_mut().inject();

    assert_eq!(arr, [32_u8, 42, 0xCC, 0xDD]);
}

fn test_dyn_vec_original() -> &'static str {
    println!("I'm original function");
    "original"
}

fn test_dyn_vec_injected() -> &'static str {
    println!("I'm injected function");
    "injected"
}

#[test]
fn test_dyn_vec() {
    let original_function = test_dyn_vec_original as *mut u8 as usize;
    let new_function = test_dyn_vec_injected as *mut u8 as usize;

    static arr: [u8; 4] = [0xAA, 0xBB, 0xCC, 0xDD];

    let mut v: Vec<Box<dyn Inject>> = vec![
        Box::new(Injection::new(arr.as_ptr() as _, vec![32])),
        Box::new(Detour::new(original_function, 14, new_function, None)),
    ];

    assert_eq!(test_dyn_vec_original(), "original");

    v.iter_mut().inject();

    assert_eq!(test_dyn_vec_original(), "injected");

    v.iter_mut().remove_injection();
}

#[test]
fn test_resolve_module_path() {
    let name = unsafe { resolve_module_path(std::ptr::null_mut()).unwrap() };
    assert_eq!(name.file_stem().unwrap(), "deps");
}

#[test]
fn test_proc_inf() {
    let _ = ProcessInfo::new(Some("Kernel32.dll")).unwrap();
}