From 5619048a4a14a9d35759f0920508eaefc81b29f9 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 22 Jun 2020 17:45:06 +0700 Subject: [PATCH] Update lpus feature Traverse scan - PsActiveProcessHead - PsLoadedModuleList - KiProcessListHead - HandleTableList pdb_store has dt(struct) to display struct --- src/bin/eprocess_traverse.rs | 33 +++++ src/bin/kernel_module_traverse.rs | 20 +++ src/bin/print_pdb.rs | 34 +++++ src/lib.rs | 205 ++++++++++++++++++++++++++++++ src/pdb_store.rs | 23 ++++ 5 files changed, 315 insertions(+) create mode 100644 src/bin/eprocess_traverse.rs create mode 100644 src/bin/kernel_module_traverse.rs diff --git a/src/bin/eprocess_traverse.rs b/src/bin/eprocess_traverse.rs new file mode 100644 index 0000000..a66857d --- /dev/null +++ b/src/bin/eprocess_traverse.rs @@ -0,0 +1,33 @@ +use std::error::Error; + +use lpus::{ + driver_state::{DriverState}, + traverse_activehead, + traverse_kiprocesslist, + traverse_handletable +}; + +fn main() -> Result<(), Box> { + let mut driver = DriverState::new(); + println!("NtLoadDriver() -> 0x{:x}", driver.startup()); + + let activehead = traverse_activehead(&driver).unwrap_or(Vec::new()); + let kiprocesslist = traverse_kiprocesslist(&driver).unwrap_or(Vec::new()); + let handletable = traverse_handletable(&driver).unwrap_or(Vec::new()); + + for r in activehead.iter() { + println!("{:#}", r.to_string()); + } + println!("========================================="); + for r in kiprocesslist.iter() { + println!("{:#}", r.to_string()); + } + println!("========================================="); + for r in handletable.iter() { + println!("{:#}", r.to_string()); + } + + println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); + Ok(()) +} + diff --git a/src/bin/kernel_module_traverse.rs b/src/bin/kernel_module_traverse.rs new file mode 100644 index 0000000..d88baea --- /dev/null +++ b/src/bin/kernel_module_traverse.rs @@ -0,0 +1,20 @@ +use std::error::Error; + +use lpus::{ + driver_state::{DriverState}, + traverse_loadedmodulelist +}; + +fn main() -> Result<(), Box> { + let mut driver = DriverState::new(); + println!("NtLoadDriver() -> 0x{:x}", driver.startup()); + + let result = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new()); + + for r in result.iter() { + println!("{:#}", r.to_string()); + } + + println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown()); + Ok(()) +} diff --git a/src/bin/print_pdb.rs b/src/bin/print_pdb.rs index 2009034..ec2b91e 100644 --- a/src/bin/print_pdb.rs +++ b/src/bin/print_pdb.rs @@ -1,6 +1,9 @@ use std::error::Error; // use std::time::{SystemTime, UNIX_EPOCH}; +use rustyline::error::ReadlineError; +use rustyline::Editor; + use lpus::{ driver_state::{DriverState}, }; @@ -22,5 +25,36 @@ fn main() -> Result<(), Box> { driver.windows_ffi.print_version(); driver.pdb_store.print_default_information(); + let mut rl = Editor::<()>::new(); + if rl.load_history("history.lpus").is_err() { + println!("No previous history."); + } + loop { + let readline = rl.readline(">> "); + match readline { + Ok(line) => { + rl.add_history_entry(line.as_str()); + println!("Line: {}", line); + // TODO: add parser here + if let Err(e) = driver.pdb_store.dt(&line) { + println!("{}", e); + } + }, + Err(ReadlineError::Interrupted) => { + println!("CTRL-C"); + break + }, + Err(ReadlineError::Eof) => { + println!("CTRL-D"); + break + }, + Err(err) => { + println!("Error: {:?}", err); + break + } + } + } + rl.save_history("history.lpus").unwrap(); + Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 6cb7d96..8e75acb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -323,3 +323,208 @@ pub fn scan_kernel_module(driver: &DriverState) -> BoxResult> { Ok(result) } + +pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult> { + let mut result: Vec = Vec::new(); + + let ntosbase = driver.get_kernel_base(); + let module_list_head = ntosbase + driver.pdb_store.get_offset_r("PsLoadedModuleList")?; + + let mut ptr: u64 = driver.decompose(&module_list_head, "_LIST_ENTRY.Flink")?; + while ptr != module_list_head.address() { + let mod_addr = Address::from_base(ptr); + + let dllbase: u64 = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.DllBase")?; + let entry: u64 = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.EntryPoint")?; + let size: u64 = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.SizeOfImage")?; + let fullname_ptr = driver.address_of(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.FullDllName")?; + let basename_ptr = driver.address_of(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.BaseDllName")?; + + let fullname = driver.get_unicode_string(fullname_ptr) + .unwrap_or("".to_string()); + let basename = driver.get_unicode_string(basename_ptr) + .unwrap_or("".to_string()); + result.push(json!({ + "address": format!("0x{:x}", mod_addr.address()), + "type": "_KLDR_DATA_TABLE_ENTRY", + "dllbase": format!("0x{:x}", dllbase), + "entry": format!("0x{:x}", entry), + "size": format!("0x{:x}", size), + "FullName": fullname, + "BaseName": basename + })); + + ptr = driver.decompose(&mod_addr, "_KLDR_DATA_TABLE_ENTRY.InLoadOrderLinks.Flink")?; + } + + Ok(result) +} + +// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(nt!PsActiveProcessHead), "nt!_EPROCESS", "ActiveProcessLinks") +pub fn traverse_activehead(driver: &DriverState) -> BoxResult> { + let mut result: Vec = Vec::new(); + + let ntosbase = driver.get_kernel_base(); + let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?; + let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?; + + let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?; + while ptr != process_list_head.address() { + let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset); + + let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?; + let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?; + let image_name: Vec = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?; + let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?; + + let eprocess_name = + if let Ok(name) = from_utf8(&image_name) { + name.to_string().trim_end_matches(char::from(0)).to_string() + } else { + "".to_string() + }; + let binary_path = driver.get_unicode_string(unicode_str_ptr) + .unwrap_or("".to_string()); + + result.push(json!({ + "address": format!("0x{:x}", &eprocess_ptr.address()), + "type": "_EPROCESS", + "pid": pid, + "ppid": ppid, + "name": eprocess_name, + "path": binary_path + })); + + ptr = driver.decompose(&eprocess_ptr, "_EPROCESS.ActiveProcessLinks.Flink")?; + } + + Ok(result) +} + +// TODO: where is afd! +// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(afd!AfdEndpointListHead), "nt!_EPROCESS", "ActiveProcessLinks") +// pub fn traverse_afdendpoint(driver: &DriverState) -> BoxResult> { +// let mut result: Vec = Vec::new(); +// +// let ntosbase = driver.get_kernel_base(); +// let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?; +// let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?; +// +// let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?; +// while ptr != process_list_head.address() { +// let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset); +// +// let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?; +// let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?; +// let image_name: Vec = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?; +// let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?; +// +// let eprocess_name = +// if let Ok(name) = from_utf8(&image_name) { +// name.to_string().trim_end_matches(char::from(0)).to_string() +// } else { +// "".to_string() +// }; +// let binary_path = driver.get_unicode_string(unicode_str_ptr) +// .unwrap_or("".to_string()); +// +// result.push(json!({ +// "address": format!("0x{:x}", &eprocess_ptr.address()), +// "type": "_EPROCESS", +// "pid": pid, +// "ppid": ppid, +// "name": eprocess_name, +// "path": binary_path +// })); +// +// ptr = driver.decompose(&eprocess_ptr, "_EPROCESS.ActiveProcessLinks.Flink")?; +// } +// +// Ok(result) +// } + +// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(nt!KiProcessListHead), "nt!_KPROCESS", "ProcessListEntry").Select( p => new {Process = (nt!_EPROCESS*)&p ) +pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult> { + let mut result: Vec = Vec::new(); + + let ntosbase = driver.get_kernel_base(); + let process_list_head = ntosbase + driver.pdb_store.get_offset_r("KiProcessListHead")?; + let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_KPROCESS.ProcessListEntry")?; + + let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?; + while ptr != process_list_head.address() { + let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset); + + let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?; + let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?; + let image_name: Vec = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?; + let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?; + + let eprocess_name = + if let Ok(name) = from_utf8(&image_name) { + name.to_string().trim_end_matches(char::from(0)).to_string() + } else { + "".to_string() + }; + let binary_path = driver.get_unicode_string(unicode_str_ptr) + .unwrap_or("".to_string()); + + result.push(json!({ + "address": format!("0x{:x}", &eprocess_ptr.address()), + "type": "_EPROCESS", + "pid": pid, + "ppid": ppid, + "name": eprocess_name, + "path": binary_path + })); + + ptr = driver.decompose(&eprocess_ptr, "_KPROCESS.ProcessListEntry.Flink")?; + } + + Ok(result) +} + +// dx Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead, "nt!_HANDLE_TABLE", "HandleTableList").Where(h => h.QuotaProcess != 0).Select( qp => new {Process= qp.QuotaProcess} ) +pub fn traverse_handletable(driver: &DriverState) -> BoxResult> { + let mut result: Vec = Vec::new(); + + let ntosbase = driver.get_kernel_base(); + let process_list_head = ntosbase + driver.pdb_store.get_offset_r("HandleTableListHead")?; + let handle_list_offset = driver.pdb_store.get_offset_r("_HANDLE_TABLE.HandleTableList")?; + + let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?; + while ptr != process_list_head.address() { + let handle_ptr = Address::from_base(ptr - handle_list_offset); + let quota_process: u64 = driver.decompose(&handle_ptr, "_HANDLE_TABLE.QuotaProcess")?; + + if quota_process != 0 { + let eprocess_ptr = Address::from_base(quota_process); + let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?; + let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?; + let image_name: Vec = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?; + let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?; + + let eprocess_name = + if let Ok(name) = from_utf8(&image_name) { + name.to_string().trim_end_matches(char::from(0)).to_string() + } else { + "".to_string() + }; + let binary_path = driver.get_unicode_string(unicode_str_ptr) + .unwrap_or("".to_string()); + + result.push(json!({ + "address": format!("0x{:x}", &eprocess_ptr.address()), + "type": "_EPROCESS", + "pid": pid, + "ppid": ppid, + "name": eprocess_name, + "path": binary_path + })); + } + + ptr = driver.decompose(&handle_ptr, "_HANDLE_TABLE.HandleTableList.Flink")?; + } + + Ok(result) +} diff --git a/src/pdb_store.rs b/src/pdb_store.rs index f451450..2876615 100644 --- a/src/pdb_store.rs +++ b/src/pdb_store.rs @@ -194,6 +194,29 @@ impl PdbStore { } } } + + pub fn dt(&self, struct_name: &str) -> BoxResult<()> { + let member_info = self.structs.get(struct_name).ok_or(format!("no struct named {}", struct_name))?; + let (_, struct_size) = member_info.get("struct_size").ok_or("")?; + println!("// 0x{:x} bytes", struct_size); + println!("struct {} {{", struct_name); + + // Vec<(offset, type, name)> + let mut members: Vec<(u64, String, String)> = Vec::new(); + for (name, (t, offset)) in member_info.iter() { + if name != "struct_size" { + members.push((*offset, t.to_string(), name.to_string())); + } + } + members.sort_by(|(o1,_,_), (o2,_,_)| o1.partial_cmp(o2).unwrap()); + + for (offset, memtype, member) in members.iter() { + println!(" +0x{:x} {} {};", offset, memtype, member); + } + + println!("}} // {}", struct_name); + Ok(()) + } } fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {