关键点:
技术细节:
注意事项:
技术细节:
关键字段:
实际开发中需要特别注意:
可以通过添加更多中间抽象层(如统一的内存保护标志、跨平台的地址类型封装)来增强代码的可维护性。同时建议结合 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)
}
// 统一权限表示
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,
// ...
}
}
}
// 统一权限表示
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 位差异
type AddressType = u32;
type AddressType = u64;
// 处理 32/64 位差异
type AddressType = u32;
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)
}
mod tests {
fn test_linux_memory_read() {
// 测试当前进程的内存读取
}
fn test_windows_handle_acquisition() {
// 测试进程打开权限
}
}
mod tests {
fn test_linux_memory_read() {
// 测试当前进程的内存读取
}
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)
}
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)
}
}
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)
}
}
#[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),
}
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))
}
}
}
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))
}
}
}
#[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),
}
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))
}
}
}
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))
}
}
}
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")?;
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)
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2025-5-18 11:38
被Hrlies编辑
,原因: