add memory region enumeration for Windows

This commit is contained in:
Adir Shitrit
2025-11-07 18:04:12 +02:00
parent 8b55344d9b
commit 3df61c281f
3 changed files with 163 additions and 0 deletions

View File

@@ -1,3 +1,5 @@
pub mod memory;
pub mod process;
pub use memory::{MemoryProtection, MemoryRegion};
pub use process::ProcessInfo;

151
ghost-core/src/memory.rs Normal file
View File

@@ -0,0 +1,151 @@
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemoryProtection {
NoAccess,
ReadOnly,
ReadWrite,
ReadExecute,
ReadWriteExecute,
Execute,
WriteCopy,
Unknown,
}
impl fmt::Display for MemoryProtection {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::NoAccess => "---",
Self::ReadOnly => "R--",
Self::ReadWrite => "RW-",
Self::ReadExecute => "R-X",
Self::ReadWriteExecute => "RWX",
Self::Execute => "--X",
Self::WriteCopy => "WC-",
Self::Unknown => "???",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone)]
pub struct MemoryRegion {
pub base_address: usize,
pub size: usize,
pub protection: MemoryProtection,
pub region_type: String,
}
impl fmt::Display for MemoryRegion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:#016x} - {:#016x} {} {}",
self.base_address,
self.base_address + self.size,
self.protection,
self.region_type
)
}
}
#[cfg(windows)]
mod platform {
use super::{MemoryProtection, MemoryRegion};
use anyhow::{Context, Result};
use windows::Win32::Foundation::{CloseHandle, HANDLE};
use windows::Win32::System::Diagnostics::Debug::ReadProcessMemory;
use windows::Win32::System::Memory::{
VirtualQueryEx, MEMORY_BASIC_INFORMATION, MEM_COMMIT, MEM_FREE, MEM_IMAGE, MEM_MAPPED,
MEM_PRIVATE, MEM_RESERVE, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE,
PAGE_EXECUTE_WRITECOPY, PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY,
};
use windows::Win32::System::Threading::{OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ};
fn parse_protection(protect: u32) -> MemoryProtection {
match protect & 0xFF {
p if p == PAGE_NOACCESS.0 => MemoryProtection::NoAccess,
p if p == PAGE_READONLY.0 => MemoryProtection::ReadOnly,
p if p == PAGE_READWRITE.0 => MemoryProtection::ReadWrite,
p if p == PAGE_EXECUTE.0 => MemoryProtection::Execute,
p if p == PAGE_EXECUTE_READ.0 => MemoryProtection::ReadExecute,
p if p == PAGE_EXECUTE_READWRITE.0 => MemoryProtection::ReadWriteExecute,
p if p == PAGE_WRITECOPY.0 || p == PAGE_EXECUTE_WRITECOPY.0 => {
MemoryProtection::WriteCopy
}
_ => MemoryProtection::Unknown,
}
}
pub fn enumerate_memory_regions(pid: u32) -> Result<Vec<MemoryRegion>> {
let mut regions = Vec::new();
unsafe {
let handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid)
.context("Failed to open process")?;
let mut address: usize = 0;
let mut mbi = MEMORY_BASIC_INFORMATION::default();
loop {
let result = VirtualQueryEx(
handle,
Some(address as *const _),
&mut mbi,
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
);
if result == 0 {
break;
}
if mbi.State == MEM_COMMIT {
let region_type = if mbi.Type == MEM_IMAGE {
"IMAGE"
} else if mbi.Type == MEM_MAPPED {
"MAPPED"
} else if mbi.Type == MEM_PRIVATE {
"PRIVATE"
} else {
"UNKNOWN"
}
.to_string();
regions.push(MemoryRegion {
base_address: mbi.BaseAddress as usize,
size: mbi.RegionSize,
protection: parse_protection(mbi.Protect.0),
region_type,
});
}
address = (mbi.BaseAddress as usize)
.checked_add(mbi.RegionSize)
.unwrap_or(usize::MAX);
if address == usize::MAX {
break;
}
}
let _ = CloseHandle(handle);
}
Ok(regions)
}
}
#[cfg(not(windows))]
mod platform {
use super::MemoryRegion;
use anyhow::Result;
pub fn enumerate_memory_regions(_pid: u32) -> Result<Vec<MemoryRegion>> {
// TODO: Implement Linux/macOS memory enumeration
Ok(Vec::new())
}
}
pub fn enumerate_memory_regions(pid: u32) -> anyhow::Result<Vec<MemoryRegion>> {
platform::enumerate_memory_regions(pid)
}