首页
社区
课程
招聘
[原创] Rust如何实现跨进程的内存浏览器
发表于: 2025-5-17 10:28 2092

[原创] Rust如何实现跨进程的内存浏览器

2025-5-17 10:28
2092

关键点

技术细节

注意事项

技术细节

关键字段

实际开发中需要特别注意:

可以通过添加更多中间抽象层(如统一的内存保护标志、跨平台的地址类型封装)来增强代码的可维护性。同时建议结合 libccrate 处理底层系统调用,使用 bitflags处理复杂的标志位组合。

以下针对实际开发中需要特别注意的问题和解决方案,通过代码案例进行补充说明:

问题:频繁解析 /proc/pid/maps 或调用 VirtualQueryEx 会产生性能瓶颈

优化点

问题:不同平台返回的错误类型需要统一处理

优势

问题:需要动态计算模块基址偏移

关键点

问题:统一不同平台的内存权限操作

使用示例

问题:在64位系统中调试32位进程

问题:暴力扫描内存效率低下

基于 Boyer-Moore 算法优化

问题:防止非法内存访问导致进程崩溃

生命周期管理

信号处理(Unix)

性能监控

结构化输出

这些补充内容覆盖了实际开发中需要处理的深层次问题,包括性能优化、错误处理、安全增强和测试策略等关键方面。实际开发时建议:

// 使用 trait 进行平台抽象
pub trait ProcessHandle {
    fn read_memory(&self, address: usize, buffer: &mut [u8]) -> Result<()>;
    // 其他方法...
}
 
// 运行时动态分派
pub struct Process {
    handle: Box<dyn ProcessHandle>, // 动态分发实现
}
// 使用 trait 进行平台抽象
pub trait ProcessHandle {
    fn read_memory(&self, address: usize, buffer: &mut [u8]) -> Result<()>;
    // 其他方法...
}
 
// 运行时动态分派
pub struct Process {
    handle: Box<dyn ProcessHandle>, // 动态分发实现
}
// windows.rs
use windows::Win32::System::Threading::OpenProcess;
 
impl WindowsProcess {
    pub fn open(pid: u32) -> Result<Self> {
        unsafe {
            let handle = OpenProcess(
                PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION,
                false, // 不继承句柄
                pid,
            )?;
            Ok(Self { handle })
        }
    }
}
// windows.rs
use windows::Win32::System::Threading::OpenProcess;
 
impl WindowsProcess {
    pub fn open(pid: u32) -> Result<Self> {
        unsafe {
            let handle = OpenProcess(
                PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION,
                false, // 不继承句柄
                pid,
            )?;
            Ok(Self { handle })
        }
    }
}
unsafe fn read_memory(&self, address: usize, buffer: &mut [u8]) -> Result<()> {
    let mut bytes_read = 0;
    let success = ReadProcessMemory(
        self.handle,
        address as *const _,
        buffer.as_mut_ptr() as *mut _,
        buffer.len(),
        &mut bytes_read,
    );
 
    if success.as_bool() && bytes_read == buffer.len() {
        Ok(())
    } else {
        Err(anyhow!("Failed to read memory. Error: {}", GetLastError()))
    }
}
unsafe fn read_memory(&self, address: usize, buffer: &mut [u8]) -> Result<()> {
    let mut bytes_read = 0;
    let success = ReadProcessMemory(
        self.handle,
        address as *const _,
        buffer.as_mut_ptr() as *mut _,
        buffer.len(),
        &mut bytes_read,
    );
 
    if success.as_bool() && bytes_read == buffer.len() {
        Ok(())
    } else {
        Err(anyhow!("Failed to read memory. Error: {}", GetLastError()))
    }
}
// unix.rs
impl UnixProcess {
    fn read_memory(&self, address: usize, buffer: &mut [u8]) -> Result<()> {
        let path = format!("/proc/{}/mem", self.pid);
        let file = File::open(path)?;
 
        // 使用 pread 原子操作
        file.read_at(buffer, address as u64)?;
        Ok(())
    }
}
// unix.rs
impl UnixProcess {
    fn read_memory(&self, address: usize, buffer: &mut [u8]) -> Result<()> {
        let path = format!("/proc/{}/mem", self.pid);
        let file = File::open(path)?;
 
        // 使用 pread 原子操作
        file.read_at(buffer, address as u64)?;
        Ok(())
    }
}
fn parse_maps(pid: i32) -> Result<Vec<MemoryRegion>> {
    let maps = fs::read_to_string(format!("/proc/{}/maps", pid))?;
 
    maps.lines().filter_map(|line| {
        let parts: Vec<&str> = line.splitn(6, ' ').collect();
        let (addr, perms) = (parts[0], parts[1]);
 
        let addrs: Vec<&str> = addr.split('-').collect();
        let start = usize::from_str_radix(addrs[0], 16).ok()?;
        let end = usize::from_str_radix(addrs[1], 16).ok()?;
 
        Some(MemoryRegion {
            start,
            end,
            permissions: perms.to_string(),
            path: parts.get(5).unwrap_or(&"").to_string(),
        })
    }).collect()
}
fn parse_maps(pid: i32) -> Result<Vec<MemoryRegion>> {
    let maps = fs::read_to_string(format!("/proc/{}/maps", pid))?;
 
    maps.lines().filter_map(|line| {
        let parts: Vec<&str> = line.splitn(6, ' ').collect();
        let (addr, perms) = (parts[0], parts[1]);
 
        let addrs: Vec<&str> = addr.split('-').collect();
        let start = usize::from_str_radix(addrs[0], 16).ok()?;
        let end = usize::from_str_radix(addrs[1], 16).ok()?;
 
        Some(MemoryRegion {
            start,
            end,
            permissions: perms.to_string(),
            path: parts.get(5).unwrap_or(&"").to_string(),
        })
    }).collect()
}
// 通用对齐检查
fn is_page_aligned(addr: usize) -> bool {
    let page_size = page_size::get();
    addr % page_size == 0
}
 
// 统一处理函数
pub fn safe_read(process: &dyn ProcessHandle, addr: usize, buf: &mut [u8]) -> Result<()> {
    if !is_page_aligned(addr) || !is_page_aligned(addr + buf.len()) {
        return Err(anyhow!("Unaligned memory access"));
    }
    process.read_memory(addr, buf)
}
// 通用对齐检查
fn is_page_aligned(addr: usize) -> bool {
    let page_size = page_size::get();
    addr % page_size == 0
}
 
// 统一处理函数
pub fn safe_read(process: &dyn ProcessHandle, addr: usize, buf: &mut [u8]) -> Result<()> {
    if !is_page_aligned(addr) || !is_page_aligned(addr + buf.len()) {
        return Err(anyhow!("Unaligned memory access"));
    }
    process.read_memory(addr, buf)
}
// 统一权限表示
#[derive(Debug, Clone, Copy)]
pub enum MemoryProtection {
    Read,
    Write,
    Execute,
    // ...
}
 
// 转换为平台特定值
impl Into<windows::Win32::System::Memory::PAGE_PROTECTION_FLAGS> for MemoryProtection {
    fn into(self) -> PAGE_PROTECTION_FLAGS {
        match self {
            Self::Read => PAGE_READONLY,
            // ...
        }
    }
}
// 统一权限表示
#[derive(Debug, Clone, Copy)]
pub enum MemoryProtection {
    Read,
    Write,
    Execute,
    // ...
}
 
// 转换为平台特定值
impl Into<windows::Win32::System::Memory::PAGE_PROTECTION_FLAGS> for MemoryProtection {
    fn into(self) -> PAGE_PROTECTION_FLAGS {
        match self {
            Self::Read => PAGE_READONLY,
            // ...
        }
    }
}
impl Process {
    pub fn pattern_scan(&self, pattern: &[Option<u8>]) -> Result<Vec<usize>> {
        let regions = self.get_memory_regions()?;
        let mut results = Vec::new();
 
        for region in regions {
            if !region.is_readable() { continue; }
 
            let mut buffer = vec![0; region.size()];
            self.read_memory(region.start, &mut buffer)?;
 
            for (offset, window) in buffer.windows(pattern.len()).enumerate() {
                if pattern.iter().enumerate().all(|(i, &expected)| {
                    expected.map(|b| b == window[i]).unwrap_or(true)
                }) {
                    results.push(region.start + offset);
                }
            }
        }
 
        Ok(results)
    }
}
impl Process {
    pub fn pattern_scan(&self, pattern: &[Option<u8>]) -> Result<Vec<usize>> {
        let regions = self.get_memory_regions()?;
        let mut results = Vec::new();
 
        for region in regions {
            if !region.is_readable() { continue; }
 
            let mut buffer = vec![0; region.size()];
            self.read_memory(region.start, &mut buffer)?;
 
            for (offset, window) in buffer.windows(pattern.len()).enumerate() {
                if pattern.iter().enumerate().all(|(i, &expected)| {
                    expected.map(|b| b == window[i]).unwrap_or(true)
                }) {
                    results.push(region.start + offset);
                }
            }
        }
 
        Ok(results)
    }
}
// Windows 实现
fn monitor_memory_writes(process: &WindowsProcess) -> Result<()> {
    unsafe {
        let old_protect = std::mem::zeroed();
        VirtualProtectEx(
            process.handle,
            address as _,
            size,
            PAGE_GUARD, // 设置内存保护
            &mut old_protect,
        )?;
    }
    // 通过异常处理捕获写入事件
}
 
// Linux 实现
fn monitor_memory_writes(pid: Pid) -> Result<()> {
    let regs = ptrace::getregs(pid)?;
    ptrace::setregs(pid, regs)?; // 设置断点
    // 使用 SIGTRAP 处理写入事件
}
// Windows 实现
fn monitor_memory_writes(process: &WindowsProcess) -> Result<()> {
    unsafe {
        let old_protect = std::mem::zeroed();
        VirtualProtectEx(
            process.handle,
            address as _,
            size,
            PAGE_GUARD, // 设置内存保护
            &mut old_protect,
        )?;
    }
    // 通过异常处理捕获写入事件
}
 
// Linux 实现
fn monitor_memory_writes(pid: Pid) -> Result<()> {
    let regs = ptrace::getregs(pid)?;
    ptrace::setregs(pid, regs)?; // 设置断点
    // 使用 SIGTRAP 处理写入事件
}
// 统一错误处理
match process.read_memory(addr, &mut buf) {
    Err(e) if e.kind() == ErrorKind::PermissionDenied => {
        eprintln!("需要管理员权限运行!");
    }
    // ...
}
// 统一错误处理
match process.read_memory(addr, &mut buf) {
    Err(e) if e.kind() == ErrorKind::PermissionDenied => {
        eprintln!("需要管理员权限运行!");
    }
    // ...
}
// 处理 32/64 位差异
#[cfg(target_pointer_width = "32")]
type AddressType = u32;
 
#[cfg(target_pointer_width = "64")]
type AddressType = u64;
// 处理 32/64 位差异
#[cfg(target_pointer_width = "32")]
type AddressType = u32;
 
#[cfg(target_pointer_width = "64")]
type AddressType = u64;
// 批量读取优化
const CHUNK_SIZE: usize = 4096 * 1024; // 4MB
 
fn read_large_memory(process: &dyn ProcessHandle, addr: usize, size: usize) -> Result<Vec<u8>> {
    let mut buffer = Vec::with_capacity(size);
    unsafe { buffer.set_len(size); }
 
    for chunk in buffer.chunks_mut(CHUNK_SIZE) {
        process.read_memory(addr + offset, chunk)?;
    }
 
    Ok(buffer)
}
// 批量读取优化
const CHUNK_SIZE: usize = 4096 * 1024; // 4MB
 
fn read_large_memory(process: &dyn ProcessHandle, addr: usize, size: usize) -> Result<Vec<u8>> {
    let mut buffer = Vec::with_capacity(size);
    unsafe { buffer.set_len(size); }
 
    for chunk in buffer.chunks_mut(CHUNK_SIZE) {
        process.read_memory(addr + offset, chunk)?;
    }
 
    Ok(buffer)
}
#[cfg(test)]
mod tests {
    #[test]
    #[cfg(target_os = "linux")]
    fn test_linux_memory_read() {
        // 测试当前进程的内存读取
    }
 
    #[test]
    #[cfg(windows)]
    fn test_windows_handle_acquisition() {
        // 测试进程打开权限
    }
}
#[cfg(test)]
mod tests {
    #[test]
    #[cfg(target_os = "linux")]
    fn test_linux_memory_read() {
        // 测试当前进程的内存读取
    }
 
    #[test]
    #[cfg(windows)]
    fn test_windows_handle_acquisition() {
        // 测试进程打开权限
    }
}
// 启动测试进程
fn spawn_test_process() -> (u32, JoinHandle<()>) {
    let handle = thread::spawn(|| {
        let data = vec![0xAAu8; 1024];
        loop { thread::park(); } // 保持进程存活
    });
    (thread::current().id(), handle)
}
// 启动测试进程
fn spawn_test_process() -> (u32, JoinHandle<()>) {
    let handle = thread::spawn(|| {
        let data = vec![0xAAu8; 1024];
        loop { thread::park(); } // 保持进程存活
    });
    (thread::current().id(), handle)
}
// process.rs
use std::time::{Duration, Instant};
 
pub struct Process {
    pid: u32,
    handle: Box<dyn ProcessHandle>,
    regions_cache: Option<(Vec<MemoryRegion>, Instant)>,
}
 
impl Process {
    const CACHE_TTL: Duration = Duration::from_secs(5);
 
    pub fn get_memory_regions_cached(&mut self) -> Result<&Vec<MemoryRegion>> {
        if let Some((regions, timestamp)) = &self.regions_cache {
            if timestamp.elapsed() < Self::CACHE_TTL {
                return Ok(regions);
            }
        }
         
        let new_regions = self.handle.get_memory_regions()?;
        self.regions_cache = Some((new_regions, Instant::now()));
        Ok(&self.regions_cache.as_ref().unwrap().0)
    }
}
// process.rs
use std::time::{Duration, Instant};
 
pub struct Process {
    pid: u32,
    handle: Box<dyn ProcessHandle>,
    regions_cache: Option<(Vec<MemoryRegion>, Instant)>,
}
 
impl Process {
    const CACHE_TTL: Duration = Duration::from_secs(5);
 
    pub fn get_memory_regions_cached(&mut self) -> Result<&Vec<MemoryRegion>> {
        if let Some((regions, timestamp)) = &self.regions_cache {
            if timestamp.elapsed() < Self::CACHE_TTL {
                return Ok(regions);
            }
        }
         
        let new_regions = self.handle.get_memory_regions()?;
        self.regions_cache = Some((new_regions, Instant::now()));
        Ok(&self.regions_cache.as_ref().unwrap().0)
    }
}
// error.rs
#[derive(thiserror::Error, Debug)]
pub enum MemoryError {
    #[error("Permission denied: {0}")]
    PermissionDenied(String),
     
    #[error("Invalid address: 0x{0:x}")]
    InvalidAddress(usize),
     
    #[error("Partial read: {0} bytes")]
    PartialRead(usize),
     
    #[error("Platform error: {0}")]
    Platform(#[from] PlatformError),
}
 
// windows.rs
impl From<windows::core::Error> for MemoryError {
    fn from(e: windows::core::Error) -> Self {
        match e.code().0 as u32 {
            windows::Win32::Foundation::ERROR_PARTIAL_COPY =>
                Self::PartialRead(0),
            windows::Win32::Foundation::ERROR_ACCESS_DENIED =>
                Self::PermissionDenied("PROCESS_VM_READ required".into()),
            _ => Self::Platform(PlatformError::Windows(e))
        }
    }
}
 
// unix.rs
impl From<nix::Error> for MemoryError {
    fn from(e: nix::Error) -> Self {
        match e {
            nix::Error::EPERM => Self::PermissionDenied("ptrace access required".into()),
            nix::Error::EIO => Self::InvalidAddress(0),
            _ => Self::Platform(PlatformError::Unix(e))
        }
    }
}
// error.rs
#[derive(thiserror::Error, Debug)]
pub enum MemoryError {
    #[error("Permission denied: {0}")]
    PermissionDenied(String),
     
    #[error("Invalid address: 0x{0:x}")]
    InvalidAddress(usize),
     
    #[error("Partial read: {0} bytes")]
    PartialRead(usize),
     
    #[error("Platform error: {0}")]
    Platform(#[from] PlatformError),
}
 
// windows.rs
impl From<windows::core::Error> for MemoryError {
    fn from(e: windows::core::Error) -> Self {
        match e.code().0 as u32 {
            windows::Win32::Foundation::ERROR_PARTIAL_COPY =>
                Self::PartialRead(0),
            windows::Win32::Foundation::ERROR_ACCESS_DENIED =>
                Self::PermissionDenied("PROCESS_VM_READ required".into()),
            _ => Self::Platform(PlatformError::Windows(e))
        }
    }
}
 
// unix.rs
impl From<nix::Error> for MemoryError {
    fn from(e: nix::Error) -> Self {
        match e {
            nix::Error::EPERM => Self::PermissionDenied("ptrace access required".into()),
            nix::Error::EIO => Self::InvalidAddress(0),
            _ => Self::Platform(PlatformError::Unix(e))
        }
    }
}
// module.rs
pub struct ModuleInfo {
    pub base_address: usize,
    pub size: usize,
    pub name: String,
}
 
impl Process {
    pub fn find_module(&self, name: &str) -> Result<ModuleInfo> {
        let regions = self.get_memory_regions()?;
         
        regions.iter()
            .filter(|r| !r.path.is_empty())
            .find(|r| r.path.ends_with(name))
            .map(|r| ModuleInfo {
                base_address: r.start,
                size: r.end - r.start,
                name: r.path.clone(),
            })
            .ok_or_else(|| anyhow!("Module not found"))
    }
 
    pub fn rebase_address(&self, offset: usize, module_name: &str) -> Result<usize> {
        let module = self.find_module(module_name)?;
        Ok(module.base_address + offset)
    }
}
 
// 使用示例:
let process = Process::open(pid)?;
let real_address = process.rebase_address(0x1234, "target.dll")?;
// module.rs
pub struct ModuleInfo {
    pub base_address: usize,
    pub size: usize,
    pub name: String,
}
 
impl Process {
    pub fn find_module(&self, name: &str) -> Result<ModuleInfo> {
        let regions = self.get_memory_regions()?;
         
        regions.iter()
            .filter(|r| !r.path.is_empty())
            .find(|r| r.path.ends_with(name))
            .map(|r| ModuleInfo {
                base_address: r.start,
                size: r.end - r.start,
                name: r.path.clone(),
            })
            .ok_or_else(|| anyhow!("Module not found"))
    }
 
    pub fn rebase_address(&self, offset: usize, module_name: &str) -> Result<usize> {
        let module = self.find_module(module_name)?;
        Ok(module.base_address + offset)

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2025-5-18 11:38 被Hrlies编辑 ,原因:
收藏
免费 12
支持
分享
最新回复 (7)
雪    币: 6
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2025-5-17 12:39
0
雪    币: 19
活跃值: (308)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
谢谢分享~
2025-5-17 13:45
0
雪    币: 300
活跃值: (770)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2025-5-20 11:33
0
雪    币: 2
活跃值: (143)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2025-5-28 16:27
0
雪    币: 237
活跃值: (1015)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
谢谢分析昂!
2025-5-30 09:40
0
雪    币: 2280
活跃值: (1565)
能力值: ( LV8,RANK:138 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2025-6-6 15:36
0
雪    币: 3596
活跃值: (3352)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
原来真正的干货在这,谢谢大佬
2天前
0
游客
登录 | 注册 方可回帖
返回