Updated to latest memflow, added set_mem_map support

pull/7/head
ko1N 4 years ago
parent 9edb44d03b
commit 2eb3ca73e6

@ -16,11 +16,15 @@ categories = [ "api-bindings", "memory-management", "os" ]
crate-type = ["lib", "cdylib"] crate-type = ["lib", "cdylib"]
[dependencies] [dependencies]
memflow = { git = "https://github.com/memflow/memflow", branch = "next", features = ["inventory", "memmapfiles"] } memflow = { git = "https://github.com/memflow/memflow", branch = "next", features = ["plugins", "memmapfiles"] }
log = { version = "0.4", default-features = false } log = { version = "0.4", default-features = false }
simple_logger = "1.0" simple_logger = "1.0"
leechcore-sys = { path = "../leechcore-sys" } leechcore-sys = { path = "../leechcore-sys" }
[dev-dependencies]
clap = "2.33"
memflow-win32 = { git = "https://github.com/memflow/memflow", branch = "next" }
[features] [features]
default = [] default = []
inventory = [] inventory = []
@ -28,3 +32,11 @@ inventory = []
[[example]] [[example]]
name = "read_phys" name = "read_phys"
path = "examples/read_phys.rs" path = "examples/read_phys.rs"
[[example]]
name = "ps_win32"
path = "examples/ps_win32.rs"
[[example]]
name = "ps_inventory"
path = "examples/ps_inventory.rs"

@ -0,0 +1,57 @@
/*!
This example shows how to use the pcileech connector in conjunction
with a specific OS layer. This example uses the `Inventory` feature of memflow
to create the connector itself and the os instance.
The example is an adaption of the memflow core process list example:
https://github.com/memflow/memflow/blob/next/memflow/examples/process_list.rs
# Remarks:
To run this example you must have the `pcileech` connector and `win32` plugin installed on your system.
Make sure they can be found in one of the following locations:
~/.local/lib/memflow/
/usr/lib/memflow/
or in any other path found in the official memflow documentation.
*/
use std::env::args;
use log::{info, Level};
use memflow::prelude::v1::*;
fn main() {
simple_logger::SimpleLogger::new()
.with_level(Level::Debug.to_level_filter())
.init()
.unwrap();
let connector_args = if let Some(arg) = args().nth(1) {
Args::parse(arg.as_ref()).expect("unable to parse command line arguments")
} else {
Args::default()
};
let inventory = Inventory::scan();
let connector = inventory
.create_connector("pcileech", None, &connector_args)
.expect("unable to create pcileech connector");
let mut os = inventory
.create_os("win32", Some(connector), &Args::default())
.expect("unable to create win32 instance with pcileech connector");
let process_list = os.process_info_list().expect("unable to read process list");
info!(
"{:>5} {:>10} {:>10} {:<}",
"PID", "SYS ARCH", "PROC ARCH", "NAME"
);
for p in process_list {
info!(
"{:>5} {:^10} {:^10} {}",
p.pid, p.sys_arch, p.proc_arch, p.name
);
}
}

@ -0,0 +1,56 @@
/*!
This example shows how to use the pcileech connector in conjunction
with a specific OS layer. This example does not use the `Inventory` feature of memflow
but hard-wires the connector instance with the OS layer directly.
The example is an adaption of the memflow core process list example:
https://github.com/memflow/memflow/blob/next/memflow/examples/process_list.rs
# Remarks:
The most flexible and recommended way to use memflow is to go through the inventory.
The inventory allows the user to swap out connectors and os layers at runtime.
For more information about the Inventory see the ps_inventory.rs example in this repository
or check out the documentation at:
https://docs.rs/memflow/0.1.5/memflow/connector/inventory/index.html
*/
use std::env::args;
use log::{info, Level};
use memflow::prelude::v1::*;
use memflow_win32::prelude::v1::*;
fn main() {
simple_logger::SimpleLogger::new()
.with_level(Level::Debug.to_level_filter())
.init()
.unwrap();
let connector_args = if let Some(arg) = args().nth(1) {
Args::parse(arg.as_ref()).expect("unable to parse command line arguments")
} else {
Args::default()
};
let connector = memflow_pcileech::create_connector(&connector_args, Level::Debug)
.expect("unable to create pcileech connector");
let mut os = Win32Kernel::builder(connector)
.build_default_caches()
.build()
.expect("unable to create win32 instance with pcileech connector");
let process_list = os.process_info_list().expect("unable to read process list");
info!(
"{:>5} {:>10} {:>10} {:<}",
"PID", "SYS ARCH", "PROC ARCH", "NAME"
);
for p in process_list {
info!(
"{:>5} {:^10} {:^10} {}",
p.pid, p.sys_arch, p.proc_arch, p.name
);
}
}

@ -1,4 +1,8 @@
use std::env; /*!
This example shows how to use the pcileech connector to read physical_memory
from a target machine. It also evaluates the number of read cycles per second
and prints them to stdout.
*/
use std::time::Instant; use std::time::Instant;
use log::{info, Level}; use log::{info, Level};
@ -11,30 +15,28 @@ fn main() {
.init() .init()
.unwrap(); .unwrap();
let args: Vec<String> = env::args().collect(); let mut connector = memflow_pcileech::create_connector(&Args::default(), Level::Debug)
let conn_args = if args.len() > 1 { .expect("unable to create pcileech connector");
ConnectorArgs::parse(&args[1]).expect("unable to parse arguments")
} else {
ConnectorArgs::new()
};
let mut conn = memflow_pcileech::create_connector(Level::Debug, &conn_args) let metadata = connector.metadata();
.expect("unable to initialize memflow_pcileech"); info!("Received metadata: {:?}", metadata);
let mut mem = vec![0; 8]; let mut mem = vec![0; 8];
conn.phys_read_raw_into(Address::from(0x1000).into(), &mut mem) connector
.unwrap(); .phys_read_raw_into(Address::from(0x1000).into(), &mut mem)
.expect("unable to read physical memory");
info!("Received memory: {:?}", mem); info!("Received memory: {:?}", mem);
let start = Instant::now(); let start = Instant::now();
let mut counter = 0; let mut counter = 0;
loop { loop {
let mut buf = vec![0; 0x1000]; let mut buf = vec![0; 0x1000];
conn.phys_read_raw_into(Address::from(0x1000).into(), &mut buf) connector
.unwrap(); .phys_read_raw_into(Address::from(0x1000).into(), &mut buf)
.expect("unable to read physical memory");
counter += 1; counter += 1;
if (counter % 10000) == 0 { if (counter % 10000000) == 0 {
let elapsed = start.elapsed().as_millis() as f64; let elapsed = start.elapsed().as_millis() as f64;
if elapsed > 0.0 { if elapsed > 0.0 {
info!("{} reads/sec", (f64::from(counter)) / elapsed * 1000.0); info!("{} reads/sec", (f64::from(counter)) / elapsed * 1000.0);

@ -93,7 +93,8 @@ impl PciLeech {
// TODO: handle version error // TODO: handle version error
// TODO: handle special case of fUserInputRequest // TODO: handle special case of fUserInputRequest
error!("leechcore error: {:?}", err); error!("leechcore error: {:?}", err);
return Err(Error::Connector("unable to create leechcore context")); return Err(Error(ErrorOrigin::Connector, ErrorKind::Configuration)
.log_error("unable to create leechcore context"));
} }
Ok(Self { Ok(Self {
@ -146,7 +147,8 @@ impl PhysicalMemory for PciLeech {
) )
}; };
if result != 1 { if result != 1 {
return Err(Error::Connector("unable to allocate scatter buffer")); return Err(Error(ErrorOrigin::Connector, ErrorKind::InvalidMemorySize)
.log_error("unable to allocate scatter buffer"));
} }
// prepare mems // prepare mems
@ -243,7 +245,8 @@ impl PhysicalMemory for PciLeech {
) )
}; };
if result != 1 { if result != 1 {
return Err(Error::Connector("unable to allocate scatter buffer")); return Err(Error(ErrorOrigin::Connector, ErrorKind::InvalidMemorySize)
.log_error("unable to allocate scatter buffer"));
} }
// prepare mems // prepare mems
@ -337,24 +340,53 @@ impl PhysicalMemory for PciLeech {
fn metadata(&self) -> PhysicalMemoryMetadata { fn metadata(&self) -> PhysicalMemoryMetadata {
self.metadata self.metadata
} }
fn set_mem_map(&mut self, mem_map: MemoryMap<(Address, usize)>) {
// TODO: check if current mem_map is empty
// TODO: update metadata.size
self.mem_map = mem_map;
}
} }
/// Creates a new PciLeech Connector instance. /// Creates a new PciLeech Connector instance.
#[connector(name = "pcileech", ty = "PciLeech")] pub fn create_connector(args: &Args, log_level: Level) -> Result<PciLeech> {
pub fn create_connector(log_level: Level, args: &ConnectorArgs) -> Result<PciLeech> {
simple_logger::SimpleLogger::new() simple_logger::SimpleLogger::new()
.with_level(log_level.to_level_filter()) .with_level(log_level.to_level_filter())
.init() .init()
.ok(); .ok();
let device = args let validator = ArgsValidator::new()
.get("device") .arg(ArgDescriptor::new("default").description("the target device to be used by LeechCore"))
.or_else(|| args.get_default()) .arg(ArgDescriptor::new("device").description("the target device to be used by LeechCore"))
.ok_or(Error::Connector("argument 'device' missing"))?; .arg(ArgDescriptor::new("memmap").description("the memory map file of the target machine"));
match validator.validate(&args) {
Ok(_) => {
let device = args.get("device").or_else(|| args.get_default()).ok_or(
Error(ErrorOrigin::Connector, ErrorKind::ArgValidation)
.log_error("'device' argument is missing"),
)?;
if let Some(memmap) = args.get("memmap") { if let Some(memmap) = args.get("memmap") {
PciLeech::with_memmap(device, memmap) PciLeech::with_memmap(device, memmap)
} else { } else {
PciLeech::new(device) PciLeech::new(device)
} }
}
Err(err) => {
error!(
"unable to validate provided arguments, valid arguments are:\n{}",
validator
);
Err(err)
}
}
}
/// Creates a new PciLeech Connector instance.
#[connector(name = "pcileech")]
pub fn create_connector_instance(args: &Args, log_level: Level) -> Result<ConnectorInstance> {
let connector = create_connector(args, log_level)?;
let instance = ConnectorInstance::builder(connector).build();
Ok(instance)
} }

Loading…
Cancel
Save