#debugging #reverse-engineering #macos #linux-macos #linux #windows

vmemory

在不考虑内存页面保护的情况下,为 Windows 和基于 Unix 的系统读取和写入其他进程的内存

8 个版本

0.1.8 2021 年 12 月 8 日
0.1.7 2021 年 12 月 7 日
0.1.0 2021 年 11 月 22 日

#358 in Unix APIs

29 每月下载量

MIT 许可证

43KB
707 代码行数(不包括注释)

vmemory

Rust 库,用于读取/写入 Windows、macOS、Linux 和未来可能支持的 BSD 变体的其他进程的内存。这将在不考虑内存页面保护的情况下写入内存。

API

ProcessMemory::new_process(file_path: &str, arguments: &Vec<String>) -> Option<ProcessMemory>

在挂起状态下启动一个新的进程,通过 self.resume() 手动恢复,传递要启动的进程的文件路径和启动进程的参数。返回一个包含要解包的结构体的选项

ProcessMemory::attach_process(pid: u32) -> Option<ProcessMemory>

使用进程 ID (PID) 连接到进程。返回一个选项结构体,可以解包,这将允许内存读写操作

ProcessMemory::write_memory(&self, _address: usize, data: &Vec<u8>, offset: bool)

向进程写入内存。要写入的内存是位于远程进程中的 _address 位置的 data 参数中的内存。offset 布尔值将指定 _address 的值是否是相对于进程加载的第一个模块/映射的偏移量(true),或者是否是要写入的直接地址值(false)

例如,第一个模块加载在 0x00400000

offset 设置为 true,且 _address = 5

内存将写入 0x00400005

ProcessMemory::read_memory(&self, _address: usize, size: usize, offset: bool) -> Vec<u8>

_address 的位置读取进程的内存,并按 size 读取 n 字节。offset 参数的规则与在 ProcessMemory::write_memory() 中指定的相同

ProcessMemory::resume(&self)

从挂起状态恢复进程(Linux/macOS 上的 SIGCONT。Windows 上的 CreateProcess 的第一个线程上的 ResumeThread)。这通常只在 Linux 上的 ptrace(2) 会话、macOS 上从挂起状态调用 posix_spawn(2) 或 Windows 上的 CreateProcess 时使用。基本上,所有 ProcessMemory::new_process() 调用都需要调用此函数

ProcessMemory::base(&self)

检索进程加载的第一个映射/模块的基本地址

示例

示例 1

使用 new_process

use vmemory::*;

fn main() {
    //
    // Spawn a new process in a suspended state with no arguments
    //
    let test = ProcessMemory::new_process(r"C:\TEST.EXE", &vec!["".to_string()]).unwrap();

    //
    // Write memory to the process at (base address + 0xA)
    // Writing 4 bytes at this location, each byte = 9
    //
    test.write_memory(0xA, &vec![9, 9, 9, 9], true);

    //
    // Read memory to confirm the write was registered to the process, as well as a few additional bytes that
    // were not written
    //
    let vmem = test.read_memory(0xA, 10, true);

    for v in vmem {
        print!("{:02X} ", v);
    }

    //
    // Get the base address of the first module in the process, and print it out
    //
    println!("\nbase: {:08X}", test.base());

    //
    // Resume the process
    //
    test.resume();
}

示例 2

在这里我们使用 attach_process 而不是 new_process

注意这个例子中的 offset 布尔值(write_memoryread_memory 的第三个参数)。在这里,传递给 write_memory 的直接地址和传递给 read_memory 的偏移量指向进程内存中的同一位置。

use vmemory::*;

fn main() {

    //
    // Attach to a process with a process ID (PID) of 3145
    // Immediately resume from the ptrace attachment
    //
    let mut test = ProcessMemory::attach_process(3145).unwrap();
    test.resume();

    //
    // Write 5 bytes at the direct address (no offset) 0x5616B07DB000
    //
    let write_test: Vec<u8> = vec![7, 7, 9, 9, 9];
    test.write_memory(0x5616B07DB000, &write_test, false);

    //
    // Read 5 bytes from the offset (0) relative to the base address of the first mapping/module in the process
    //
    let vmem = test.read_memory(0, 5, true);

    for v in &vmem {
        print!("{:02X} ", v);
    }

    //
    // Print out the base address of the process
    //
    println!("\nbase: {:08X}", test.base());
}

依赖项

~2MB
~42K SLoC