You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
5.9 KiB
Rust
217 lines
5.9 KiB
Rust
use std::io::Write;
|
|
use std::time::{Duration, Instant};
|
|
|
|
use clap::*;
|
|
use log::Level;
|
|
|
|
use memflow::connector::*;
|
|
use memflow::mem::*;
|
|
use memflow::process::*;
|
|
use memflow::types::*;
|
|
|
|
use memflow_win32::error::Result;
|
|
use memflow_win32::offsets::Win32Offsets;
|
|
use memflow_win32::win32::{Kernel, KernelInfo, Win32ModuleInfo, Win32Process};
|
|
|
|
use rand::{Rng, SeedableRng};
|
|
use rand_xorshift::XorShiftRng as CurRng;
|
|
|
|
fn rwtest<T: VirtualMemory>(
|
|
proc: &mut Win32Process<T>,
|
|
module: &dyn OsProcessModuleInfo,
|
|
chunk_sizes: &[usize],
|
|
chunk_counts: &[usize],
|
|
read_size: usize,
|
|
) {
|
|
let mut rng = CurRng::seed_from_u64(0);
|
|
|
|
println!("Performance bench:");
|
|
print!("{:#7}", "SIZE");
|
|
|
|
for i in chunk_counts {
|
|
print!(", x{:02x} mb/s, x{:02x} calls/s", *i, *i);
|
|
}
|
|
|
|
println!();
|
|
|
|
let start = Instant::now();
|
|
let mut ttdur = Duration::new(0, 0);
|
|
|
|
for i in chunk_sizes {
|
|
print!("0x{:05x}", *i);
|
|
for o in chunk_counts {
|
|
let mut done_size = 0_usize;
|
|
let mut total_dur = Duration::new(0, 0);
|
|
let mut calls = 0;
|
|
let mut bufs = vec![(vec![0 as u8; *i], 0); *o];
|
|
|
|
let base_addr = rng.gen_range(
|
|
module.base().as_u64(),
|
|
module.base().as_u64() + module.size() as u64,
|
|
);
|
|
|
|
while done_size < read_size {
|
|
for (_, addr) in bufs.iter_mut() {
|
|
*addr = base_addr + rng.gen_range(0, 0x2000);
|
|
}
|
|
|
|
let now = Instant::now();
|
|
{
|
|
let mut batcher = proc.virt_mem.virt_batcher();
|
|
|
|
for (buf, addr) in bufs.iter_mut() {
|
|
batcher.read_raw_into(Address::from(*addr), buf);
|
|
}
|
|
}
|
|
total_dur += now.elapsed();
|
|
done_size += *i * *o;
|
|
calls += 1;
|
|
}
|
|
|
|
ttdur += total_dur;
|
|
let total_time = total_dur.as_secs_f64();
|
|
|
|
print!(
|
|
", {:8.2}, {:11.2}",
|
|
(done_size / 0x0010_0000) as f64 / total_time,
|
|
calls as f64 / total_time
|
|
);
|
|
std::io::stdout().flush().expect("");
|
|
}
|
|
println!();
|
|
}
|
|
|
|
let total_dur = start.elapsed();
|
|
println!(
|
|
"Total bench time: {:.2} {:.2}",
|
|
total_dur.as_secs_f64(),
|
|
ttdur.as_secs_f64()
|
|
);
|
|
}
|
|
|
|
fn read_bench<T: PhysicalMemory + ?Sized, V: VirtualTranslate>(
|
|
phys_mem: &mut T,
|
|
vat: &mut V,
|
|
kernel_info: KernelInfo,
|
|
) -> Result<()> {
|
|
let offsets = Win32Offsets::builder().kernel_info(&kernel_info).build()?;
|
|
let mut kernel = Kernel::new(phys_mem, vat, offsets, kernel_info);
|
|
|
|
let proc_list = kernel.process_info_list()?;
|
|
let mut rng = CurRng::seed_from_u64(rand::thread_rng().gen_range(0, !0u64));
|
|
loop {
|
|
let mut prc = Win32Process::with_kernel_ref(
|
|
&mut kernel,
|
|
proc_list[rng.gen_range(0, proc_list.len())].clone(),
|
|
);
|
|
|
|
let mod_list: Vec<Win32ModuleInfo> = prc
|
|
.module_list()?
|
|
.into_iter()
|
|
.filter(|module| module.size() > 0x1000)
|
|
.collect();
|
|
|
|
if !mod_list.is_empty() {
|
|
let tmod = &mod_list[rng.gen_range(0, mod_list.len())];
|
|
println!(
|
|
"Found test module {} ({:x}) in {}",
|
|
tmod.name(),
|
|
tmod.size(),
|
|
prc.proc_info.name(),
|
|
);
|
|
|
|
let mem_map = prc.virt_mem.virt_page_map(size::gb(1));
|
|
|
|
println!("Memory map (with up to 1GB gaps):");
|
|
|
|
for (addr, len) in mem_map {
|
|
println!("{:x}-{:x}", addr, addr + len);
|
|
}
|
|
|
|
rwtest(
|
|
&mut prc,
|
|
tmod,
|
|
&[0x10000, 0x1000, 0x100, 0x10, 0x8],
|
|
&[32, 8, 1],
|
|
0x0010_0000 * 32,
|
|
);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let matches = App::new("read_keys example")
|
|
.version(crate_version!())
|
|
.author(crate_authors!())
|
|
.arg(Arg::with_name("verbose").short("v").multiple(true))
|
|
.arg(
|
|
Arg::with_name("connector")
|
|
.long("connector")
|
|
.short("c")
|
|
.takes_value(true)
|
|
.required(true),
|
|
)
|
|
.arg(
|
|
Arg::with_name("args")
|
|
.long("args")
|
|
.short("a")
|
|
.takes_value(true)
|
|
.default_value(""),
|
|
)
|
|
.get_matches();
|
|
|
|
// set log level
|
|
let level = match matches.occurrences_of("verbose") {
|
|
0 => Level::Error,
|
|
1 => Level::Warn,
|
|
2 => Level::Info,
|
|
3 => Level::Debug,
|
|
4 => Level::Trace,
|
|
_ => Level::Trace,
|
|
};
|
|
simple_logger::SimpleLogger::new()
|
|
.with_level(level.to_level_filter())
|
|
.init()
|
|
.unwrap();
|
|
|
|
// create inventory + connector
|
|
let inventory = unsafe { ConnectorInventory::scan() };
|
|
let mut connector = unsafe {
|
|
inventory.create_connector(
|
|
matches.value_of("connector").unwrap(),
|
|
&ConnectorArgs::parse(matches.value_of("args").unwrap()).unwrap(),
|
|
)
|
|
}
|
|
.unwrap();
|
|
|
|
// scan for win32 kernel
|
|
let kernel_info = KernelInfo::scanner(&mut connector).scan()?;
|
|
|
|
let mut vat = DirectTranslate::new();
|
|
|
|
println!("Benchmarking uncached reads:");
|
|
read_bench(&mut connector, &mut vat, kernel_info.clone()).unwrap();
|
|
|
|
println!();
|
|
println!("Benchmarking cached reads:");
|
|
let mut mem_cached = CachedMemoryAccess::builder(&mut connector)
|
|
.arch(kernel_info.start_block.arch)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut vat_cached = CachedVirtualTranslate::builder(vat)
|
|
.arch(kernel_info.start_block.arch)
|
|
.build()
|
|
.unwrap();
|
|
|
|
read_bench(&mut mem_cached, &mut vat_cached, kernel_info).unwrap();
|
|
|
|
println!("TLB Hits {}\nTLB Miss {}", vat_cached.hitc, vat_cached.misc);
|
|
|
|
Ok(())
|
|
}
|