Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion memflow-win32-defs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ keywords = [ "memflow", "introspection", "memory", "dma" ]
categories = [ "api-bindings", "memory-management", "os" ]

[dependencies]
memflow = { version = "0.2", default-features = false }
#memflow = { version = "0.2", default-features = false }
memflow = { path = "../../memflow/memflow" }

log = { version = "0.4", default-features = false }
no-std-compat = { version = "0.4", features = ["alloc"] }
serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] }
Expand Down
26 changes: 17 additions & 9 deletions memflow-win32-defs/src/offsets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,17 @@ use std::{fs::File, io::Read, path::Path};
#[repr(C)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
pub struct Win32ArchOffsets {
pub peb_ldr: usize, // _PEB::Ldr
pub peb_process_params: usize, // _PEB::ProcessParameters
pub ldr_list: usize, // _PEB_LDR_DATA::InLoadOrderModuleList
pub ldr_data_base: usize, // _LDR_DATA_TABLE_ENTRY::DllBase
pub ldr_data_size: usize, // _LDR_DATA_TABLE_ENTRY::SizeOfImage
pub ldr_data_full_name: usize, // _LDR_DATA_TABLE_ENTRY::FullDllName
pub ldr_data_base_name: usize, // _LDR_DATA_TABLE_ENTRY::BaseDllName
pub ppm_image_path_name: usize, // _RTL_USER_PROCESS_PARAMETERS::ImagePathName
pub ppm_command_line: usize, // _RTL_USER_PROCESS_PARAMETERS::CommandLine
pub peb_ldr: usize, // _PEB::Ldr
pub peb_process_params: usize, // _PEB::ProcessParameters
pub ldr_list: usize, // _PEB_LDR_DATA::InLoadOrderModuleList
pub ldr_data_base: usize, // _LDR_DATA_TABLE_ENTRY::DllBase
pub ldr_data_size: usize, // _LDR_DATA_TABLE_ENTRY::SizeOfImage
pub ldr_data_full_name: usize, // _LDR_DATA_TABLE_ENTRY::FullDllName
pub ldr_data_base_name: usize, // _LDR_DATA_TABLE_ENTRY::BaseDllName
pub ppm_image_path_name: usize, // _RTL_USER_PROCESS_PARAMETERS::ImagePathName
pub ppm_command_line: usize, // _RTL_USER_PROCESS_PARAMETERS::CommandLine
pub ppm_environment: usize, // _RTL_USER_PROCESS_PARAMETERS::Environment
pub ppm_environment_size: usize, // _RTL_USER_PROCESS_PARAMETERS::EnvironmentSize
}

pub const X86: Win32ArchOffsets = Win32ArchOffsets {
Expand All @@ -56,6 +58,8 @@ pub const X86: Win32ArchOffsets = Win32ArchOffsets {
ldr_data_base_name: 0x2c,
ppm_image_path_name: 0x38,
ppm_command_line: 0x40,
ppm_environment: 0x48,
ppm_environment_size: 0x290,
};

pub const X64: Win32ArchOffsets = Win32ArchOffsets {
Expand All @@ -68,6 +72,8 @@ pub const X64: Win32ArchOffsets = Win32ArchOffsets {
ldr_data_base_name: 0x58,
ppm_image_path_name: 0x60,
ppm_command_line: 0x70,
ppm_environment: 0x80,
ppm_environment_size: 0x3f0,
};

pub const AARCH64: Win32ArchOffsets = Win32ArchOffsets {
Expand All @@ -80,6 +86,8 @@ pub const AARCH64: Win32ArchOffsets = Win32ArchOffsets {
ldr_data_base_name: 0x58,
ppm_image_path_name: 0x60,
ppm_command_line: 0x70,
ppm_environment: 0x80,
ppm_environment_size: 0x3f0,
};

impl Win32OffsetsArchitecture {
Expand Down
8 changes: 5 additions & 3 deletions memflow-win32/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "memflow-win32"
version = "0.2.1"
authors = ["ko1N <[email protected]>", "Aurimas Blažulionis <[email protected]>"]
authors = ["ko1N <[email protected]>", "Aurimas Blažulionis <[email protected]>", "k1nd0ne <[email protected]>"]
edition = "2021"
rust-version = "1.65"
description = "win32 integration of the memflow physical memory introspection framework"
Expand All @@ -21,7 +21,8 @@ codecov = { repository = "github", branch = "master", service = "github" }
crate-type = ["lib", "cdylib"]

[dependencies]
memflow = { version = "0.2", default-features = false }
#memflow = { version = "0.2", default-features = false }
memflow = { path = "../../memflow/memflow" }
log = { version = "0.4", default-features = false }
pelite = { version = "0.10", default-features = false }
widestring = { version = "1.1", default-features = false, features = ["alloc"] }
Expand All @@ -43,7 +44,8 @@ toml = "0.8"
[build-dependencies]
toml = "0.8"
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] }
memflow = { version = "0.2", default-features = false }
#memflow = { version = "0.2", default-features = false }
memflow = { path = "../../memflow/memflow" }
memflow-win32-defs = { version = "0.2", path = "../memflow-win32-defs", features = ["symstore"] }

[features]
Expand Down
104 changes: 104 additions & 0 deletions memflow-win32/examples/envars_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*!
This example shows how to use a dynamically loaded connector in conjunction
with memflow-win32. This example uses the `Inventory` feature of memflow
but hard-wires the connector instance into the memflow-win32 OS layer.

The example is an adaption of the memflow core process list example:
https://github.com/memflow/memflow/blob/next/memflow/examples/process_list.rs

# Usage:
```bash
cargo run --release --example envar_list -- -vv -c memraw:/path/to/memory.raw
```
*/
use clap::*;
use log::Level;

use memflow::prelude::v1::*;
use memflow_win32::prelude::v1::*;

pub fn main() -> Result<()> {
let matches = parse_args();
let chain = extract_args(&matches)?;

let mut inventory = Inventory::scan();
let connector = inventory.builder().connector_chain(chain).build()?;

let os = Win32Kernel::builder(connector)
.build_default_caches()
.build()
.unwrap();

let mut process = os
.into_process_by_name("explorer.exe")
.expect("unable to find process");
println!("found process: {:?}", process.proc_info.base_info.name);

println!(
"\nPID {:>5} | {:<} | sys={:?} proc={:?}",
process.proc_info.base_info.pid,
process.proc_info.base_info.name,
process.proc_info.base_info.sys_arch,
process.proc_info.base_info.proc_arch
);
let envar_list = process
.envar_list()
.expect("unable to retrieve environment variables list");

println!(" VARIABLE | VALUE");

for ev in envar_list {
println!(" {}={}", ev.name.as_ref(), ev.value.as_ref());
}

Ok(())
}

fn parse_args() -> ArgMatches {
Command::new("envar_list example")
.version(crate_version!())
.author(crate_authors!())
.arg(Arg::new("verbose").short('v').action(ArgAction::Count))
.arg(
Arg::new("connector")
.short('c')
.action(ArgAction::Append)
.required(true),
)
.arg(Arg::new("os").short('o').action(ArgAction::Append))
.get_matches()
}

fn extract_args(matches: &ArgMatches) -> Result<ConnectorChain<'_>> {
let log_level = match matches.get_count("verbose") {
0 => Level::Error,
1 => Level::Warn,
2 => Level::Info,
3 => Level::Debug,
4 => Level::Trace,
_ => Level::Trace,
};
simplelog::TermLogger::init(
log_level.to_level_filter(),
simplelog::Config::default(),
simplelog::TerminalMode::Stdout,
simplelog::ColorChoice::Auto,
)
.unwrap();

let conn_iter = matches
.indices_of("connector")
.zip(matches.get_many::<String>("connector"))
.map(|(a, b)| a.zip(b.map(String::as_str)))
.into_iter()
.flatten();

let os_iter = matches
.indices_of("os")
.zip(matches.get_many::<String>("os"))
.map(|(a, b)| a.zip(b.map(String::as_str)))
.into_iter()
.flatten();

ConnectorChain::new(conn_iter, os_iter)
}
2 changes: 2 additions & 0 deletions memflow-win32/src/win32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ pub use kernel::Win32Kernel;
pub use kernel_builder::Win32KernelBuilder;
pub use kernel_info::Win32KernelInfo;

pub mod envars;
pub mod keyboard;
pub mod module;
pub mod process;
pub mod unicode_string;
pub mod vat;
pub mod vkey;

pub use envars::*;
pub use keyboard::*;
pub use module::*;
pub use process::*;
Expand Down
109 changes: 109 additions & 0 deletions memflow-win32/src/win32/envars.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use std::prelude::v1::*;

use crate::offsets::Win32ArchOffsets;

use log::trace;

use memflow::architecture::ArchitectureIdent;
use memflow::error::Result;
use memflow::mem::MemoryView;
use memflow::os::util::env_block_list_utf16_callback;
use memflow::os::{EnvVarCallback, EnvVarInfo};
use memflow::types::{umem, Address};

#[derive(Debug, Clone, Copy)]
#[repr(C)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
pub struct Win32EnvListInfo {
env_block: Address,
env_size: umem,
offsets: Win32ArchOffsets,
proc_params: Address,
}

impl Win32EnvListInfo {
/// Construct from a PEB: reads _PEB::ProcessParameters and
/// _RTL_USER_PROCESS_PARAMETERS::Environment (PWSTR) and
/// _RTL_USER_PROCESS_PARAMETERS::EnvironmentSize.

pub fn with_peb(
mem: &mut impl MemoryView,
peb: Address,
arch: ArchitectureIdent,
) -> Result<Self> {
let offsets = Win32ArchOffsets::from(arch);
let arch_obj = arch.into();

trace!("peb_process_params_offs={:x}", offsets.peb_process_params);
let proc_params = mem.read_addr_arch(arch_obj, peb + offsets.peb_process_params)?;
trace!("ProcessParameters={:x}", proc_params);

trace!("ppm_environment_offs={:x}", offsets.ppm_environment);
let env_block = mem.read_addr_arch(arch_obj, proc_params + offsets.ppm_environment)?;
trace!("Environment={:x}", env_block);

trace!(
"ppm_environment_size_offs={:x}",
offsets.ppm_environment_size
);
let size_addr = proc_params + offsets.ppm_environment_size;

let env_size: umem = mem.read(size_addr)?;

trace!("EnvironmentSize={:x}", env_size);
Ok(Self {
env_block,
env_size,
offsets,
proc_params,
})
}

/// Construct directly from a known Environment pointer and size.
pub fn with_base(env_block: Address, env_size: umem, arch: ArchitectureIdent) -> Result<Self> {
let offsets = Win32ArchOffsets::from(arch);
trace!(
"env_block={:x} offsets={:?} size={:?}",
env_block,
offsets,
env_size
);
Ok(Self {
env_block,
env_size,
offsets,
proc_params: Address::NULL,
})
}

#[inline]
pub fn env_block(&self) -> Address {
self.env_block
}

/// Collect all environment variables into a Vec.
pub fn envar_list<V: MemoryView>(
&self,
mem: &mut impl AsMut<V>,
arch: ArchitectureIdent,
) -> Result<Vec<EnvVarInfo>> {
let mut out = vec![];
self.envar_list_callback(mem, arch, (&mut out).into())?;
Ok(out)
}

/// Enumerate environment variables via callback (UTF-16LE multi-string).
///
/// # Arguments
/// * `mem` - memory view in process context
/// * `arch` - view architecture (native or WOW64)
/// * `callback` - receives each EnvVarInfo; return `true` to continue, `false` to stop.
pub fn envar_list_callback<M: AsMut<V>, V: MemoryView>(
&self,
mem: &mut M,
arch: ArchitectureIdent,
callback: EnvVarCallback,
) -> Result<()> {
env_block_list_utf16_callback(mem.as_mut(), self.env_block, self.env_size, arch, callback)
}
}
18 changes: 16 additions & 2 deletions memflow-win32/src/win32/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use crate::{
};

use super::{
process::IMAGE_FILE_NAME_LENGTH, Win32KernelBuilder, Win32KernelInfo, Win32Keyboard,
Win32ModuleListInfo, Win32Process, Win32ProcessInfo, Win32VirtualTranslate,
process::IMAGE_FILE_NAME_LENGTH, Win32EnvListInfo, Win32KernelBuilder, Win32KernelInfo,
Win32Keyboard, Win32ModuleListInfo, Win32Process, Win32ProcessInfo, Win32VirtualTranslate,
};

use memflow::mem::virt_translate::*;
Expand Down Expand Up @@ -207,6 +207,9 @@ impl<T: 'static + PhysicalMemory + Clone, V: 'static + VirtualTranslate2 + Clone
module_info_native: Some(kernel_modules),
module_info_wow64: None,

env_info_native: None,
env_info_wow64: None,

vad_root,
})
}
Expand Down Expand Up @@ -317,6 +320,14 @@ impl<T: 'static + PhysicalMemory + Clone, V: 'static + VirtualTranslate2 + Clone
.map(|peb| Win32ModuleListInfo::with_peb(&mut proc_reader, peb, base_info.proc_arch))
.transpose()?;

let env_info_native = peb_native
.map(|peb| Win32EnvListInfo::with_peb(&mut proc_reader, peb, base_info.sys_arch))
.transpose()?;

let env_info_wow64 = peb_wow64
.map(|peb| Win32EnvListInfo::with_peb(&mut proc_reader, peb, base_info.proc_arch))
.transpose()?;

Ok(Win32ProcessInfo {
base_info,

Expand All @@ -333,6 +344,9 @@ impl<T: 'static + PhysicalMemory + Clone, V: 'static + VirtualTranslate2 + Clone
module_info_native,
module_info_wow64,

env_info_native,
env_info_wow64,

vad_root,
})
}
Expand Down
Loading