Cleaned up code, updated Readme and added the option to load custom memory maps via the arguments

pull/7/head
ko1N 4 years ago
parent 9a90bf5dd9
commit 4c176636d1

@ -7,3 +7,6 @@ default-members = [
"leechcore-sys", "leechcore-sys",
"memflow-pcileech", "memflow-pcileech",
] ]
[profile.release]
lto = true

@ -9,11 +9,23 @@ More information about pcileech can be found under https://github.com/ufrisk/pci
## Compilation ## Compilation
- Make sure the git submodule is checked out First make sure that the `leechcore` submodule is checked out:
- Make sure gcc, clang, libusb-1.0 are installed (on windows you can use chocolatey) ```
- Run `cargo build --release` git submodule init
git submodule sync
git submodule update
```
Install the following build tools:
- gcc
- clang
- libusb-1.0 (only required on linux)
On Windows you additionally need to supply the proprietary FTD3XX.dll.
This project uses libusb to interface with the ftdi chip over usb. Make sure you have the appropiate headers installed. More information about the libusb implementation can be found in the https://github.com/a1ien/rusb project. On Linux you need to check-out and compile the `leechcore_ft601_driver_linux` project from the [LeechCore-Plugins](https://github.com/ufrisk/LeechCore-plugins) repository.
More information about these requirements can be found in the [LeechCore-Plugins](https://github.com/ufrisk/LeechCore-plugins) repository.
### Using the install script ### Using the install script
@ -40,6 +52,28 @@ To compile a dynamic library as a plugin use the following command:
```cargo build --release --all-features``` ```cargo build --release --all-features```
## Arguments
The following arguments can be used when loading the connector:
- `device` - the name of the pcileech device to open (e.g. FPGA) (default argument, required)
- `memmap` - a file that contains a custom memory map in TOML format (optional)
The memory map file must contain a mapping table in the following format:
```toml
[[range]]
base=0x1000
length=0x1000
[[range]]
base=0x2000
length=0x1000
real_base=0x3000
```
The `real_base` parameter is optional. If it is not set there will be no re-mapping.
## License ## License
Licensed under MIT License, see [LICENSE](LICENSE). Licensed under MIT License, see [LICENSE](LICENSE).

@ -1,8 +1,10 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(clippy::useless_transmute)] #![allow(non_camel_case_types)]
#![allow(clippy::cognitive_complexity)] #![allow(improper_ctypes)]
#![allow(clippy::missing_safety_doc)] #![allow(clippy::missing_safety_doc)]
//#![allow(clippy::useless_transmute)]
//#![allow(clippy::cognitive_complexity)]
include!(concat!(env!("OUT_DIR"), "/leechcore.rs")); include!(concat!(env!("OUT_DIR"), "/leechcore.rs"));

@ -16,8 +16,8 @@ categories = [ "api-bindings", "memory-management", "os" ]
crate-type = ["lib", "cdylib"] crate-type = ["lib", "cdylib"]
[dependencies] [dependencies]
memflow = { version = "0.1", features = ["inventory"] } memflow = { git = "https://github.com/memflow/memflow", branch = "dev", features = ["inventory", "serde_derive"] }
memflow-derive = { version = "0.1" } memflow-derive = { git = "https://github.com/memflow/memflow", branch = "dev" }
log = { version = "0.4", default-features = false } log = { version = "0.4", default-features = false }
leechcore-sys = { path = "../leechcore-sys" } leechcore-sys = { path = "../leechcore-sys" }
@ -25,12 +25,8 @@ leechcore-sys = { path = "../leechcore-sys" }
libc = "0.2" libc = "0.2"
[dev-dependencies] [dev-dependencies]
clap = "2.33"
simple_logger = "1.0" simple_logger = "1.0"
[profile.release]
lto = true
[features] [features]
default = [] default = []
inventory = [] inventory = []

@ -1,3 +1,4 @@
use std::env;
use std::time::Instant; use std::time::Instant;
use log::{info, Level}; use log::{info, Level};
@ -5,41 +6,27 @@ use log::{info, Level};
use memflow::*; use memflow::*;
fn main() { fn main() {
simple_logger::init_with_level(Level::Debug).unwrap(); simple_logger::SimpleLogger::new()
.with_level(Level::Debug.to_level_filter())
// TODO: parse command-line args .init()
/* .unwrap();
let mut conn = match memflow_pcileech::create_connector(
&ConnectorArgs::parse("name=win10,type=kvm").unwrap(),
) {
Ok(br) => br,
Err(e) => {
info!("couldn't open memory read context: {:?}", e);
return;
}
};
*/
let mut conn = memflow_pcileech::PciLeech::new("FPGA").unwrap();
info!("conn: {:?}", conn);
let addr = Address::from(0x1000); let args: Vec<String> = env::args().collect();
let mut mem = vec![0; 8]; println!("{:?}", args);
conn.phys_read_raw_into(addr.into(), &mut mem).unwrap(); let conn_args = if args.len() > 1 {
info!("Received memory: {:?}", mem); ConnectorArgs::parse(&args[1]).expect("unable to parse arguments")
} else {
ConnectorArgs::new()
};
/* let mut conn = memflow_pcileech::create_connector(&conn_args)
// write .expect("unable to initialize memflow_pcileech");
mem[0] = 123;
//mem[5] = 123;
conn.phys_write_raw((addr + 5).into(), &mut mem[..1])
.unwrap();
// re-read let addr = Address::from(0x1000);
let mut mem = vec![0; 16];
conn.phys_read_raw_into(addr.into(), &mut mem).unwrap(); conn.phys_read_raw_into(addr.into(), &mut mem).unwrap();
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 {
@ -56,5 +43,4 @@ fn main() {
} }
} }
} }
*/
} }

@ -2,11 +2,11 @@
use std::ffi::c_void; use std::ffi::c_void;
use std::os::raw::c_char; use std::os::raw::c_char;
use std::path::Path;
use std::ptr; use std::ptr;
use std::slice;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use log::{error, info, warn}; use log::{error, info};
use memflow::*; use memflow::*;
use memflow_derive::connector; use memflow_derive::connector;
@ -14,20 +14,19 @@ use memflow_derive::connector;
use leechcore_sys::*; use leechcore_sys::*;
const PAGE_SIZE: usize = 0x1000usize; const PAGE_SIZE: usize = 0x1000usize;
const BUF_ALIGN: u64 = 4; const BUF_ALIGN: u64 = 4;
const BUF_MIN_LEN: usize = 8; const BUF_MIN_LEN: usize = 8;
const BUF_LEN_ALIGN: usize = 8; const BUF_LEN_ALIGN: usize = 8;
const fn calc_num_pages(start: u64, size: u64) -> u64 {
((start & (PAGE_SIZE as u64 - 1)) + size + (PAGE_SIZE as u64 - 1)) >> 12
}
fn build_lc_config(device: &str) -> LC_CONFIG { fn build_lc_config(device: &str) -> LC_CONFIG {
let cdevice = unsafe { &*(device.as_bytes() as *const [u8] as *const [c_char]) }; let cdevice = unsafe { &*(device.as_bytes() as *const [u8] as *const [c_char]) };
let mut adevice: [c_char; 260] = [0; 260]; let mut adevice: [c_char; 260] = [0; 260];
adevice[..device.len().min(260)].copy_from_slice(&cdevice[..device.len().min(260)]); adevice[..device.len().min(260)].copy_from_slice(&cdevice[..device.len().min(260)]);
let cfg = LC_CONFIG { // TODO: copy device + remote
LC_CONFIG {
dwVersion: LC_CONFIG_VERSION, dwVersion: LC_CONFIG_VERSION,
dwPrintfVerbosity: LC_CONFIG_PRINTF_ENABLED | LC_CONFIG_PRINTF_V | LC_CONFIG_PRINTF_VV, dwPrintfVerbosity: LC_CONFIG_PRINTF_ENABLED | LC_CONFIG_PRINTF_V | LC_CONFIG_PRINTF_VV,
szDevice: adevice, szDevice: adevice,
@ -39,11 +38,11 @@ fn build_lc_config(device: &str) -> LC_CONFIG {
fRemote: 0, fRemote: 0,
fRemoteDisableCompress: 0, fRemoteDisableCompress: 0,
szDeviceName: [0; 260], szDeviceName: [0; 260],
}; }
}
// TODO: copy device + remote
cfg const fn calc_num_pages(start: u64, size: u64) -> u64 {
((start & (PAGE_SIZE as u64 - 1)) + size + (PAGE_SIZE as u64 - 1)) >> 12
} }
#[derive(Debug)] #[derive(Debug)]
@ -59,7 +58,7 @@ impl Clone for PciLeech {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
handle: self.handle.clone(), handle: self.handle.clone(),
metadata: self.metadata.clone(), metadata: self.metadata,
mem_map: self.mem_map.clone(), mem_map: self.mem_map.clone(),
} }
} }
@ -68,11 +67,20 @@ impl Clone for PciLeech {
// TODO: proper drop + free impl -> LcMemFree(pLcErrorInfo); // TODO: proper drop + free impl -> LcMemFree(pLcErrorInfo);
impl PciLeech { impl PciLeech {
pub fn new(device: &str) -> Result<Self> { pub fn new(device: &str) -> Result<Self> {
Self::with_map(device, MemoryMap::new()) Self::with_mapping(device, MemoryMap::new())
}
pub fn with_memmap<P: AsRef<Path>>(device: &str, path: P) -> Result<Self> {
info!(
"loading memory mappings from file: {}",
path.as_ref().to_string_lossy()
);
let memmap = MemoryMap::open(path)?;
info!("{:?}", memmap);
Self::with_mapping(device, memmap)
} }
// TODO: load a memory map via the arguments fn with_mapping(device: &str, mem_map: MemoryMap<(Address, usize)>) -> Result<Self> {
pub fn with_map(device: &str, mem_map: MemoryMap<(Address, usize)>) -> Result<Self> {
// open device // open device
let mut conf = build_lc_config(device); let mut conf = build_lc_config(device);
let err = std::ptr::null_mut::<PLC_CONFIG_ERRORINFO>(); let err = std::ptr::null_mut::<PLC_CONFIG_ERRORINFO>();
@ -88,7 +96,7 @@ impl PciLeech {
handle: Arc::new(Mutex::new(handle)), handle: Arc::new(Mutex::new(handle)),
metadata: PhysicalMemoryMetadata { metadata: PhysicalMemoryMetadata {
size: conf.paMax as usize, size: conf.paMax as usize,
readonly: if conf.fVolatile == 0 { true } else { false }, readonly: conf.fVolatile == 0,
// TODO: writable flag // TODO: writable flag
}, },
mem_map, mem_map,
@ -124,7 +132,7 @@ impl PhysicalMemory for PciLeech {
let mut i = 0usize; let mut i = 0usize;
for read in data.iter_mut() { for read in data.iter_mut() {
for (page_addr, out) in read.1.page_chunks(read.0.into(), PAGE_SIZE) { for (page_addr, out) in read.1.page_chunks(read.0.into(), PAGE_SIZE) {
let mem = unsafe { *mems.offset(i as isize) }; let mem = unsafe { *mems.add(i) };
let addr_align = page_addr.as_u64() & (BUF_ALIGN - 1); let addr_align = page_addr.as_u64() & (BUF_ALIGN - 1);
let len_align = out.len() & (BUF_LEN_ALIGN - 1); let len_align = out.len() & (BUF_LEN_ALIGN - 1);
@ -162,7 +170,7 @@ impl PhysicalMemory for PciLeech {
i = 0usize; i = 0usize;
for read in data.iter_mut() { for read in data.iter_mut() {
for (page_addr, out) in read.1.page_chunks(read.0.into(), PAGE_SIZE) { for (page_addr, out) in read.1.page_chunks(read.0.into(), PAGE_SIZE) {
let mem = unsafe { *mems.offset(i as isize) }; let mem = unsafe { *mems.add(i) };
let addr_align = page_addr.as_u64() & (BUF_ALIGN - 1); let addr_align = page_addr.as_u64() & (BUF_ALIGN - 1);
let len_align = out.len() & (BUF_LEN_ALIGN - 1); let len_align = out.len() & (BUF_LEN_ALIGN - 1);
@ -216,7 +224,7 @@ impl PhysicalMemory for PciLeech {
let mut i = 0usize; let mut i = 0usize;
for write in data.iter() { for write in data.iter() {
for (page_addr, out) in write.1.page_chunks(write.0.into(), PAGE_SIZE) { for (page_addr, out) in write.1.page_chunks(write.0.into(), PAGE_SIZE) {
let mem = unsafe { *mems.offset(i as isize) }; let mem = unsafe { *mems.add(i) };
let addr_align = page_addr.as_u64() & (BUF_ALIGN - 1); let addr_align = page_addr.as_u64() & (BUF_ALIGN - 1);
let len_align = out.len() & (BUF_LEN_ALIGN - 1); let len_align = out.len() & (BUF_LEN_ALIGN - 1);
@ -227,6 +235,8 @@ impl PhysicalMemory for PciLeech {
unsafe { (*mem).pb = out.as_ptr() as *mut u8 }; unsafe { (*mem).pb = out.as_ptr() as *mut u8 };
unsafe { (*mem).cb = out.len() as u32 }; unsafe { (*mem).cb = out.len() as u32 };
} else { } else {
// TODO: dispatch all necessary reads into 1 batch
// non-aligned or small read // non-aligned or small read
let mut buffer_len = (out.len() + addr_align as usize).max(BUF_MIN_LEN); let mut buffer_len = (out.len() + addr_align as usize).max(BUF_MIN_LEN);
buffer_len += BUF_LEN_ALIGN - (buffer_len & (BUF_LEN_ALIGN - 1)); buffer_len += BUF_LEN_ALIGN - (buffer_len & (BUF_LEN_ALIGN - 1));
@ -257,6 +267,8 @@ impl PhysicalMemory for PciLeech {
} }
} }
// TODO: unleak memory from Box::into_raw()
// free temporary buffers // free temporary buffers
unsafe { unsafe {
LcMemFree(mems as *mut c_void); LcMemFree(mems as *mut c_void);
@ -266,7 +278,7 @@ impl PhysicalMemory for PciLeech {
} }
fn metadata(&self) -> PhysicalMemoryMetadata { fn metadata(&self) -> PhysicalMemoryMetadata {
self.metadata.clone() self.metadata
} }
} }
@ -277,5 +289,10 @@ pub fn create_connector(args: &ConnectorArgs) -> Result<PciLeech> {
.get("device") .get("device")
.or_else(|| args.get_default()) .or_else(|| args.get_default())
.ok_or(Error::Connector("argument 'device' missing"))?; .ok_or(Error::Connector("argument 'device' missing"))?;
if let Some(memmap) = args.get("memmap") {
PciLeech::with_memmap(device, memmap)
} else {
PciLeech::new(device) PciLeech::new(device)
}
} }

Loading…
Cancel
Save