关键点:
技术细节:
注意事项:
技术细节:
关键字段:
实际开发中需要特别注意:
可以通过添加更多中间抽象层(如统一的内存保护标志、跨平台的地址类型封装)来增强代码的可维护性。同时建议结合 libc
crate 处理底层系统调用,使用 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)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2025-5-18 11:38
被Hrlies编辑
,原因: