🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)
🕵️ SicherheitslückenWhat continuous operational resilience looks like under DORA(09.09.2026 um 17:53 Uhr)
🔧 AI Nachrichten OpenAI seeks tougher AI rules. CIOs may feel the ripple effects(10.09.2026 um 12:11 Uhr)
🔧 AI Nachrichten Mistral valued at €21bn after €3bn Series D funding round(08.09.2026 um 10:19 Uhr)
🪟 Windows TippsWindows XP's Cursor Indicator Is Getting a Windows 11 Refresh(25.08.2026 um 13:00 Uhr)

🔧 Programmierung 🕛 vor 1 Monat 11 Min Lesezeit
0

[Advanced Rust] 1.8. Memory Pt.6 - Scanning Address Space Through the Operating System

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




1.8.1. Scan the Address Space Through the Operating System (Example)



Operating systems provide interfaces that let programs make requests — system calls. On Windows, KERNEL32.DLL provides functions for inspecting and manipulating the memory of running processes.



This example is performed on Windows. Why use Windows as the example?




  • The function names are easy to understand

  • No knowledge of the POSIX API is required






1.8.2. Dependencies



This example uses the windows-sys crate, which provides low-level bindings to the Windows API. Add the following dependency to Cargo.toml:




CODE
[dependencies]
windows-sys = { version = "0.59.0", features = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_ProcessStatus",
"Win32_System_Threading",
] }







  • Here we use windows-sys to call Windows APIs such as GetCurrentProcess, K32GetProcessMemoryInfo, and VirtualQueryEx. Those modules are feature-gated, so the features above must be enabled.






1.8.3. Main Program



Then bring the required items into scope in main.rs:




CODE
use std::ffi::c_void;
use std::mem;
use windows_sys::Win32::System::Memory::{VirtualQueryEx, MEMORY_BASIC_INFORMATION};
use windows_sys::Win32::System::ProcessStatus::{PROCESS_MEMORY_COUNTERS, K32GetProcessMemoryInfo};
use windows_sys::Win32::System::Threading::{GetCurrentProcess, GetCurrentProcessId};

/// Windows `PVOID` / `SIZE_T` as used by the Win32 APIs.
/// In `windows-sys` 0.59+, these are expressed as raw Rust types rather than
/// named aliases under `Win32::Foundation`.
type PVOID = *mut c_void;
type SIZE_T = usize;








  • PVOID: Represents a void* pointer, used to describe an opaque memory address. Here it is a local alias for *mut c_void.


  • SIZE_T: Corresponds to an unsigned integer type used to represent the size of a memory region. Here it is a local alias for usize (matching the windows-sys 0.59+ signatures).


  • MEMORY_BASIC_INFORMATION: A built-in system structure used to describe the basic information of a memory region.


  • PROCESS_MEMORY_COUNTERS: A structure used to record a process’s memory usage.


  • K32GetProcessMemoryInfo: This function retrieves memory information for the current process.


  • GetCurrentProcess and GetCurrentProcessId: Retrieve the current process handle and process ID, respectively.






For convenient Debug output, we wrap the PROCESS_MEMORY_COUNTERS returned by the Windows API in a custom ProcessInfo structure:




CODE
#[derive(Debug)]
struct ProcessInfo {
cb: u32,
page_fault_count: u32,
peak_working_set_size: usize,
working_set_size: usize,
quota_peak_paged_pool_usage: usize,
quota_paged_pool_usage: usize,
quota_peak_non_paged_pool_usage: usize,
quota_non_paged_pool_usage: usize,
pagefile_usage: usize,
peak_pagefile_usage: usize,
}








  • cb (u32):




    • Description: The size of the structure in bytes.

    • Purpose: Identifies the size of the structure for compatibility.




  • page_fault_count (u32):




    • Description: The total number of page faults since the process started.

    • Purpose: A page fault is the handling process triggered when a memory access misses physical memory. It includes soft faults (data obtained from the file cache) and hard faults (data loaded from disk).




  • peak_working_set_size (usize):




    • Description: The peak size of the working set used by the process, meaning the memory currently resident in physical memory.

    • Purpose: Used to monitor the process’s peak memory usage.




  • working_set_size (usize):




    • Description: The current size of the process’s working set.

    • Purpose: Shows how much physical memory the process is currently using.




  • quota_peak_paged_pool_usage (usize):




    • Description: The peak size of the process’s paged-pool quota usage.

    • Purpose: The paged pool is kernel-mode memory that can be paged out to disk.




  • quota_paged_pool_usage (usize)




    • Description: The current size of the process’s paged-pool quota usage.

    • Purpose: Used to monitor the amount of pageable kernel memory currently in use.




  • quota_peak_non_paged_pool_usage (usize):




    • Description: The peak size of the process’s non-paged-pool quota usage.

    • Purpose: The non-paged pool is kernel-mode memory that remains permanently resident in physical memory.




  • quota_non_paged_pool_usage (usize):




    • Description: The current size of the process’s non-paged-pool quota usage.

    • Purpose: Used to monitor the amount of non-pageable kernel memory currently in use.




  • pagefile_usage (usize):




    • Description: The current amount of space used by the process in the page file.

    • Purpose: Indicates how much of the process’s data has been paged to disk.




  • peak_pagefile_usage (usize)




    • Description: The peak amount of page-file space used by the process.

    • Purpose: Used to monitor the process’s page-file high-water mark.





MEMORY_BASIC_INFORMATION from windows-sys does not implement Debug, so we also wrap its fields for printing:




CODE
#[derive(Debug)]
struct MemoryBasicInfo {
base_address: *mut c_void,
allocation_base: *mut c_void,
allocation_protect: u32,
region_size: usize,
state: u32,
protect: u32,
type_: u32,
}









Get the current process handle and process ID (these must go inside an unsafe block):




CODE
let this_proc = GetCurrentProcess();
let this_pid = GetCurrentProcessId();









Retrieve process memory information:




CODE
let mut mem_counters: PROCESS_MEMORY_COUNTERS = mem::zeroed();
let mem_counters_size = mem::size_of::<PROCESS_MEMORY_COUNTERS>() as u32;
K32GetProcessMemoryInfo(this_proc, &mut mem_counters, mem_counters_size);








  1. let mut mem_counters: PROCESS_MEMORY_COUNTERS = mem::zeroed();




    • Use mem::zeroed() to create and initialize a PROCESS_MEMORY_COUNTERS structure so that all of its fields are zero.


    • PROCESS_MEMORY_COUNTERS is a predefined Windows structure used to store process memory statistics.




  2. let mem_counters_size = mem::size_of::<PROCESS_MEMORY_COUNTERS>() as u32;




    • Use mem::size_of to compute the size of the PROCESS_MEMORY_COUNTERS structure in bytes.

    • Convert that size to u32, which is then used as a parameter in the API call below.




  3. K32GetProcessMemoryInfo(this_proc, &mut mem_counters, mem_counters_size);





    • Parameter explanation:



      • this_proc: The current process handle, indicating which process’s memory data you want to query.


      • &mut mem_counters: A mutable reference to the PROCESS_MEMORY_COUNTERS structure, used to receive the memory statistics returned by the API.


      • mem_counters_size: The size of the structure, ensuring the API can correctly read and populate the structure data.




    • Purpose:
      Call K32GetProcessMemoryInfo to fill mem_counters with the current process’s memory state, such as the page-fault count, working-set size, and page-file usage.








Wrap the memory information in our custom ProcessInfo:




CODE
let proc_info = ProcessInfo {
cb: mem_counters.cb,
page_fault_count: mem_counters.PageFaultCount,
peak_working_set_size: mem_counters.PeakWorkingSetSize,
working_set_size: mem_counters.WorkingSetSize,
quota_peak_paged_pool_usage: mem_counters.QuotaPeakPagedPoolUsage,
quota_paged_pool_usage: mem_counters.QuotaPagedPoolUsage,
quota_peak_non_paged_pool_usage: mem_counters.QuotaPeakNonPagedPoolUsage,
quota_non_paged_pool_usage: mem_counters.QuotaNonPagedPoolUsage,
pagefile_usage: mem_counters.PagefileUsage,
peak_pagefile_usage: mem_counters.PeakPagefileUsage,
};









Define the starting and ending addresses for the scan:




CODE
let min_addr: PVOID = 0 as PVOID;









Set a typical upper bound for a 64-bit user-mode address space:




CODE
let max_addr: PVOID = 0x00007FFF_FFFF_FFFF as PVOID;









Print the process information and the address range:




CODE
println!("{:p} @ {:p}", this_pid as *const (), this_proc as *const ());
println!("{:?}", proc_info);
println!("min: {:p}, max: {:p}", min_addr, max_addr);









Initialize the parameters required by VirtualQueryEx:




CODE
let MEMINFO_SIZE = mem::size_of::<MEMORY_BASIC_INFORMATION>();
let mut base_addr: PVOID = min_addr;
let mut mem_info: MEMORY_BASIC_INFORMATION = mem::zeroed();








  1. let MEMINFO_SIZE = mem::size_of::<MEMORY_BASIC_INFORMATION>();





    • Purpose: Compute the size of MEMORY_BASIC_INFORMATION in bytes and store it in MEMINFO_SIZE.


    • Reason: The VirtualQueryEx function requires the size of this structure buffer so it can write the query result correctly.




  2. let mut base_addr: PVOID = min_addr;





    • Purpose: Initialize the starting address for the virtual-memory scan by setting the first scan address to min_addr.


    • base_addr: Represents the starting address of the current query and will be incremented in the loop below to traverse the entire virtual address space.




  3. let mut mem_info: MEMORY_BASIC_INFORMATION = mem::zeroed();





    • Purpose: Use mem::zeroed() to create and initialize a MEMORY_BASIC_INFORMATION structure, setting all fields to zero.





    - Reason: This structure will store the result of VirtualQueryEx, namely the detailed information of the memory region corresponding to the current query address.





Scan the entire address space by calling VirtualQueryEx in a loop:




CODE
loop {
let rc: SIZE_T = VirtualQueryEx(this_proc, base_addr, &mut mem_info, MEMINFO_SIZE as SIZE_T);

if rc == 0 {
break;
}

// `MEMORY_BASIC_INFORMATION` from `windows-sys` does not implement `Debug`,
// so wrap the fields we care about for printing.
let printable = MemoryBasicInfo {
base_address: mem_info.BaseAddress,
allocation_base: mem_info.AllocationBase,
allocation_protect: mem_info.AllocationProtect,
region_size: mem_info.RegionSize,
state: mem_info.State,
protect: mem_info.Protect,
type_: mem_info.Type,
};
println!("{:#?}", printable);
// Add the size of the current region to get the next query address
base_addr = ((base_addr as usize) + mem_info.RegionSize) as PVOID;
if (base_addr as usize) >= (max_addr as usize) {
break;
}
}









1.8.4. Full Code



main.rs:




CODE
use std::ffi::c_void;
use std::mem;
use windows_sys::Win32::System::Memory::{VirtualQueryEx, MEMORY_BASIC_INFORMATION};
use windows_sys::Win32::System::ProcessStatus::{PROCESS_MEMORY_COUNTERS, K32GetProcessMemoryInfo};
use windows_sys::Win32::System::Threading::{GetCurrentProcess, GetCurrentProcessId};

/// Windows `PVOID` / `SIZE_T` as used by the Win32 APIs.
/// In `windows-sys` 0.59+, these are expressed as raw Rust types rather than
/// named aliases under `Win32::Foundation`.
type PVOID = *mut c_void;
type SIZE_T = usize;

/// To allow Debug-formatted output, we wrap PROCESS_MEMORY_COUNTERS ourselves.
#[derive(Debug)]
struct ProcessInfo {
cb: u32,
page_fault_count: u32,
peak_working_set_size: usize,
working_set_size: usize,
quota_peak_paged_pool_usage: usize,
quota_paged_pool_usage: usize,
quota_peak_non_paged_pool_usage: usize,
quota_non_paged_pool_usage: usize,
pagefile_usage: usize,
peak_pagefile_usage: usize,
}

/// `MEMORY_BASIC_INFORMATION` from `windows-sys` does not implement `Debug`.
#[derive(Debug)]
struct MemoryBasicInfo {
base_address: *mut c_void,
allocation_base: *mut c_void,
allocation_protect: u32,
region_size: usize,
state: u32,
protect: u32,
type_: u32,
}

fn main() {
unsafe {
// Get the current process handle and process ID
let this_proc = GetCurrentProcess();
let this_pid = GetCurrentProcessId();

// Get process memory information
let mut mem_counters: PROCESS_MEMORY_COUNTERS = mem::zeroed();
let mem_counters_size = mem::size_of::<PROCESS_MEMORY_COUNTERS>() as u32;
K32GetProcessMemoryInfo(this_proc, &mut mem_counters, mem_counters_size);

// Wrap the memory information in our custom ProcessInfo
let proc_info = ProcessInfo {
cb: mem_counters.cb,
page_fault_count: mem_counters.PageFaultCount,
peak_working_set_size: mem_counters.PeakWorkingSetSize,
working_set_size: mem_counters.WorkingSetSize,
quota_peak_paged_pool_usage: mem_counters.QuotaPeakPagedPoolUsage,
quota_paged_pool_usage: mem_counters.QuotaPagedPoolUsage,
quota_peak_non_paged_pool_usage: mem_counters.QuotaPeakNonPagedPoolUsage,
quota_non_paged_pool_usage: mem_counters.QuotaNonPagedPoolUsage,
pagefile_usage: mem_counters.PagefileUsage,
peak_pagefile_usage: mem_counters.PeakPagefileUsage,
};

// Define the start and end addresses of the scan
let min_addr: PVOID = 0 as PVOID;
// Set a typical upper bound for a 64-bit user-mode address space
let max_addr: PVOID = 0x00007FFF_FFFF_FFFF as PVOID;

// Print
println!("{:p} @ {:p}", this_pid as *const (), this_proc as *const ());
println!("{:?}", proc_info);
println!("min: {:p}, max: {:p}", min_addr, max_addr);

// Initialize the parameters required by VirtualQueryEx
let MEMINFO_SIZE = mem::size_of::<MEMORY_BASIC_INFORMATION>();
let mut base_addr: PVOID = min_addr;
let mut mem_info: MEMORY_BASIC_INFORMATION = mem::zeroed();

// Loop over VirtualQueryEx to scan the entire address space
loop {
let rc: SIZE_T =
VirtualQueryEx(this_proc, base_addr, &mut mem_info, MEMINFO_SIZE as SIZE_T);
if rc == 0 {
break;
}

let printable = MemoryBasicInfo {
base_address: mem_info.BaseAddress,
allocation_base: mem_info.AllocationBase,
allocation_protect: mem_info.AllocationProtect,
region_size: mem_info.RegionSize,
state: mem_info.State,
protect: mem_info.Protect,
type_: mem_info.Type,
};
println!("{:#?}", printable);
// Add the size of the current region to get the next query address
base_addr = ((base_addr as usize) + mem_info.RegionSize) as PVOID;
if (base_addr as usize) >= (max_addr as usize) {
break;
}
}
}
}






Cargo.toml:




CODE
[package]  
name = "RustStudy"
version = "0.1.0"
edition = "2021"

[dependencies]
windows-sys = { version = "0.59.0", features = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_ProcessStatus",
"Win32_System_Threading",
] }









1.8.5. Steps for Reading and Writing Process Memory



The logic for reading and writing process memory is fairly simple. Pseudocode:




CODE
let pid = some_process_id;
OpenProcess(pid);

loop over the address space {
call VirtualQueryEx() to reach the next memory block

use ReadProcessMemory() to access the memory block
search for a specific pattern

call WriteProcessMemory() with the value you need
}








  • let pid = some_process_id;: Get the current process ID


  • OpenProcess(pid);: Open this process



Linux provides simple APIs: process_vm_readv() and process_vm_writev(), which correspond to ReadProcessMemory() and WriteProcessMemory() on Windows.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Sam Altman calls GPT-6 Astra rollout ‘messy’ as enterprise users wait for access
1 Quelle
Swiss government explores replacing Microsoft 365 with open-source software
1 Quelle
What continuous operational resilience looks like under DORA
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten [Advanced Rust] 1.8. Memory Pt.6 - Scanning Address Space Through the Operating System

Thematisch verwandte Begriffe: Advanced, Rust, Memory, Scanning · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...