diff --git a/src/bin/driver_irp.rs b/src/bin/driver_irp.rs index e99cd5b..1637d13 100644 --- a/src/bin/driver_irp.rs +++ b/src/bin/driver_irp.rs @@ -21,12 +21,12 @@ fn main() -> Result<(), Box> { let kmods = scan_kernel_module(&driver).unwrap_or(Vec::new()); for d in drivers.iter() { - println!("{} {}", d["device"], d["address"]); + println!("{} {}", d["address"], d["device"]); } let mut rl = Editor::<()>::new(); loop { - let readline = rl.readline(">> "); + let readline = rl.readline("irp> "); match readline { Ok(line) => { rl.add_history_entry(line.as_str()); @@ -39,9 +39,11 @@ fn main() -> Result<(), Box> { .iter() .enumerate() { + let addr: u64 = + addr_.as_str().and_then(|x| parse(x).ok()).unwrap_or(0); + let mut owner = "(??)"; + println!("{} {}", addr, get_irp_name(idx)); for kmod in kmods.iter() { - let addr: u64 = - addr_.as_str().and_then(|x| parse(x).ok()).unwrap_or(0); let base: u64 = kmod["dllbase"] .as_str() .and_then(|x| parse(x).ok()) @@ -51,15 +53,11 @@ fn main() -> Result<(), Box> { .and_then(|x| parse(x).ok()) .unwrap_or(0); if addr > base && addr < base + size { - println!( - "{} 0x{:x} {}", - get_irp_name(idx), - addr, - kmod["BaseName"] - ); + owner = kmod["BaseName"].as_str().unwrap_or("(??)"); break; } } + println!("\towned by {}", owner); } break; } diff --git a/src/bin/kernel_module_traverse.rs b/src/bin/kernel_module_traverse.rs index 57a6b9c..99a8d3c 100644 --- a/src/bin/kernel_module_traverse.rs +++ b/src/bin/kernel_module_traverse.rs @@ -2,7 +2,9 @@ use std::error::Error; use parse_int::parse; -use lpus::{driver_state::DriverState, traverse_loadedmodulelist, traverse_unloadeddrivers}; +use lpus::{ + driver_state::DriverState, ssdt_table, traverse_loadedmodulelist, traverse_unloadeddrivers, +}; fn main() -> Result<(), Box> { let mut driver = DriverState::new(); @@ -17,31 +19,20 @@ fn main() -> Result<(), Box> { let loaded = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new()); let unloaded = traverse_unloadeddrivers(&driver).unwrap_or(Vec::new()); - - // TODO: move to another place - // From Vol3 SSDT scan - // https://github.com/volatilityfoundation/volatility3/blob/master/volatility/framework/plugins/windows/ssdt.py + let ssdt = ssdt_table(&driver)?; let ntosbase = driver.get_kernel_base(); - let servicetable = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceTable")?; - let servicelimit_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceLimit")?; - let servicelimit = driver.deref_addr_new::(servicelimit_ptr.address()) as u64; - let ssdt: Vec = driver - .deref_array::(&servicetable, servicelimit) - .iter() - .map(|entry| servicetable.address() + ((entry >> 4) as u64)) - .collect(); - - for r in loaded.iter() { - println!("{:#}", r.to_string()); - } + // for r in loaded.iter() { + // println!("{:#}", r.to_string()); + // } println!("============================================="); for r in unloaded.iter() { println!("{:#}", r.to_string()); } println!("============================================="); - for func in ssdt { - for r in loaded.iter() { + for (idx, func) in ssdt.iter().enumerate() { + println!("SSDT [{}]\t0x{:x}", idx, func); + let owner = loaded.iter().find_map(|r| { let base = r["dllbase"] .as_str() .and_then(|b| parse::(b).ok()) @@ -51,26 +42,34 @@ fn main() -> Result<(), Box> { .and_then(|s| parse::(s).ok()) .unwrap_or(0); - if func > base && func < base + size { - let offset = func - ntosbase.address(); - let funcname: String = { - let mut n = "".to_string(); - for (name, o) in driver.pdb_store.symbols.iter() { - if *o == offset { - n = name.clone(); - } - } - if n == "" { - "(??)".to_string() - } else { - n - } - }; - println!("SSDT 0x{:x} {}!{}", func, r["BaseName"], funcname); - break; // next func + if *func > base && *func < base + size { + let module = r["BaseName"].as_str().unwrap(); + Some(module) } + else { + None + } + }); + if owner == Some("ntoskrnl.exe") { + let offset = func - ntosbase.address(); + let funcname: String = { + driver.pdb_store.symbols.iter().find_map(|(name, o)| { + if o.clone() == offset { + Some(name.clone()) + } + else { + None + } + }).unwrap_or("(??)".to_string()) + }; + println!("\towned by nt!{}", funcname); + } + else if let Some(owner_) = owner { + println!("\towned by {}", owner_); + } + else { + println!("\tmissing owner"); } - // TODO: If not found, search other list } println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); diff --git a/src/bin/lpus_all.rs b/src/bin/lpus_all.rs new file mode 100644 index 0000000..58c36c8 --- /dev/null +++ b/src/bin/lpus_all.rs @@ -0,0 +1,52 @@ +use serde_json::{json}; +use std::error::Error; +use std::fs; + + +use lpus::{ + driver_state::DriverState, scan_eprocess, scan_ethread, traverse_activehead, + traverse_handletable, traverse_kiprocesslist, scan_driver, scan_kernel_module, + traverse_loadedmodulelist, traverse_unloadeddrivers, + ssdt_table +}; + +fn main() -> Result<(), Box> { + let mut driver = DriverState::new(); + if !driver.is_supported() { + return Err(format!( + "Windows version {:?} is not supported", + driver.windows_ffi.short_version + ) + .into()); + } + println!("NtLoadDriver() -> 0x{:x}", driver.startup()); + + let eprocess_1 = scan_eprocess(&driver)?; + let eprocess_2 = traverse_activehead(&driver)?; + let eprocess_3 = traverse_kiprocesslist(&driver)?; + let eprocess_4 = traverse_handletable(&driver)?; + let ethread = scan_ethread(&driver)?; + let drivers = scan_driver(&driver)?; + let kernel_module_1 = scan_kernel_module(&driver)?; + let kernel_module_2 = traverse_loadedmodulelist(&driver)?; + let unloaded_driver = traverse_unloadeddrivers(&driver)?; + let ssdt: Vec = ssdt_table(&driver)?.into_iter().map(|x| format!("0x{:x}", x)).collect(); + + let result = json!({ + "scan_eprocess": eprocess_1, + "traverse_activehead": eprocess_2, + "traverse_kiprocesslist": eprocess_3, + "traverse_handletable": eprocess_4, + "scan_ethread": ethread, + "scan_driver": drivers, + "scan_kernel_module": kernel_module_1, + "traverse_loadedmodulelist": kernel_module_2, + "traverse_unloadeddrivers": unloaded_driver, + "ssdt_table": ssdt + }); + + fs::write("./lpus.json", format!("{:#}", result)).ok(); + + println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); + Ok(()) +} diff --git a/src/downloader.rs b/src/downloader.rs new file mode 100644 index 0000000..de278b5 --- /dev/null +++ b/src/downloader.rs @@ -0,0 +1,53 @@ +use std::error::Error; + +use indicatif::{ProgressBar, ProgressStyle}; +use reqwest::{header, Client}; +use std::path::Path; +use structopt::StructOpt; +use tokio::{fs, io::AsyncWriteExt}; + +type BoxResult = Result>; + +async fn download(url: &str, path: &PathBuf) -> BoxResult<()> { + let client = Client::new(); + let total_size = { + let resp = client.head(url).send().await?; + if resp.status().is_success() { + resp.headers() + .get(header::CONTENT_LENGTH) + .and_then(|ct_len| ct_len.to_str().ok()) + .and_then(|ct_len| ct_len.parse().ok()) + .unwrap_or(0) + } else { + return Err(format!("Couldn'n download URL: {}", url)); + } + }; + + let mut request = client.get(url); + let pb = ProgressBar::new(total_size); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{elapsed_precise}] \ + [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})") + .progress_chars("#>-")); + + let file = Path::new(path); + + if file.exists() { + return Err(format!("File {:?} existed", file)); + // let size = file.metadata()?.len().saturating_sub(1); + // request = request.header(header::RANGE, format!("bytes={}-", size)); + // pb.inc(size); + } + + let mut source = request.send().await?; + let mut dest = fs::OpenOptions::new().create(true).append(true).open(&file).await?; + while let Some(chunk) = source.chunk().await? { + dest.write_all(&chunk).await?; + pb.inc(chunk.len() as u64); + } + + println!("Download of '{}' has been completed.", file.to_str().unwrap()); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 1d0e6fe..0a91713 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -566,3 +566,19 @@ pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult> { Ok(result) } + +pub fn ssdt_table(driver: &DriverState) -> BoxResult> { + // https://github.com/volatilityfoundation/volatility3/blob/master/volatility/framework/plugins/windows/ssdt.py + let ntosbase = driver.get_kernel_base(); + let servicetable = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceTable")?; + let servicelimit_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceLimit")?; + + // TODO: Shifting is wrong, Rust seems to do arithmetic shift + let servicelimit = driver.deref_addr_new::(servicelimit_ptr.address()) as u64; + let ssdt: Vec = driver + .deref_array::(&servicetable, servicelimit) + .iter() + .map(|entry| servicetable.address() + ((*entry as u64) >> 4)) + .collect(); + Ok(ssdt) +}