3

I am trying to read the memory of another process (a dummy program in which a couple of variables are just initialized) using this wrapper over winapi. If I compile this program in debug(cargo build) mode, then the output is true, but everything changes if I compile with the --release(cargo build --release) flag

Sources without uses :

fn main() {
    const PID: u32 = 808;
    let decs;

    unsafe {
        decs = OpenProcess(PROCESS_ALL_ACCESS, false, PID).unwrap();
        let err = GetLastError();
        if err.0 != 0 {
            println!("{:?}", err);
        }
        
    }

    let mut my_int = 0;

    unsafe {
        let addr = 0xd79bdef564 as *const c_void;
        let mut success;

        success = VirtualProtectEx(
            decs,
            addr,
            4,
            PAGE_READWRITE,
            &mut 0 as *mut _ as *mut PAGE_PROTECTION_FLAGS,
        );
        if success.0 == 0 {
            let err = GetLastError();
            println!("{:?}", err);
        }

        let mut buff: i32 = 0;
        success = ReadProcessMemory(
            decs,
            addr,
            &mut my_int as *mut _ as *mut c_void,
            4,
            Some(&mut buff as *mut _ as *mut usize),
        );
        if success.0 == 0 {
            let err = GetLastError();
            println!("{:?}", err);
        }
    }

    println!("{}", my_int);
    unsafe {
        Sleep(2000);
    }
}

In debug mode, the correct output is 123457, but in release mode output is 0.

On the web, I came across information about incorrect behavior between debug and release, but there were either pointers to functions or operations with float, as it seems to me, this is not my case.

I tried to change the optimization mode during the release build in cargo.toml, if I set opt-level = 0, there will be no problem (but this is equivalent to debug), but if I set at least opt-level = 1, then the problem appears.

kik3r
  • 41
  • 4
  • 3
    `&mut 0 as *mut _ as *mut PAGE_PROTECTION_FLAGS` this looks wrong since you are passing a pointer to integer as a pointer to `PAGE_PROTECTION_FLAGS`. If you want to pass a null pointer, use `ptr::null_mut()` instead. – kmdreko Feb 24 '23 at 21:49
  • 1
    Its also strange you define `buff` to be a `i32`, when you swiftly use it like its a `usize`. You also don't check that `buff` is `4` after reading (which would indicate it read the full amount) – kmdreko Feb 24 '23 at 21:52
  • @kmdreko , yes, thank you very much for the answer and for the comment about the size check. The problem was just because of the invalid null pointer, ptr::null_mut() fixed it. Do you have any thoughts why my version worked correctly in debug mode? – kik3r Feb 24 '23 at 22:14
  • Undefined behavior is undefined. – cafce25 Feb 24 '23 at 23:21
  • 3
    @kik3r often UB can be masked in debug mode because a lot of optimisations haven't been applied. Release mode makes a lot of assumptions about your code and will aggressively rewrite it. Sometimes your UB will not surface even with release, but will appear when you update to a newer compiler version or compile for a different target arch. – Peter Hall Feb 24 '23 at 23:40

0 Answers0