<p align="center">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="256" height="256">
<rect width="256" height="256" rx="16" fill="#111"/>
<rect x="40" y="40" width="28" height="28" rx="4" fill="#334155"/>
<rect x="76" y="40" width="28" height="28" rx="4" fill="#334155"/>
<rect x="112" y="40" width="28" height="28" rx="4" fill="#f97316"/>
<rect x="148" y="40" width="28" height="28" rx="4" fill="#f97316"/>
<rect x="184" y="40" width="28" height="28" rx="4" fill="#334155"/>
<rect x="40" y="76" width="28" height="28" rx="4" fill="#334155"/>
<rect x="76" y="76" width="28" height="28" rx="4" fill="#38bdf8"/>
<rect x="112" y="76" width="28" height="28" rx="4" fill="#334155"/>
<rect x="148" y="76" width="28" height="28" rx="4" fill="#334155"/>
<rect x="184" y="76" width="28" height="28" rx="4" fill="#38bdf8"/>
<rect x="40" y="112" width="28" height="28" rx="4" fill="#334155"/>
<rect x="76" y="112" width="28" height="28" rx="4" fill="#334155"/>
<rect x="112" y="112" width="28" height="28" rx="4" fill="#334155"/>
<rect x="148" y="112" width="28" height="28" rx="4" fill="#a78bfa"/>
<rect x="184" y="112" width="28" height="28" rx="4" fill="#334155"/>
<line x1="64" y1="216" x2="126" y2="154" stroke="#f97316" stroke-width="3" stroke-linecap="round"/>
<circle cx="126" cy="154" r="5" fill="#f97316"/>
<circle cx="54" cy="226" r="6" fill="#f97316"/>
</svg>
</p>
<h1 align="center">procmod-core</h1>
<p align="center">Cross-platform process memory read/write for Rust.</p>
---
Read and write memory in external processes on macOS, Linux, and Windows. Enumerate loaded modules and memory regions. Pure Rust, no C FFI wrappers.
## Install
```toml
[dependencies]
procmod-core = "1"
```
## Quick start
Read a game's player health from a known memory address:
```rust
use procmod_core::Process;
fn main() -> procmod_core::Result<()> {
let game = Process::attach(pid)?;
// read the player's health at a known offset
let health: f32 = unsafe { game.read(0x7FF6_1A00_4200)? };
println!("player health: {}", health);
Ok(())
}
```
## Usage
### Attach to a process
```rust
let process = Process::attach(1234)?;
```
### Read and write memory
```rust
// read a typed value (T must be valid for any bit pattern)
let hp: f32 = unsafe { process.read(address)? };
// write a typed value
process.write(address, &100.0_f32)?;
// raw byte operations
let bytes = process.read_bytes(address, 64)?;
process.write_bytes(address, &[0x90, 0x90, 0x90])?;
```
### Enumerate modules
Find where a game's main executable or a specific DLL is loaded, then scan from its base address:
```rust
let modules = process.modules()?;
for m in &modules {
println!("{}: base={:#x} size={:#x}", m.name, m.base, m.size);
}
// find a specific module
```
### Query memory regions
Understand what memory is mapped and with what permissions - useful for finding writable data segments or executable code:
```rust
let regions = process.regions()?;
for r in ®ions {
println!("{:#x} ({} bytes) {}", r.base, r.size, r.protection);
}
// find all writable regions
let writable: Vec<_> = regions.iter().filter(|r| r.protection.write).collect();
```
## Platform support
| macOS | Mach VM (`mach_vm_read_overwrite` / `mach_vm_write`) | x86_64, arm64 |
| Linux | `process_vm_readv` / `process_vm_writev` | x86_64, arm64 |
| Windows | `ReadProcessMemory` / `WriteProcessMemory` | x86_64 |
## Permissions
- **macOS**: Requires the `com.apple.security.cs.debugger` entitlement or running as root. SIP must allow task_for_pid on the target.
- **Linux**: Requires `CAP_SYS_PTRACE` or appropriate `ptrace_scope` settings. Reading a child process's memory generally works without extra privileges.
- **Windows**: Requires `SeDebugPrivilege` for system processes. Standard user can read/write processes they own.
## License
MIT