diff --git a/Cargo.lock b/Cargo.lock index c6561a8..fa2d373 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,17 @@ name = "anyhow" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "app_dirs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "1.0.0" @@ -341,6 +352,7 @@ dependencies = [ name = "lpus" version = "0.1.0" dependencies = [ + "app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "pdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -464,6 +476,15 @@ dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ole32-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "openssl" version = "0.10.28" @@ -762,6 +783,15 @@ dependencies = [ "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "shell32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.2" @@ -1099,8 +1129,14 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" +"checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" @@ -1157,6 +1193,7 @@ dependencies = [ "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)" = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)" = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" @@ -1191,6 +1228,7 @@ dependencies = [ "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" "checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" +"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" "checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" @@ -1233,3 +1271,4 @@ dependencies = [ "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" diff --git a/Cargo.toml b/Cargo.toml index 2fbe7d5..6d54bd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ name = "lpus" doctest = false [dependencies] +app_dirs = "1.2.1" hex = "0.4.2" pdb = "0.5.0" chrono = "0.4" diff --git a/src/bin/eprocess_scan.rs b/src/bin/eprocess_scan.rs index ffe89db..8ff1c9f 100644 --- a/src/bin/eprocess_scan.rs +++ b/src/bin/eprocess_scan.rs @@ -34,14 +34,14 @@ fn main() -> Result<(), Box> { let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?; let eprocess_name_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?; let eprocess_create_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.CreateTime")?; - let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?; + // let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?; let eprocess_valid_start = data_addr; let eprocess_valid_end = (pool_addr + chunk_size) - eprocess_size; let mut try_eprocess_ptr = eprocess_valid_start; let mut create_time = 0u64; - let mut exit_time = 0u64; + // let mut exit_time = 0u64; while try_eprocess_ptr <= eprocess_valid_end { driver.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time); // driver.deref_addr(try_eprocess_ptr + eprocess_exit_time_offset, &mut exit_time); @@ -51,7 +51,7 @@ fn main() -> Result<(), Box> { } try_eprocess_ptr += 0x4; // search exhaustively } - if (try_eprocess_ptr > eprocess_valid_end) { + if try_eprocess_ptr > eprocess_valid_end { return Ok(false); } diff --git a/src/driver_state.rs b/src/driver_state.rs index e7e81ab..87b87e3 100644 --- a/src/driver_state.rs +++ b/src/driver_state.rs @@ -81,7 +81,7 @@ pub struct DriverState { impl DriverState { pub fn new() -> Self { Self { - pdb_store: parse_pdb(), + pdb_store: parse_pdb().expect("Cannot get PDB file"), windows_ffi: WindowsFFI::new() } } diff --git a/src/lib.rs b/src/lib.rs index cda8c7f..4621008 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ extern crate chrono; +extern crate app_dirs; pub mod pdb_store; pub mod windows; diff --git a/src/pdb_store.rs b/src/pdb_store.rs index dc5663e..c61e434 100644 --- a/src/pdb_store.rs +++ b/src/pdb_store.rs @@ -1,26 +1,25 @@ use std::error::Error; use std::io; use std::io::{Read}; -use std::path::Path; +use std::path::{PathBuf}; use std::fs::File; use std::collections::HashMap; -use pdb::PDB; -use pdb::SymbolData; -use pdb::TypeData; -use pdb::ClassType; -use pdb::ModifierType; -use pdb::Rva; +use pdb::{ + PDB, SymbolData, TypeData, ClassType, ModifierType, Rva, + FallibleIterator, TypeFinder, TypeIndex +}; -use pdb::FallibleIterator; -use pdb::TypeFinder; -use pdb::TypeIndex; +use app_dirs::{AppInfo, AppDataType, app_dir}; +const APP_INFO: AppInfo = AppInfo { name: "lpus", author: "nganhkhoa" }; -const PDBNAME: &str = "ntkrnlmp.pdb"; +const KERNEL_PDB_NAME: &str = "ntkrnlmp.pdb"; const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe"; const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols"; +type BoxResult = Result>; + type SymbolStore = HashMap; type StructStore = HashMap>; @@ -30,7 +29,7 @@ pub struct PdbStore { } impl PdbStore { - pub fn get_offset_r(&self, name: &str) -> Result> { + pub fn get_offset_r(&self, name: &str) -> BoxResult { self.get_offset(name) .ok_or(format!("{} is not found in PDB", name).into()) } @@ -57,7 +56,7 @@ impl PdbStore { } #[allow(dead_code)] - pub fn addr_decompose(&self, addr: u64, full_name: &str) -> Result>{ + pub fn addr_decompose(&self, addr: u64, full_name: &str) -> BoxResult{ if !full_name.contains(".") { return Err("Not decomposable".into()); } @@ -258,11 +257,12 @@ fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String { } } -pub fn download_pdb() { - let mut ntoskrnl = File::open(NTOSKRNL_PATH).expect("Cannot open ntoskrnl.exe"); +fn get_guid_age(exe_file: &str) -> BoxResult<(String, u32)>{ + // TODO: Check file existance + let mut file = File::open(exe_file)?; let mut buffer = Vec::new(); - ntoskrnl.read_to_end(&mut buffer).expect("Cannot read file ntoskrnl.exe"); + file.read_to_end(&mut buffer)?; let mut buffiter = buffer.chunks(4); while buffiter.next().unwrap() != [0x52, 0x53, 0x44, 0x53] { @@ -292,37 +292,54 @@ pub fn download_pdb() { raw_age[0], raw_age[1], raw_age[2], raw_age[3] ]); - let downloadurl = format!("{}/{}/{}{:X}/{}", PDB_SERVER_PATH, PDBNAME, guid, age, PDBNAME); - println!("{}", downloadurl); - - let mut resp = reqwest::blocking::get(&downloadurl).expect("request failed"); - let mut out = File::create(PDBNAME).expect("failed to create file"); - io::copy(&mut resp, &mut out).expect("failed to copy content"); + Ok((guid, age)) } -pub fn parse_pdb() -> PdbStore { - // TODO: Detect pdb file and ntoskrnl file version differs +fn pdb_exists(pdbname: &str, guid: &str, age: u32) -> BoxResult<(bool, PathBuf)> { // Use a folder at %APPDATA% to save pdb files - // %APPDATA%\lpus - // |--ntoskrnl + // %APPDATA%\nganhkhoaa\lpus + // |--ntkrnlmp.pdb // |--|--GUID // |--|--|--ntkrnlmp.pdb - // |--file + // |--file.pdb // |--|--GUID // |--|--|--file.pdb - // TODO: Turn function to Result to handle error - if !Path::new(PDBNAME).exists() { - download_pdb(); - } - let f = File::open("ntkrnlmp.pdb").expect("No such file ./ntkrnlmp.pdb"); - let mut pdb = PDB::open(f).expect("Cannot open as a PDB file"); + let mut pdb_location = app_dir(AppDataType::UserData, &APP_INFO, + &format!("{}/{}/{}", pdbname, guid, age))?; + pdb_location.push(pdbname); + Ok((pdb_location.exists(), pdb_location)) +} - let info = pdb.pdb_information().expect("Cannot get pdb information"); - let dbi = pdb.debug_information().expect("cannot get debug information"); +fn download_pdb(pdbname: &str, guid: &str, age: u32, outfile: &PathBuf) -> BoxResult<()> { + let downloadurl = format!("{}/{}/{}{:X}/{}", PDB_SERVER_PATH, pdbname, guid, age, pdbname); + println!("{}", downloadurl); + + let mut resp = reqwest::blocking::get(&downloadurl)?; + let mut out = File::create(outfile)?; + io::copy(&mut resp, &mut out)?; + Ok(()) +} + +pub fn parse_pdb() -> BoxResult { + // TODO: Resolve pdb name + // ntoskrnl.exe -> ntkrnlmp.pdb + // tcpip.sys -> tcpip.pdb ????? + // There may be more pdb files in the future + let (guid, age) = get_guid_age(NTOSKRNL_PATH)?; + let (exists, pdb_path) = pdb_exists(KERNEL_PDB_NAME, &guid, age)?; + if !exists { + println!("PDB not found, download into {:?}", pdb_path); + download_pdb(KERNEL_PDB_NAME, &guid, age, &pdb_path)?; + } + let f = File::open(pdb_path)?; + let mut pdb = PDB::open(f)?; + + let info = pdb.pdb_information()?; + let dbi = pdb.debug_information()?; println!("PDB for {}, guid: {}, age: {}\n", dbi.machine_type().unwrap(), info.guid, dbi.age().unwrap_or(0)); - let type_information = pdb.type_information().expect("Cannot get type information"); + let type_information = pdb.type_information()?; let mut type_finder = type_information.type_finder(); let mut iter = type_information.iter(); while let Some(_typ) = iter.next().unwrap() { @@ -330,8 +347,8 @@ pub fn parse_pdb() -> PdbStore { } let mut symbol_extracted: SymbolStore = HashMap::new(); - let addr_map = pdb.address_map().expect("Cannot get address map"); - let glosym = pdb.global_symbols().expect("Cannot get global symbols"); + let addr_map = pdb.address_map()?; + let glosym = pdb.global_symbols()?; let mut symbols = glosym.iter(); while let Some(symbol) = symbols.next().unwrap() { match symbol.parse() { @@ -370,8 +387,8 @@ pub fn parse_pdb() -> PdbStore { } } - PdbStore { + Ok(PdbStore { symbols: symbol_extracted, structs: struct_extracted - } + }) } diff --git a/src/windows.rs b/src/windows.rs index 5f96b4b..648034f 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -24,7 +24,7 @@ use winapi::um::securitybaseapi::{AdjustTokenPrivileges}; use winapi::um::winbase::{LookupPrivilegeValueA}; use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE}; -const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa"; +const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus"; #[allow(dead_code)] #[derive(Debug, Copy, Clone)] @@ -61,8 +61,8 @@ impl WindowsFFI { let str_rtl_get_version = CString::new("RtlGetVersion").unwrap(); let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").unwrap(); - let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\nganhkhoa.sys").unwrap(); - let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\nganhkhoa").unwrap(); + let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\lpus.sys").unwrap(); + let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\lpus").unwrap(); let str_type = CString::new("Type").unwrap(); let str_error_control = CString::new("ErrorControl").unwrap(); let str_start = CString::new("Start").unwrap();