This commit is contained in:
nganhkhoa 2020-07-21 17:07:52 +07:00
parent 60513ee142
commit 2d7576b1e2
5 changed files with 165 additions and 47 deletions

View File

@ -21,12 +21,12 @@ fn main() -> Result<(), Box<dyn Error>> {
let kmods = scan_kernel_module(&driver).unwrap_or(Vec::new()); let kmods = scan_kernel_module(&driver).unwrap_or(Vec::new());
for d in drivers.iter() { for d in drivers.iter() {
println!("{} {}", d["device"], d["address"]); println!("{} {}", d["address"], d["device"]);
} }
let mut rl = Editor::<()>::new(); let mut rl = Editor::<()>::new();
loop { loop {
let readline = rl.readline(">> "); let readline = rl.readline("irp> ");
match readline { match readline {
Ok(line) => { Ok(line) => {
rl.add_history_entry(line.as_str()); rl.add_history_entry(line.as_str());
@ -39,9 +39,11 @@ fn main() -> Result<(), Box<dyn Error>> {
.iter() .iter()
.enumerate() .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() { 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"] let base: u64 = kmod["dllbase"]
.as_str() .as_str()
.and_then(|x| parse(x).ok()) .and_then(|x| parse(x).ok())
@ -51,15 +53,11 @@ fn main() -> Result<(), Box<dyn Error>> {
.and_then(|x| parse(x).ok()) .and_then(|x| parse(x).ok())
.unwrap_or(0); .unwrap_or(0);
if addr > base && addr < base + size { if addr > base && addr < base + size {
println!( owner = kmod["BaseName"].as_str().unwrap_or("(??)");
"{} 0x{:x} {}",
get_irp_name(idx),
addr,
kmod["BaseName"]
);
break; break;
} }
} }
println!("\towned by {}", owner);
} }
break; break;
} }

View File

@ -2,7 +2,9 @@ use std::error::Error;
use parse_int::parse; 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<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let mut driver = DriverState::new(); let mut driver = DriverState::new();
@ -17,31 +19,20 @@ fn main() -> Result<(), Box<dyn Error>> {
let loaded = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new()); let loaded = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new());
let unloaded = traverse_unloadeddrivers(&driver).unwrap_or(Vec::new()); let unloaded = traverse_unloadeddrivers(&driver).unwrap_or(Vec::new());
let ssdt = ssdt_table(&driver)?;
// TODO: move to another place
// From Vol3 SSDT scan
// https://github.com/volatilityfoundation/volatility3/blob/master/volatility/framework/plugins/windows/ssdt.py
let ntosbase = driver.get_kernel_base(); 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::<u32>(servicelimit_ptr.address()) as u64; // for r in loaded.iter() {
let ssdt: Vec<u64> = driver // println!("{:#}", r.to_string());
.deref_array::<u32>(&servicetable, servicelimit) // }
.iter()
.map(|entry| servicetable.address() + ((entry >> 4) as u64))
.collect();
for r in loaded.iter() {
println!("{:#}", r.to_string());
}
println!("============================================="); println!("=============================================");
for r in unloaded.iter() { for r in unloaded.iter() {
println!("{:#}", r.to_string()); println!("{:#}", r.to_string());
} }
println!("============================================="); println!("=============================================");
for func in ssdt { for (idx, func) in ssdt.iter().enumerate() {
for r in loaded.iter() { println!("SSDT [{}]\t0x{:x}", idx, func);
let owner = loaded.iter().find_map(|r| {
let base = r["dllbase"] let base = r["dllbase"]
.as_str() .as_str()
.and_then(|b| parse::<u64>(b).ok()) .and_then(|b| parse::<u64>(b).ok())
@ -51,26 +42,34 @@ fn main() -> Result<(), Box<dyn Error>> {
.and_then(|s| parse::<u64>(s).ok()) .and_then(|s| parse::<u64>(s).ok())
.unwrap_or(0); .unwrap_or(0);
if func > base && func < base + size { if *func > base && *func < base + size {
let offset = func - ntosbase.address(); let module = r["BaseName"].as_str().unwrap();
let funcname: String = { Some(module)
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
} }
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()); println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());

52
src/bin/lpus_all.rs Normal file
View File

@ -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<dyn Error>> {
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<String> = 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(())
}

53
src/downloader.rs Normal file
View File

@ -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<T> = Result<T, Box<dyn Error>>;
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(())
}

View File

@ -566,3 +566,19 @@ pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult<Vec<Value>> {
Ok(result) Ok(result)
} }
pub fn ssdt_table(driver: &DriverState) -> BoxResult<Vec<u64>> {
// 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::<u32>(servicelimit_ptr.address()) as u64;
let ssdt: Vec<u64> = driver
.deref_array::<u32>(&servicetable, servicelimit)
.iter()
.map(|entry| servicetable.address() + ((*entry as u64) >> 4))
.collect();
Ok(ssdt)
}