From 30da3fe60ac65d8c4b3e819ac553d2a4fd8d9264 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Sun, 23 Feb 2020 02:04:09 +0700 Subject: [PATCH 1/4] load driver code --- Cargo.lock | 15 +++ Cargo.toml | 4 +- src/main.rs | 299 +++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 255 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9a8b45..b777d89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -197,6 +197,11 @@ dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "http" version = "0.2.0" @@ -454,8 +459,11 @@ dependencies = [ name = "parse_pdb_for_offsets" version = "0.1.0" dependencies = [ + "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)", "reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1012,6 +1020,11 @@ dependencies = [ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "widestring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.2.8" @@ -1088,6 +1101,7 @@ dependencies = [ "checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b" "checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" @@ -1180,6 +1194,7 @@ dependencies = [ "checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d" "checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b" "checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" +"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 8acf159..38e9381 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,8 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +hex = "0.4.2" pdb = "0.5.0" +widestring = "0.4.0" +winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt"] } reqwest = { version = "0.10.1", features = ["blocking"] } - diff --git a/src/main.rs b/src/main.rs index 4e9d163..63da85f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,11 +11,23 @@ use pdb::SymbolData; use pdb::TypeData; use pdb::ClassType; use pdb::ModifierType; +use pdb::Rva; use pdb::FallibleIterator; use pdb::TypeFinder; use pdb::TypeIndex; +use std::ffi::CString; +use widestring::{U16CString}; +use winapi::shared::minwindef::{DWORD}; +use winapi::shared::ntdef::*; +use winapi::um::winnt::{SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES}; +use winapi::um::handleapi::*; +use winapi::um::winbase::*; +use winapi::um::processthreadsapi::*; +use winapi::um::libloaderapi::*; +use winapi::um::securitybaseapi::*; + const PDBNAME: &str = "ntkrnlmp.pdb"; const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe"; const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols"; @@ -112,14 +124,148 @@ fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String { } } -fn parse_pdb() { +type SymbolStore = HashMap; +type StructStore = HashMap>; + +struct PdbStore { + pub symbols: SymbolStore, + pub structs: StructStore +} + +impl PdbStore { + fn get_offset(&self, name: &str) -> Option { + if name.contains(".") { + let v: Vec<&str> = name.split_terminator('.').collect(); + match self.structs.get(v[0]) { + Some(member_info) => { + match member_info.get(v[1]) { + Some((_memtype, offset)) => Some(*offset), + None => None + } + }, + None => None + } + } + else { + match self.symbols.get(name) { + Some(offset) => Some(*offset), + None => None + } + } + } + + fn addr_decompose(&self, addr: u64, full_name: &str) -> Result{ + if !full_name.contains(".") { + return Err("Not decomposable".to_string()); + } + + let mut name_part: Vec<&str> = full_name.split_terminator('.').collect(); + let mut next: Vec<_> = name_part.drain(2..).collect(); + match self.structs.get(name_part[0]) { + Some(member_info) => { + match member_info.get(name_part[1]) { + Some((memtype, offset)) => { + if next.len() != 0 { + if memtype.contains("*") { + return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1])); + } + next.insert(0, memtype); + self.addr_decompose(addr + *offset, &next.join(".")) + } + else { + Ok(addr + *offset) + } + }, + None => Err(format!("Not found member {}", name_part[1])) + } + }, + None => Err(format!("Struct {} not found", name_part[0])) + } + } + + fn default_information(&self) { + let need_symbols = [ + "PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes", + "PoolBigPageTable", "PoolBigPageTableSize", + // "PoolVector", "ExpNumberOfNonPagedPools", + "KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP + "MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8 + "MiNonPagedPoolBitMap", "MiNonPagedPoolVaBitMap", + "MiState" // Windows 10 + ]; + + let mut need_structs = HashMap::new(); + need_structs.insert("_POOL_HEADER", vec![]); + need_structs.insert("_PEB", vec![]); + need_structs.insert("_LIST_ENTRY", vec![ + "Flink", "Blink" + ]); + need_structs.insert("_FILE_OBJECT", vec![ + "FileName" + ]); + need_structs.insert("_EPROCESS", vec![ + "struct_size", + "UniqueProcessId", "ActiveProcessLinks", "CreateTime", + "Peb", "ImageFilePointer", "ImageFileName", "ThreadListHead" + ]); + need_structs.insert("_KDDEBUGGER_DATA64", vec![ + "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP + ]); + need_structs.insert("_POOL_TRACKER_BIG_PAGES", vec![]); + + // these struct supports finding NonPagedPool{First,Last}Va in windows 10 + need_structs.insert("_MI_SYSTEM_INFORMATION", vec![ + "Hardware", // windows 10 2016+ + "SystemNodeInformation" // windows 10 2015 + ]); + need_structs.insert("_MI_HARDWARE_STATE", vec![ + "SystemNodeInformation", // till windows 10 1900 + "SystemNodeNonPagedPool" // windows insider, 2020 + ]); + need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900 + "NonPagedPoolFirstVa", "NonPagedPoolLastVa", + "NonPagedBitMap", // missing on windows 10 1900+ + "DynamicBitMapNonPagedPool" // some weird field + ]); + need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020 + "NonPagedPoolFirstVa", "NonPagedPoolLastVa", + "DynamicBitMapNonPagedPool" // some weird field + ]); + need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]); + need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020 + need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020 + + for &symbol in &need_symbols { + match self.symbols.get(symbol) { + Some(offset) => println!("0x{:x} {}", offset, symbol), + None => {} + } + } + + for (&struct_name, members) in &need_structs { + match self.structs.get(struct_name) { + Some(member_info) => { + for &member in members { + match member_info.get(member) { + Some((memtype, offset)) => + println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member), + None => {} + } + } + }, + None => {} + } + } + } +} + +fn parse_pdb() -> PdbStore { 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 info = pdb.pdb_information().expect("Cannot get pdb information"); let dbi = pdb.debug_information().expect("cannot get debug information"); - println!("PDB for {}, guid: {}, age: {},", dbi.machine_type().unwrap(), info.guid, dbi.age().unwrap_or(0)); - println!(""); + 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 mut type_finder = type_information.type_finder(); @@ -128,101 +274,62 @@ fn parse_pdb() { type_finder.update(&iter); } + let mut symbol_extracted: SymbolStore = HashMap::new(); + // find global symbols offset let addr_map = pdb.address_map().expect("Cannot get address map"); let glosym = pdb.global_symbols().expect("Cannot get global symbols"); let mut symbols = glosym.iter(); - let need_symbols = [ - "PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes", - // "PoolVector", "ExpNumberOfNonPagedPools", - "KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP - "MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8 - "MiNonPagedPoolBitMap", "MiNonPagedPoolVaBitMap", - "MiState" // Windows 10 - ]; while let Some(symbol) = symbols.next().unwrap() { match symbol.parse() { Ok(SymbolData::PublicSymbol(data)) => { let name = symbol.name().unwrap().to_string(); - for sym in need_symbols.iter() { - if &name == sym { - let rva = data.offset.to_rva(&addr_map).unwrap_or_default(); - println!("{} {} {} {}:{}", - get_type_as_str(&type_finder, &(symbol.raw_kind() as u32)), name, rva, data.offset.section, data.offset.offset); - } - } + let Rva(rva) = data.offset.to_rva(&addr_map).unwrap_or_default(); + symbol_extracted.insert(format!("{}", name), rva as u64); }, _ => { // println!("Something else"); } } } - println!(""); - let mut need_structs = HashMap::new(); - // need_structs.insert("_KLDR_DATA_TABLE_ENTRY", vec![]); - need_structs.insert("_PEB", vec![]); - need_structs.insert("_LIST_ENTRY", vec![]); - need_structs.insert("_EPROCESS", vec![]); - need_structs.insert("_KDDEBUGGER_DATA64", vec![ - "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP - "MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8 -- not sure, global symbols - "MiState" // Windows 10 -- not sure, global symbols - ]); + // println!("{:?}", symbol_extracted); - // these struct supports finding NonPagedPool{First,Last}Va in windows 10 - need_structs.insert("_MI_SYSTEM_INFORMATION", vec![ - "Hardware", // windows 10 2016+ - "SystemNodeInformation" // windows 10 2015 - ]); - need_structs.insert("_MI_HARDWARE_STATE", vec![ - "SystemNodeInformation", // till windows 10 1900 - "SystemNodeNonPagedPool" // windows insider, 2020 - ]); - need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900 - "NonPagedPoolFirstVa", "NonPagedPoolLastVa", - "NonPagedBitMap", // missing on windows 10 1900+ - "DynamicBitMapNonPagedPool" // some weird field - ]); - need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020 - "NonPagedPoolFirstVa", "NonPagedPoolLastVa", - "DynamicBitMapNonPagedPool" // some weird field - ]); - need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]); - need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020 - need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020 + let mut struct_extracted: StructStore = HashMap::new(); iter = type_information.iter(); while let Some(typ) = iter.next().unwrap() { // type_finder.update(&iter); match typ.parse() { - Ok(TypeData::Class(ClassType {name, fields: Some(fields), ..})) => { - let n = name.to_string(); - // println!("{}", name); - if !need_structs.contains_key(&*n) { - continue; - } - println!("beginstruct {}", name); + Ok(TypeData::Class(ClassType {name, fields: Some(fields), size, ..})) => { + let mut struct_fields = HashMap::new(); + struct_fields.insert("struct_size".to_string(), ("u32".to_string(), size as u64)); match type_finder.find(fields).unwrap().parse().unwrap() { TypeData::FieldList(list) => { // `fields` is a Vec for field in list.fields { if let TypeData::Member(member) = field { let mem_typ = get_type_as_str(&type_finder, &member.field_type); - println!("\t0x{:x} {} {}", member.offset, mem_typ, member.name); + // println!("\t0x{:x} {} {}", member.offset, mem_typ, member.name); + struct_fields.insert( + format!("{}", member.name), (mem_typ, member.offset as u64)); } else { - println!("\tmember_func"); - // handle member functions, nested types, etc. } } } _ => {} } - println!("endstruct\n"); + struct_extracted.insert(format!("{}", name), struct_fields); + // println!("endstruct\n"); }, _ => {} } } + // println!("{:?}", struct_extracted); + PdbStore { + symbols: symbol_extracted, + structs: struct_extracted + } } fn download_pdb() { @@ -267,9 +374,77 @@ fn download_pdb() { io::copy(&mut resp, &mut out).expect("failed to copy content"); } + fn main() { if !Path::new(PDBNAME).exists() { download_pdb(); } - parse_pdb(); + let store = parse_pdb(); + store.default_information(); + + match store.get_offset("MiState") { + Some(offset) => println!("0x{:x} MiState", offset), + None => {} + }; + match store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool") { + Some(offset) => println!("0x{:x} _MI_HARDWARE_STATE.SystemNodeNonPagedPool", offset), + None => {} + }; + match store.addr_decompose(0xfffff8005d44f200, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool") { + Ok(offset) => println!("0x{:x}", offset), + Err(msg) => println!("{}", msg) + }; + + let str_ntdll = CString::new("ntdll").expect(""); + let str_nt_load_driver = CString::new("NtLoadDriver").expect(""); + let str_nt_unload_driver = CString::new("NtUnloadDriver").expect(""); + let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").expect(""); + let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").expect(""); + + let str_driver_reg = + U16CString::from_str("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); + + let nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; + let nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; + let rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR); + + unsafe { + let ntdll = LoadLibraryA(str_ntdll.as_ptr()); + let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr()); + let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr()); + let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr()); + + // https://github.com/jamalcoder/winapi-dynamic-api-call-using-rust/blob/d0a2386fe590899115442c5e87688ba60013acf7/src/main.rs#L60 + nt_load_driver = std::mem::transmute(nt_load_driver_); + nt_unload_driver = std::mem::transmute(nt_unload_driver_); + rtl_init_unicode_str = std::mem::transmute(rtl_init_unicode_str_); + + println!("ntdll 0x{:x}", ntdll as DWORD); + println!("NtLoadDriver 0x{:x}", nt_load_driver_ as DWORD); + println!("NtUnloadDriver 0x{:x}", nt_unload_driver_ as DWORD); + println!("RtlInitUnicodeString 0x{:x}", rtl_init_unicode_str_ as DWORD); + + // Setup privilege SeLoadDriverPrivilege + let mut token_handle: HANDLE = std::ptr::null_mut(); + let mut luid = LUID::default(); + println!("OpenProcessToken() -> 0x{:x}", + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle)); + println!("LookupPrivilegeValueA() -> 0x{:x}", + LookupPrivilegeValueA(std::ptr::null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid)); + let mut new_token_state = TOKEN_PRIVILEGES { + PrivilegeCount: 1, + Privileges: [LUID_AND_ATTRIBUTES { + Luid: luid, + Attributes: SE_PRIVILEGE_ENABLED + }] + }; + println!("AdjustTokenPrivileges() -> 0x{:x}", + AdjustTokenPrivileges(token_handle, 0, &mut new_token_state, 16, std::ptr::null_mut(), std::ptr::null_mut())); + CloseHandle(token_handle); + + let mut str_driver_reg_unicode = UNICODE_STRING::default(); + rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); + println!("NtLoadDriver() -> 0x{:x}", nt_load_driver(&mut str_driver_reg_unicode)); + println!("NtUnloadDriver() -> 0x{:x}", nt_unload_driver(&mut str_driver_reg_unicode)); + } } From 71b59861c56af58efc3f4d5b13b2b42f790a0f2d Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Sun, 23 Feb 2020 03:06:01 +0700 Subject: [PATCH 2/4] add driver to registry --- Cargo.toml | 2 +- src/main.rs | 62 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 38e9381..01a0399 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,5 @@ edition = "2018" hex = "0.4.2" pdb = "0.5.0" widestring = "0.4.0" -winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt"] } +winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg"] } reqwest = { version = "0.10.1", features = ["blocking"] } diff --git a/src/main.rs b/src/main.rs index 63da85f..8a4a13a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,9 +19,13 @@ use pdb::TypeIndex; use std::ffi::CString; use widestring::{U16CString}; -use winapi::shared::minwindef::{DWORD}; +use winapi::shared::minwindef::{HKEY}; use winapi::shared::ntdef::*; -use winapi::um::winnt::{SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES}; +use winapi::um::winnt::{ + SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES, + REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE +}; +use winapi::um::winreg::*; use winapi::um::handleapi::*; use winapi::um::winbase::*; use winapi::um::processthreadsapi::*; @@ -391,7 +395,8 @@ fn main() { None => {} }; match store.addr_decompose(0xfffff8005d44f200, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool") { - Ok(offset) => println!("0x{:x}", offset), + Ok(offset) => + println!("0x{:x} == ((_MI_SYSTEM_INFORMATION)0xfffff8005d44f200).Hardware.SystemNodeNonPagedPool", offset), Err(msg) => println!("{}", msg) }; @@ -401,9 +406,16 @@ fn main() { let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").expect(""); let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").expect(""); + let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\nganhkhoa.sys").expect(""); + let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); let str_driver_reg = U16CString::from_str("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); + let str_type = CString::new("Type").expect(""); + let str_error_control = CString::new("ErrorControl").expect(""); + let str_start = CString::new("Start").expect(""); + let str_image_path = CString::new("ImagePath").expect(""); + let mut str_driver_reg_unicode = UNICODE_STRING::default(); let nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; let nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; let rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR); @@ -414,23 +426,40 @@ fn main() { let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr()); let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr()); - // https://github.com/jamalcoder/winapi-dynamic-api-call-using-rust/blob/d0a2386fe590899115442c5e87688ba60013acf7/src/main.rs#L60 nt_load_driver = std::mem::transmute(nt_load_driver_); nt_unload_driver = std::mem::transmute(nt_unload_driver_); rtl_init_unicode_str = std::mem::transmute(rtl_init_unicode_str_); - println!("ntdll 0x{:x}", ntdll as DWORD); - println!("NtLoadDriver 0x{:x}", nt_load_driver_ as DWORD); - println!("NtUnloadDriver 0x{:x}", nt_unload_driver_ as DWORD); - println!("RtlInitUnicodeString 0x{:x}", rtl_init_unicode_str_ as DWORD); + // setup registry + let mut registry_key: HKEY = std::ptr::null_mut(); + RegCreateKeyExA( + HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(), + 0, std::ptr::null_mut(), + REG_OPTION_NON_VOLATILE, KEY_WRITE, + std::ptr::null_mut(), &mut registry_key, std::ptr::null_mut() + ); + let type_value: [u8; 4] = 1u32.to_le_bytes(); + let error_control_value: [u8; 4] = 1u32.to_le_bytes(); + let start_value: [u8; 4] = 3u32.to_le_bytes(); + let registry_values = [ + (str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4), + (str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4), + (str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4), + (str_image_path.as_ptr(), REG_SZ, str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1) + ]; + for &(key, keytype, value_ptr, size_in_bytes) in ®istry_values { + RegSetValueExA( + registry_key, key, 0, + keytype, value_ptr, size_in_bytes as u32 + ); + } + RegCloseKey(registry_key); // Setup privilege SeLoadDriverPrivilege let mut token_handle: HANDLE = std::ptr::null_mut(); let mut luid = LUID::default(); - println!("OpenProcessToken() -> 0x{:x}", - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle)); - println!("LookupPrivilegeValueA() -> 0x{:x}", - LookupPrivilegeValueA(std::ptr::null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid)); + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle); + LookupPrivilegeValueA(std::ptr::null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid); let mut new_token_state = TOKEN_PRIVILEGES { PrivilegeCount: 1, Privileges: [LUID_AND_ATTRIBUTES { @@ -438,13 +467,12 @@ fn main() { Attributes: SE_PRIVILEGE_ENABLED }] }; - println!("AdjustTokenPrivileges() -> 0x{:x}", - AdjustTokenPrivileges(token_handle, 0, &mut new_token_state, 16, std::ptr::null_mut(), std::ptr::null_mut())); + AdjustTokenPrivileges(token_handle, 0, &mut new_token_state, 16, std::ptr::null_mut(), std::ptr::null_mut()); CloseHandle(token_handle); - let mut str_driver_reg_unicode = UNICODE_STRING::default(); rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); - println!("NtLoadDriver() -> 0x{:x}", nt_load_driver(&mut str_driver_reg_unicode)); - println!("NtUnloadDriver() -> 0x{:x}", nt_unload_driver(&mut str_driver_reg_unicode)); } + + println!("NtLoadDriver() -> 0x{:x}", nt_load_driver(&mut str_driver_reg_unicode)); + println!("NtUnloadDriver() -> 0x{:x}", nt_unload_driver(&mut str_driver_reg_unicode)); } From f872b8e14a71e51f5661e0060e038bb6d4569cc8 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 24 Feb 2020 00:10:00 +0700 Subject: [PATCH 3/4] moved functions to modules --- src/main.rs | 501 ++++------------------------------------------- src/pdb_store.rs | 353 +++++++++++++++++++++++++++++++++ src/windows.rs | 177 +++++++++++++++++ 3 files changed, 565 insertions(+), 466 deletions(-) create mode 100644 src/pdb_store.rs create mode 100644 src/windows.rs diff --git a/src/main.rs b/src/main.rs index 8a4a13a..183bfaf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,478 +1,47 @@ extern crate reqwest; - -use std::io; -use std::io::Read; -use std::fs::File; +use std::io::{Write}; use std::path::Path; -use std::collections::HashMap; +use std::net::TcpListener; +use std::thread; -use pdb::PDB; -use pdb::SymbolData; -use pdb::TypeData; -use pdb::ClassType; -use pdb::ModifierType; -use pdb::Rva; - -use pdb::FallibleIterator; -use pdb::TypeFinder; -use pdb::TypeIndex; - -use std::ffi::CString; -use widestring::{U16CString}; -use winapi::shared::minwindef::{HKEY}; -use winapi::shared::ntdef::*; -use winapi::um::winnt::{ - SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES, - REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE -}; -use winapi::um::winreg::*; -use winapi::um::handleapi::*; -use winapi::um::winbase::*; -use winapi::um::processthreadsapi::*; -use winapi::um::libloaderapi::*; -use winapi::um::securitybaseapi::*; - -const PDBNAME: &str = "ntkrnlmp.pdb"; -const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe"; -const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols"; - -fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String { - match type_finder.find(*typ).unwrap().parse().unwrap() { - TypeData::Class(ct) => { - format!("{}", ct.name.to_string()) - }, - TypeData::Primitive(pt) => { - format!("{:?}", pt.kind) - }, - TypeData::Pointer(pt) => { - format!("{}*", get_type_as_str(type_finder, &pt.underlying_type)) - }, - TypeData::StaticMember(st) => { - format!("static {}", get_type_as_str(type_finder, &st.field_type)) - }, - TypeData::Array(at) => { - format!("{}{:?}", - get_type_as_str(type_finder, &at.element_type), /* get_type_as_str(type_finder, &at.indexing_type), */ at.dimensions) - }, - // TypeData::Enumeration(et) => { - // format!("enumeration") - // }, - // TypeData::Enumerate(et) => { - // format!("enumerate") - // }, - // TypeData::MemberFunction(mft) => { - // format!("member function") - // }, - // TypeData::OverloadedMethod(ovmt) => { - // format!("overloaded method") - // }, - // TypeData::Nested(nt) => { - // format!("nested") - // }, - // TypeData::BaseClass(bct) => { - // format!("base class") - // }, - // TypeData::VirtualBaseClass(vbct) => { - // format!("virtual base class") - // }, - // TypeData::VirtualFunctionTablePointer(vftpt) => { - // format!("virtual function table pointer") - // }, - TypeData::Procedure(pt) => { - let rettype = match pt.return_type { - Some(rt) => get_type_as_str(type_finder, &rt), - _ => "UNKNOWN".to_string() - }; - format!("{}({})", rettype, get_type_as_str(type_finder, &pt.argument_list)) - }, - TypeData::Modifier(mt) => { - match mt { - ModifierType { constant: true, volatile: true, unaligned: true, .. } => - format!("const volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), - ModifierType { constant: true, volatile: true, unaligned: false, .. } => - format!("const volatile {}", get_type_as_str(type_finder, &mt.underlying_type)), - ModifierType { constant: true, volatile: false, unaligned: true, .. } => - format!("const unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), - ModifierType { constant: false, volatile: true, unaligned: true, .. } => - format!("volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), - ModifierType { constant: true, volatile: false, unaligned: false, .. } => - format!("const {}", get_type_as_str(type_finder, &mt.underlying_type)), - ModifierType { constant: false, volatile: true, unaligned: false, .. } => - format!("volatile {}", get_type_as_str(type_finder, &mt.underlying_type)), - ModifierType { constant: false, volatile: false, unaligned: true, .. } => - format!("unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), - _ => format!("modifier {}", get_type_as_str(type_finder, &mt.underlying_type)) - } - }, - // TypeData::Union(ut) => { - // format!("union") - // }, - // TypeData::Bitfield(bft) => { - // format!("bitfield") - // }, - TypeData::FieldList(_flt) => { - format!("fieldlist") - }, - // TypeData::ArgumentList(alt) => { - // format!("arglist") - // }, - // TypeData::MethodList(mlt) => { - // format!("methodlist") - // }, - unk => { - match unk.name() { - Some(s) => format!("{}", s.to_string()), - _ => "UNNOWN".to_string() - } - } - } -} - -type SymbolStore = HashMap; -type StructStore = HashMap>; - -struct PdbStore { - pub symbols: SymbolStore, - pub structs: StructStore -} - -impl PdbStore { - fn get_offset(&self, name: &str) -> Option { - if name.contains(".") { - let v: Vec<&str> = name.split_terminator('.').collect(); - match self.structs.get(v[0]) { - Some(member_info) => { - match member_info.get(v[1]) { - Some((_memtype, offset)) => Some(*offset), - None => None - } - }, - None => None - } - } - else { - match self.symbols.get(name) { - Some(offset) => Some(*offset), - None => None - } - } - } - - fn addr_decompose(&self, addr: u64, full_name: &str) -> Result{ - if !full_name.contains(".") { - return Err("Not decomposable".to_string()); - } - - let mut name_part: Vec<&str> = full_name.split_terminator('.').collect(); - let mut next: Vec<_> = name_part.drain(2..).collect(); - match self.structs.get(name_part[0]) { - Some(member_info) => { - match member_info.get(name_part[1]) { - Some((memtype, offset)) => { - if next.len() != 0 { - if memtype.contains("*") { - return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1])); - } - next.insert(0, memtype); - self.addr_decompose(addr + *offset, &next.join(".")) - } - else { - Ok(addr + *offset) - } - }, - None => Err(format!("Not found member {}", name_part[1])) - } - }, - None => Err(format!("Struct {} not found", name_part[0])) - } - } - - fn default_information(&self) { - let need_symbols = [ - "PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes", - "PoolBigPageTable", "PoolBigPageTableSize", - // "PoolVector", "ExpNumberOfNonPagedPools", - "KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP - "MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8 - "MiNonPagedPoolBitMap", "MiNonPagedPoolVaBitMap", - "MiState" // Windows 10 - ]; - - let mut need_structs = HashMap::new(); - need_structs.insert("_POOL_HEADER", vec![]); - need_structs.insert("_PEB", vec![]); - need_structs.insert("_LIST_ENTRY", vec![ - "Flink", "Blink" - ]); - need_structs.insert("_FILE_OBJECT", vec![ - "FileName" - ]); - need_structs.insert("_EPROCESS", vec![ - "struct_size", - "UniqueProcessId", "ActiveProcessLinks", "CreateTime", - "Peb", "ImageFilePointer", "ImageFileName", "ThreadListHead" - ]); - need_structs.insert("_KDDEBUGGER_DATA64", vec![ - "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP - ]); - need_structs.insert("_POOL_TRACKER_BIG_PAGES", vec![]); - - // these struct supports finding NonPagedPool{First,Last}Va in windows 10 - need_structs.insert("_MI_SYSTEM_INFORMATION", vec![ - "Hardware", // windows 10 2016+ - "SystemNodeInformation" // windows 10 2015 - ]); - need_structs.insert("_MI_HARDWARE_STATE", vec![ - "SystemNodeInformation", // till windows 10 1900 - "SystemNodeNonPagedPool" // windows insider, 2020 - ]); - need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900 - "NonPagedPoolFirstVa", "NonPagedPoolLastVa", - "NonPagedBitMap", // missing on windows 10 1900+ - "DynamicBitMapNonPagedPool" // some weird field - ]); - need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020 - "NonPagedPoolFirstVa", "NonPagedPoolLastVa", - "DynamicBitMapNonPagedPool" // some weird field - ]); - need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]); - need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020 - need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020 - - for &symbol in &need_symbols { - match self.symbols.get(symbol) { - Some(offset) => println!("0x{:x} {}", offset, symbol), - None => {} - } - } - - for (&struct_name, members) in &need_structs { - match self.structs.get(struct_name) { - Some(member_info) => { - for &member in members { - match member_info.get(member) { - Some((memtype, offset)) => - println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member), - None => {} - } - } - }, - None => {} - } - } - } -} - -fn parse_pdb() -> PdbStore { - 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 info = pdb.pdb_information().expect("Cannot get pdb information"); - let dbi = pdb.debug_information().expect("cannot get 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 mut type_finder = type_information.type_finder(); - let mut iter = type_information.iter(); - while let Some(_typ) = iter.next().unwrap() { - type_finder.update(&iter); - } - - let mut symbol_extracted: SymbolStore = HashMap::new(); - - // find global symbols offset - let addr_map = pdb.address_map().expect("Cannot get address map"); - let glosym = pdb.global_symbols().expect("Cannot get global symbols"); - let mut symbols = glosym.iter(); - while let Some(symbol) = symbols.next().unwrap() { - match symbol.parse() { - Ok(SymbolData::PublicSymbol(data)) => { - let name = symbol.name().unwrap().to_string(); - let Rva(rva) = data.offset.to_rva(&addr_map).unwrap_or_default(); - symbol_extracted.insert(format!("{}", name), rva as u64); - }, - _ => { - // println!("Something else"); - } - } - } - - // println!("{:?}", symbol_extracted); - - let mut struct_extracted: StructStore = HashMap::new(); - - iter = type_information.iter(); - while let Some(typ) = iter.next().unwrap() { - // type_finder.update(&iter); - match typ.parse() { - Ok(TypeData::Class(ClassType {name, fields: Some(fields), size, ..})) => { - let mut struct_fields = HashMap::new(); - struct_fields.insert("struct_size".to_string(), ("u32".to_string(), size as u64)); - match type_finder.find(fields).unwrap().parse().unwrap() { - TypeData::FieldList(list) => { - // `fields` is a Vec - for field in list.fields { - if let TypeData::Member(member) = field { - let mem_typ = get_type_as_str(&type_finder, &member.field_type); - // println!("\t0x{:x} {} {}", member.offset, mem_typ, member.name); - struct_fields.insert( - format!("{}", member.name), (mem_typ, member.offset as u64)); - } else { - } - } - } - _ => {} - } - struct_extracted.insert(format!("{}", name), struct_fields); - // println!("endstruct\n"); - }, - _ => {} - } - } - // println!("{:?}", struct_extracted); - PdbStore { - symbols: symbol_extracted, - structs: struct_extracted - } -} - -fn download_pdb() { - let mut ntoskrnl = File::open(NTOSKRNL_PATH).expect("Cannot open ntoskrnl.exe"); - - let mut buffer = Vec::new(); - ntoskrnl.read_to_end(&mut buffer).expect("Cannot read file ntoskrnl.exe"); - - let mut buffiter = buffer.chunks(4); - while buffiter.next().unwrap() != [0x52, 0x53, 0x44, 0x53] { - // signature == RSDS - } - - // next 16 bytes is guid in raw bytes - let raw_guid: Vec = vec![ - buffiter.next().unwrap(), - buffiter.next().unwrap(), - buffiter.next().unwrap(), - buffiter.next().unwrap(), - ].concat(); - - // guid to hex string - let guid = (vec![ - raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0], - raw_guid[5], raw_guid[4], - raw_guid[7], raw_guid[6], - raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11], - raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15], - ].iter().map(|b| format!("{:02X}", b)).collect::>()).join(""); - - // next 4 bytes is age, in little endian - let raw_age = buffiter.next().unwrap(); - let age = u32::from_le_bytes([ - 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"); -} +mod pdb_store; +mod windows; fn main() { - if !Path::new(PDBNAME).exists() { - download_pdb(); + if !Path::new(pdb_store::PDBNAME).exists() { + pdb_store::download_pdb(); } - let store = parse_pdb(); - store.default_information(); + let store = pdb_store::parse_pdb(); + store.print_default_information(); - match store.get_offset("MiState") { - Some(offset) => println!("0x{:x} MiState", offset), - None => {} - }; - match store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool") { - Some(offset) => println!("0x{:x} _MI_HARDWARE_STATE.SystemNodeNonPagedPool", offset), - None => {} - }; - match store.addr_decompose(0xfffff8005d44f200, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool") { - Ok(offset) => - println!("0x{:x} == ((_MI_SYSTEM_INFORMATION)0xfffff8005d44f200).Hardware.SystemNodeNonPagedPool", offset), - Err(msg) => println!("{}", msg) - }; + // match store.get_offset("MiState") { + // Some(offset) => println!("0x{:x} MiState", offset), + // None => {} + // }; + // match store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool") { + // Some(offset) => println!("0x{:x} _MI_HARDWARE_STATE.SystemNodeNonPagedPool", offset), + // None => {} + // }; + // match store.addr_decompose(0xfffff8005d44f200, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool") { + // Ok(offset) => + // println!("0x{:x} == ((_MI_SYSTEM_INFORMATION)0xfffff8005d44f200).Hardware.SystemNodeNonPagedPool", offset), + // Err(msg) => println!("{}", msg) + // }; - let str_ntdll = CString::new("ntdll").expect(""); - let str_nt_load_driver = CString::new("NtLoadDriver").expect(""); - let str_nt_unload_driver = CString::new("NtUnloadDriver").expect(""); - let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").expect(""); - let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").expect(""); + let mut windows_ffi = windows::WindowsFFI::new(); + windows_ffi.print_version(); - let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\nganhkhoa.sys").expect(""); - let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); - let str_driver_reg = - U16CString::from_str("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); - let str_type = CString::new("Type").expect(""); - let str_error_control = CString::new("ErrorControl").expect(""); - let str_start = CString::new("Start").expect(""); - let str_image_path = CString::new("ImagePath").expect(""); + println!("NtLoadDriver() -> 0x{:x}", windows_ffi.load_driver()); + println!("NtUnloadDriver() -> 0x{:x}", windows_ffi.unload_driver()); - let mut str_driver_reg_unicode = UNICODE_STRING::default(); - let nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; - let nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; - let rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR); - - unsafe { - let ntdll = LoadLibraryA(str_ntdll.as_ptr()); - let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr()); - let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr()); - let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr()); - - nt_load_driver = std::mem::transmute(nt_load_driver_); - nt_unload_driver = std::mem::transmute(nt_unload_driver_); - rtl_init_unicode_str = std::mem::transmute(rtl_init_unicode_str_); - - // setup registry - let mut registry_key: HKEY = std::ptr::null_mut(); - RegCreateKeyExA( - HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(), - 0, std::ptr::null_mut(), - REG_OPTION_NON_VOLATILE, KEY_WRITE, - std::ptr::null_mut(), &mut registry_key, std::ptr::null_mut() - ); - let type_value: [u8; 4] = 1u32.to_le_bytes(); - let error_control_value: [u8; 4] = 1u32.to_le_bytes(); - let start_value: [u8; 4] = 3u32.to_le_bytes(); - let registry_values = [ - (str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4), - (str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4), - (str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4), - (str_image_path.as_ptr(), REG_SZ, str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1) - ]; - for &(key, keytype, value_ptr, size_in_bytes) in ®istry_values { - RegSetValueExA( - registry_key, key, 0, - keytype, value_ptr, size_in_bytes as u32 - ); - } - RegCloseKey(registry_key); - - // Setup privilege SeLoadDriverPrivilege - let mut token_handle: HANDLE = std::ptr::null_mut(); - let mut luid = LUID::default(); - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle); - LookupPrivilegeValueA(std::ptr::null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid); - let mut new_token_state = TOKEN_PRIVILEGES { - PrivilegeCount: 1, - Privileges: [LUID_AND_ATTRIBUTES { - Luid: luid, - Attributes: SE_PRIVILEGE_ENABLED - }] - }; - AdjustTokenPrivileges(token_handle, 0, &mut new_token_state, 16, std::ptr::null_mut(), std::ptr::null_mut()); - CloseHandle(token_handle); - - rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); - } - - println!("NtLoadDriver() -> 0x{:x}", nt_load_driver(&mut str_driver_reg_unicode)); - println!("NtUnloadDriver() -> 0x{:x}", nt_unload_driver(&mut str_driver_reg_unicode)); + // let listener = TcpListener::bind("127.0.0.1:8989").expect("Cannot bind to port 8989"); + // println!("listening started, ready to accept"); + // for stream in listener.incoming() { + // thread::spawn(|| { + // println!("Connection received"); + // let mut stream = stream.unwrap(); + // stream.write(b"Hello World\r\n").unwrap(); + // }); + // } } diff --git a/src/pdb_store.rs b/src/pdb_store.rs new file mode 100644 index 0000000..ae8b309 --- /dev/null +++ b/src/pdb_store.rs @@ -0,0 +1,353 @@ +use std::io; +use std::io::{Read}; +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::FallibleIterator; +use pdb::TypeFinder; +use pdb::TypeIndex; + + +pub const PDBNAME: &str = "ntkrnlmp.pdb"; +pub const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe"; +pub const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols"; + +type SymbolStore = HashMap; +type StructStore = HashMap>; + +pub struct PdbStore { + pub symbols: SymbolStore, + pub structs: StructStore +} + +impl PdbStore { + pub fn get_offset(&self, name: &str) -> Option { + if name.contains(".") { + let v: Vec<&str> = name.split_terminator('.').collect(); + match self.structs.get(v[0]) { + Some(member_info) => { + match member_info.get(v[1]) { + Some((_memtype, offset)) => Some(*offset), + None => None + } + }, + None => None + } + } + else { + match self.symbols.get(name) { + Some(offset) => Some(*offset), + None => None + } + } + } + + pub fn addr_decompose(&self, addr: u64, full_name: &str) -> Result{ + if !full_name.contains(".") { + return Err("Not decomposable".to_string()); + } + + let mut name_part: Vec<&str> = full_name.split_terminator('.').collect(); + let mut next: Vec<_> = name_part.drain(2..).collect(); + match self.structs.get(name_part[0]) { + Some(member_info) => { + match member_info.get(name_part[1]) { + Some((memtype, offset)) => { + if next.len() != 0 { + if memtype.contains("*") { + return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1])); + } + next.insert(0, memtype); + self.addr_decompose(addr + *offset, &next.join(".")) + } + else { + Ok(addr + *offset) + } + }, + None => Err(format!("Not found member {}", name_part[1])) + } + }, + None => Err(format!("Struct {} not found", name_part[0])) + } + } + + pub fn print_default_information(&self) { + let need_symbols = [ + "PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes", + "PoolBigPageTable", "PoolBigPageTableSize", + // "PoolVector", "ExpNumberOfNonPagedPools", + "KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP + "MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8 + "MiNonPagedPoolBitMap", "MiNonPagedPoolVaBitMap", + "MiState" // Windows 10 + ]; + + let mut need_structs = HashMap::new(); + need_structs.insert("_POOL_HEADER", vec![]); + need_structs.insert("_PEB", vec![]); + need_structs.insert("_LIST_ENTRY", vec![ + "Flink", "Blink" + ]); + need_structs.insert("_FILE_OBJECT", vec![ + "FileName" + ]); + need_structs.insert("_EPROCESS", vec![ + "struct_size", + "UniqueProcessId", "ActiveProcessLinks", "CreateTime", + "Peb", "ImageFilePointer", "ImageFileName", "ThreadListHead" + ]); + need_structs.insert("_KDDEBUGGER_DATA64", vec![ + "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP + ]); + need_structs.insert("_POOL_TRACKER_BIG_PAGES", vec![]); + + // these struct supports finding NonPagedPool{First,Last}Va in windows 10 + need_structs.insert("_MI_SYSTEM_INFORMATION", vec![ + "Hardware", // windows 10 2016+ + "SystemNodeInformation" // windows 10 2015 + ]); + need_structs.insert("_MI_HARDWARE_STATE", vec![ + "SystemNodeInformation", // till windows 10 1900 + "SystemNodeNonPagedPool" // windows insider, 2020 + ]); + need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900 + "NonPagedPoolFirstVa", "NonPagedPoolLastVa", + "NonPagedBitMap", // missing on windows 10 1900+ + "DynamicBitMapNonPagedPool" // some weird field + ]); + need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020 + "NonPagedPoolFirstVa", "NonPagedPoolLastVa", + "DynamicBitMapNonPagedPool" // some weird field + ]); + need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]); + need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020 + need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020 + + for &symbol in &need_symbols { + match self.symbols.get(symbol) { + Some(offset) => println!("0x{:x} {}", offset, symbol), + None => {} + } + } + + for (&struct_name, members) in &need_structs { + match self.structs.get(struct_name) { + Some(member_info) => { + for &member in members { + match member_info.get(member) { + Some((memtype, offset)) => + println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member), + None => {} + } + } + }, + None => {} + } + } + } +} + +fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String { + match type_finder.find(*typ).unwrap().parse().unwrap() { + TypeData::Class(ct) => { + format!("{}", ct.name.to_string()) + }, + TypeData::Primitive(pt) => { + format!("{:?}", pt.kind) + }, + TypeData::Pointer(pt) => { + format!("{}*", get_type_as_str(type_finder, &pt.underlying_type)) + }, + TypeData::StaticMember(st) => { + format!("static {}", get_type_as_str(type_finder, &st.field_type)) + }, + TypeData::Array(at) => { + format!("{}{:?}", + get_type_as_str(type_finder, &at.element_type), /* get_type_as_str(type_finder, &at.indexing_type), */ at.dimensions) + }, + // TypeData::Enumeration(et) => { + // format!("enumeration") + // }, + // TypeData::Enumerate(et) => { + // format!("enumerate") + // }, + // TypeData::MemberFunction(mft) => { + // format!("member function") + // }, + // TypeData::OverloadedMethod(ovmt) => { + // format!("overloaded method") + // }, + // TypeData::Nested(nt) => { + // format!("nested") + // }, + // TypeData::BaseClass(bct) => { + // format!("base class") + // }, + // TypeData::VirtualBaseClass(vbct) => { + // format!("virtual base class") + // }, + // TypeData::VirtualFunctionTablePointer(vftpt) => { + // format!("virtual function table pointer") + // }, + TypeData::Procedure(pt) => { + let rettype = match pt.return_type { + Some(rt) => get_type_as_str(type_finder, &rt), + _ => "UNKNOWN".to_string() + }; + format!("{}({})", rettype, get_type_as_str(type_finder, &pt.argument_list)) + }, + TypeData::Modifier(mt) => { + match mt { + ModifierType { constant: true, volatile: true, unaligned: true, .. } => + format!("const volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), + ModifierType { constant: true, volatile: true, unaligned: false, .. } => + format!("const volatile {}", get_type_as_str(type_finder, &mt.underlying_type)), + ModifierType { constant: true, volatile: false, unaligned: true, .. } => + format!("const unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), + ModifierType { constant: false, volatile: true, unaligned: true, .. } => + format!("volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), + ModifierType { constant: true, volatile: false, unaligned: false, .. } => + format!("const {}", get_type_as_str(type_finder, &mt.underlying_type)), + ModifierType { constant: false, volatile: true, unaligned: false, .. } => + format!("volatile {}", get_type_as_str(type_finder, &mt.underlying_type)), + ModifierType { constant: false, volatile: false, unaligned: true, .. } => + format!("unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)), + _ => format!("modifier {}", get_type_as_str(type_finder, &mt.underlying_type)) + } + }, + // TypeData::Union(ut) => { + // format!("union") + // }, + // TypeData::Bitfield(bft) => { + // format!("bitfield") + // }, + TypeData::FieldList(_flt) => { + format!("fieldlist") + }, + // TypeData::ArgumentList(alt) => { + // format!("arglist") + // }, + // TypeData::MethodList(mlt) => { + // format!("methodlist") + // }, + unk => { + match unk.name() { + Some(s) => format!("{}", s.to_string()), + _ => "UNNOWN".to_string() + } + } + } +} + +pub fn parse_pdb() -> PdbStore { + 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 info = pdb.pdb_information().expect("Cannot get pdb information"); + let dbi = pdb.debug_information().expect("cannot get 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 mut type_finder = type_information.type_finder(); + let mut iter = type_information.iter(); + while let Some(_typ) = iter.next().unwrap() { + type_finder.update(&iter); + } + + 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 mut symbols = glosym.iter(); + while let Some(symbol) = symbols.next().unwrap() { + match symbol.parse() { + Ok(SymbolData::PublicSymbol(data)) => { + let name = symbol.name().unwrap().to_string(); + let Rva(rva) = data.offset.to_rva(&addr_map).unwrap_or_default(); + symbol_extracted.insert(format!("{}", name), rva as u64); + }, + _ => { + } + } + } + + let mut struct_extracted: StructStore = HashMap::new(); + iter = type_information.iter(); + while let Some(typ) = iter.next().unwrap() { + match typ.parse() { + Ok(TypeData::Class(ClassType {name, fields: Some(fields), size, ..})) => { + let mut struct_fields = HashMap::new(); + struct_fields.insert("struct_size".to_string(), ("u32".to_string(), size as u64)); + match type_finder.find(fields).unwrap().parse().unwrap() { + TypeData::FieldList(list) => { + for field in list.fields { + if let TypeData::Member(member) = field { + let mem_typ = get_type_as_str(&type_finder, &member.field_type); + struct_fields.insert( + format!("{}", member.name), (mem_typ, member.offset as u64)); + } + } + } + _ => {} + } + struct_extracted.insert(format!("{}", name), struct_fields); + }, + _ => {} + } + } + + PdbStore { + symbols: symbol_extracted, + structs: struct_extracted + } +} + +pub fn download_pdb() { + let mut ntoskrnl = File::open(NTOSKRNL_PATH).expect("Cannot open ntoskrnl.exe"); + + let mut buffer = Vec::new(); + ntoskrnl.read_to_end(&mut buffer).expect("Cannot read file ntoskrnl.exe"); + + let mut buffiter = buffer.chunks(4); + while buffiter.next().unwrap() != [0x52, 0x53, 0x44, 0x53] { + // signature == RSDS + } + + // next 16 bytes is guid in raw bytes + let raw_guid: Vec = vec![ + buffiter.next().unwrap(), + buffiter.next().unwrap(), + buffiter.next().unwrap(), + buffiter.next().unwrap(), + ].concat(); + + // guid to hex string + let guid = (vec![ + raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0], + raw_guid[5], raw_guid[4], + raw_guid[7], raw_guid[6], + raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11], + raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15], + ].iter().map(|b| format!("{:02X}", b)).collect::>()).join(""); + + // next 4 bytes is age, in little endian + let raw_age = buffiter.next().unwrap(); + let age = u32::from_le_bytes([ + 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"); +} + diff --git a/src/windows.rs b/src/windows.rs new file mode 100644 index 0000000..0775e8d --- /dev/null +++ b/src/windows.rs @@ -0,0 +1,177 @@ +use std::ffi::CString; +use widestring::{U16CString}; + +use winapi::shared::ntdef::*; +use winapi::shared::minwindef::{DWORD, HKEY, HMODULE}; +use winapi::um::winnt::{ + SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES, + REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE, + PRTL_OSVERSIONINFOW, OSVERSIONINFOW +}; + +use winapi::um::handleapi::*; +use winapi::um::libloaderapi::*; +use winapi::um::processthreadsapi::*; +use winapi::um::securitybaseapi::*; +use winapi::um::winbase::*; +use winapi::um::winreg::*; + +#[derive(Debug)] +pub enum WindowsVersion { + Windows10_2015, + Windows10_2016, + Windows10_2017, + Windows10_2018, + Windows10_2019, + Windows10_2020, + Windows10FastRing, + Windows10VersionUnknown +} + +pub struct WindowsFFI { + pub version_info: OSVERSIONINFOW, + pub short_version: WindowsVersion, + driver_registry_string: UNICODE_STRING, + ntdll: HMODULE, + nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS, + nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS, + rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR), + rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS, +} + +impl WindowsFFI { + pub fn new() -> Self { + let str_ntdll = CString::new("ntdll").expect(""); + let str_nt_load_driver = CString::new("NtLoadDriver").expect(""); + let str_nt_unload_driver = CString::new("NtUnloadDriver").expect(""); + let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").expect(""); + let str_rtl_get_version = CString::new("RtlGetVersion").expect(""); + let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").expect(""); + + let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\nganhkhoa.sys").expect(""); + let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); + let str_driver_reg = + U16CString::from_str("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa").expect(""); + let str_type = CString::new("Type").expect(""); + let str_error_control = CString::new("ErrorControl").expect(""); + let str_start = CString::new("Start").expect(""); + let str_image_path = CString::new("ImagePath").expect(""); + + let mut str_driver_reg_unicode = UNICODE_STRING::default(); + let mut version_info = OSVERSIONINFOW { + dwOSVersionInfoSize: 0u32, + dwMajorVersion: 0u32, + dwMinorVersion: 0u32, + dwBuildNumber: 0u32, + dwPlatformId: 0u32, + szCSDVersion: [0u16; 128], + }; + + let ntdll: HMODULE; + let nt_load_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; + let nt_unload_driver: extern "stdcall" fn(PUNICODE_STRING) -> NTSTATUS; + let rtl_init_unicode_str: extern "stdcall" fn(PUNICODE_STRING, PCWSTR); + let rtl_get_version: extern "system" fn(PRTL_OSVERSIONINFOW) -> NTSTATUS; + + // some pointer unsafe C code + unsafe { + ntdll = LoadLibraryA(str_ntdll.as_ptr()); + let nt_load_driver_ = GetProcAddress(ntdll, str_nt_load_driver.as_ptr()); + let nt_unload_driver_ = GetProcAddress(ntdll, str_nt_unload_driver.as_ptr()); + let rtl_init_unicode_str_ = GetProcAddress(ntdll, str_rtl_init_unicode_str.as_ptr()); + let rtl_get_version_ = GetProcAddress(ntdll, str_rtl_get_version.as_ptr()); + + nt_load_driver = std::mem::transmute(nt_load_driver_); + nt_unload_driver = std::mem::transmute(nt_unload_driver_); + rtl_init_unicode_str = std::mem::transmute(rtl_init_unicode_str_); + rtl_get_version = std::mem::transmute(rtl_get_version_); + + // setup registry + let mut registry_key: HKEY = std::ptr::null_mut(); + RegCreateKeyExA( + HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(), + 0, std::ptr::null_mut(), + REG_OPTION_NON_VOLATILE, KEY_WRITE, + std::ptr::null_mut(), &mut registry_key, std::ptr::null_mut() + ); + let type_value: [u8; 4] = 1u32.to_le_bytes(); + let error_control_value: [u8; 4] = 1u32.to_le_bytes(); + let start_value: [u8; 4] = 3u32.to_le_bytes(); + let registry_values = [ + (str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4), + (str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4), + (str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4), + (str_image_path.as_ptr(), REG_SZ, + str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1) + ]; + for &(key, keytype, value_ptr, size_in_bytes) in ®istry_values { + RegSetValueExA( + registry_key, key, 0, + keytype, value_ptr, size_in_bytes as u32 + ); + } + RegCloseKey(registry_key); + + // Setup privilege SeLoadDriverPrivilege + let mut token_handle: HANDLE = std::ptr::null_mut(); + let mut luid = LUID::default(); + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle); + LookupPrivilegeValueA(std::ptr::null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid); + let mut new_token_state = TOKEN_PRIVILEGES { + PrivilegeCount: 1, + Privileges: [LUID_AND_ATTRIBUTES { + Luid: luid, + Attributes: SE_PRIVILEGE_ENABLED + }] + }; + AdjustTokenPrivileges( + token_handle, 0, &mut new_token_state, 16, std::ptr::null_mut(), std::ptr::null_mut()); + CloseHandle(token_handle); + + // init string for load and unload driver routine + rtl_init_unicode_str(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16); + } + + rtl_get_version(&mut version_info); + + let short_version = match version_info.dwBuildNumber { + 17134 | 17763 => WindowsVersion::Windows10_2018, + 18362 | 18363 => WindowsVersion::Windows10_2019, + 19041 => WindowsVersion::Windows10_2020, + _ if version_info.dwBuildNumber >= 19536 => WindowsVersion::Windows10FastRing, + _ => WindowsVersion::Windows10VersionUnknown + }; + + Self { + version_info, + short_version, + driver_registry_string: str_driver_reg_unicode, + ntdll, + nt_load_driver, + nt_unload_driver, + rtl_init_unicode_str, + rtl_get_version + } + } + + pub fn load_driver(&mut self) -> NTSTATUS { + (self.nt_load_driver)(&mut self.driver_registry_string) + } + + pub fn unload_driver(&mut self) -> NTSTATUS { + (self.nt_unload_driver)(&mut self.driver_registry_string) + } + + pub fn get_build_number(&self) -> DWORD { + self.version_info.dwBuildNumber + } + + pub fn print_version(&self) { + println!("Windows version: {}.{}.{} {:?}", + self.version_info.dwMajorVersion, + self.version_info.dwMinorVersion, + self.version_info.dwBuildNumber, + self.short_version + ); + } +} From ebeea02962698808a02ba1bd622181c0cdf2a8e6 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 24 Feb 2020 00:32:53 +0700 Subject: [PATCH 4/4] remove warnings --- src/main.rs | 34 ---------------- src/pdb_store.rs | 100 +++++++++++++++++++++++++---------------------- src/windows.rs | 4 ++ 3 files changed, 58 insertions(+), 80 deletions(-) diff --git a/src/main.rs b/src/main.rs index 183bfaf..953a8f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,47 +1,13 @@ -extern crate reqwest; -use std::io::{Write}; -use std::path::Path; -use std::net::TcpListener; -use std::thread; - - mod pdb_store; mod windows; fn main() { - if !Path::new(pdb_store::PDBNAME).exists() { - pdb_store::download_pdb(); - } let store = pdb_store::parse_pdb(); store.print_default_information(); - // match store.get_offset("MiState") { - // Some(offset) => println!("0x{:x} MiState", offset), - // None => {} - // }; - // match store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool") { - // Some(offset) => println!("0x{:x} _MI_HARDWARE_STATE.SystemNodeNonPagedPool", offset), - // None => {} - // }; - // match store.addr_decompose(0xfffff8005d44f200, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool") { - // Ok(offset) => - // println!("0x{:x} == ((_MI_SYSTEM_INFORMATION)0xfffff8005d44f200).Hardware.SystemNodeNonPagedPool", offset), - // Err(msg) => println!("{}", msg) - // }; - let mut windows_ffi = windows::WindowsFFI::new(); windows_ffi.print_version(); println!("NtLoadDriver() -> 0x{:x}", windows_ffi.load_driver()); println!("NtUnloadDriver() -> 0x{:x}", windows_ffi.unload_driver()); - - // let listener = TcpListener::bind("127.0.0.1:8989").expect("Cannot bind to port 8989"); - // println!("listening started, ready to accept"); - // for stream in listener.incoming() { - // thread::spawn(|| { - // println!("Connection received"); - // let mut stream = stream.unwrap(); - // stream.write(b"Hello World\r\n").unwrap(); - // }); - // } } diff --git a/src/pdb_store.rs b/src/pdb_store.rs index ae8b309..0514de4 100644 --- a/src/pdb_store.rs +++ b/src/pdb_store.rs @@ -1,5 +1,6 @@ use std::io; use std::io::{Read}; +use std::path::Path; use std::fs::File; use std::collections::HashMap; @@ -15,9 +16,9 @@ use pdb::TypeFinder; use pdb::TypeIndex; -pub const PDBNAME: &str = "ntkrnlmp.pdb"; -pub const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe"; -pub const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols"; +const PDBNAME: &str = "ntkrnlmp.pdb"; +const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe"; +const PDB_SERVER_PATH: &str = "http://msdl.microsoft.com/download/symbols"; type SymbolStore = HashMap; type StructStore = HashMap>; @@ -28,6 +29,7 @@ pub struct PdbStore { } impl PdbStore { + #[allow(dead_code)] pub fn get_offset(&self, name: &str) -> Option { if name.contains(".") { let v: Vec<&str> = name.split_terminator('.').collect(); @@ -49,6 +51,7 @@ impl PdbStore { } } + #[allow(dead_code)] pub fn addr_decompose(&self, addr: u64, full_name: &str) -> Result{ if !full_name.contains(".") { return Err("Not decomposable".to_string()); @@ -78,6 +81,7 @@ impl PdbStore { } } + #[allow(dead_code)] pub fn print_default_information(&self) { let need_symbols = [ "PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes", @@ -246,7 +250,54 @@ 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"); + + let mut buffer = Vec::new(); + ntoskrnl.read_to_end(&mut buffer).expect("Cannot read file ntoskrnl.exe"); + + let mut buffiter = buffer.chunks(4); + while buffiter.next().unwrap() != [0x52, 0x53, 0x44, 0x53] { + // signature == RSDS + } + + // next 16 bytes is guid in raw bytes + let raw_guid: Vec = vec![ + buffiter.next().unwrap(), + buffiter.next().unwrap(), + buffiter.next().unwrap(), + buffiter.next().unwrap(), + ].concat(); + + // guid to hex string + let guid = (vec![ + raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0], + raw_guid[5], raw_guid[4], + raw_guid[7], raw_guid[6], + raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11], + raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15], + ].iter().map(|b| format!("{:02X}", b)).collect::>()).join(""); + + // next 4 bytes is age, in little endian + let raw_age = buffiter.next().unwrap(); + let age = u32::from_le_bytes([ + 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"); +} + pub fn parse_pdb() -> PdbStore { + // TODO: Detect pdb file and ntoskrnl file version differs + // The guid of ntoskrnl and pdb file are different + 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"); @@ -308,46 +359,3 @@ pub fn parse_pdb() -> PdbStore { structs: struct_extracted } } - -pub fn download_pdb() { - let mut ntoskrnl = File::open(NTOSKRNL_PATH).expect("Cannot open ntoskrnl.exe"); - - let mut buffer = Vec::new(); - ntoskrnl.read_to_end(&mut buffer).expect("Cannot read file ntoskrnl.exe"); - - let mut buffiter = buffer.chunks(4); - while buffiter.next().unwrap() != [0x52, 0x53, 0x44, 0x53] { - // signature == RSDS - } - - // next 16 bytes is guid in raw bytes - let raw_guid: Vec = vec![ - buffiter.next().unwrap(), - buffiter.next().unwrap(), - buffiter.next().unwrap(), - buffiter.next().unwrap(), - ].concat(); - - // guid to hex string - let guid = (vec![ - raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0], - raw_guid[5], raw_guid[4], - raw_guid[7], raw_guid[6], - raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11], - raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15], - ].iter().map(|b| format!("{:02X}", b)).collect::>()).join(""); - - // next 4 bytes is age, in little endian - let raw_age = buffiter.next().unwrap(); - let age = u32::from_le_bytes([ - 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"); -} - diff --git a/src/windows.rs b/src/windows.rs index 0775e8d..d0daff4 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -16,6 +16,7 @@ use winapi::um::securitybaseapi::*; use winapi::um::winbase::*; use winapi::um::winreg::*; +#[allow(dead_code)] #[derive(Debug)] pub enum WindowsVersion { Windows10_2015, @@ -28,6 +29,7 @@ pub enum WindowsVersion { Windows10VersionUnknown } +#[allow(dead_code)] pub struct WindowsFFI { pub version_info: OSVERSIONINFOW, pub short_version: WindowsVersion, @@ -162,10 +164,12 @@ impl WindowsFFI { (self.nt_unload_driver)(&mut self.driver_registry_string) } + #[allow(dead_code)] pub fn get_build_number(&self) -> DWORD { self.version_info.dwBuildNumber } + #[allow(dead_code)] pub fn print_version(&self) { println!("Windows version: {}.{}.{} {:?}", self.version_info.dwMajorVersion,