Update lpus feature
Traverse scan - PsActiveProcessHead - PsLoadedModuleList - KiProcessListHead - HandleTableList pdb_store has dt(struct) to display struct
This commit is contained in:
parent
8cf91aef79
commit
5619048a4a
33
src/bin/eprocess_traverse.rs
Normal file
33
src/bin/eprocess_traverse.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use lpus::{
|
||||||
|
driver_state::{DriverState},
|
||||||
|
traverse_activehead,
|
||||||
|
traverse_kiprocesslist,
|
||||||
|
traverse_handletable
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
|
20
src/bin/kernel_module_traverse.rs
Normal file
20
src/bin/kernel_module_traverse.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use lpus::{
|
||||||
|
driver_state::{DriverState},
|
||||||
|
traverse_loadedmodulelist
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
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(())
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
// use std::time::{SystemTime, UNIX_EPOCH};
|
// use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
use rustyline::error::ReadlineError;
|
||||||
|
use rustyline::Editor;
|
||||||
|
|
||||||
use lpus::{
|
use lpus::{
|
||||||
driver_state::{DriverState},
|
driver_state::{DriverState},
|
||||||
};
|
};
|
||||||
@ -22,5 +25,36 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
driver.windows_ffi.print_version();
|
driver.windows_ffi.print_version();
|
||||||
driver.pdb_store.print_default_information();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
205
src/lib.rs
205
src/lib.rs
@ -323,3 +323,208 @@ pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
|
let mut result: Vec<Value> = 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<Vec<Value>> {
|
||||||
|
let mut result: Vec<Value> = 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<u8> = 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<Vec<Value>> {
|
||||||
|
// let mut result: Vec<Value> = 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<u8> = 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<Vec<Value>> {
|
||||||
|
let mut result: Vec<Value> = 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<u8> = 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<Vec<Value>> {
|
||||||
|
let mut result: Vec<Value> = 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<u8> = 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)
|
||||||
|
}
|
||||||
|
@ -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 {
|
fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
|
||||||
|
Loading…
Reference in New Issue
Block a user