multiple binary and code refactor

This commit is contained in:
nganhkhoa 2020-05-19 03:52:18 +07:00
parent 3214e79d63
commit dae10a5312
9 changed files with 146 additions and 162 deletions

24
Cargo.lock generated
View File

@ -337,6 +337,18 @@ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lpus"
version = "0.1.0"
dependencies = [
"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)",
"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]]
name = "matches"
version = "0.1.8"
@ -482,18 +494,6 @@ dependencies = [
"vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "parse_pdb_for_offsets"
version = "0.1.0"
dependencies = [
"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)",
"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]]
name = "pdb"
version = "0.5.0"

View File

@ -1,10 +1,14 @@
[package]
name = "parse_pdb_for_offsets"
name = "lpus"
version = "0.1.0"
authors = ["nganhkhoa <mail.nganhkhoa@gmail.com>"]
description = "Live pool tag scanning frontend"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "lpus"
doctest = false
[dependencies]
hex = "0.4.2"

73
src/bin/eprocess_scan.rs Normal file
View File

@ -0,0 +1,73 @@
use std::error::Error;
use std::str::{from_utf8};
use chrono::Utc;
use chrono::{DateTime};
use std::time::{UNIX_EPOCH, Duration};
use lpus::{
driver_state::{DriverState /* , EprocessPoolChunk */}
};
#[allow(dead_code)]
fn to_str_time(time_ms: u64) -> String {
if time_ms == 0 {
return "".to_string();
}
let d = UNIX_EPOCH + Duration::from_millis(time_ms);
let datetime = DateTime::<Utc>::from(d);
let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string();
timestamp_str
}
fn main() -> Result<(), Box<dyn Error>> {
// for windows admin require
// https://github.com/nabijaczleweli/rust-embed-resource
let mut driver = DriverState::new();
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
// let eprocess_scan_head = driver.scan_active_head(ntosbase)?;
// let mut eprocess_list: Vec<EprocessPoolChunk> = Vec::new();
driver.scan_pool(b"Proc", |pool_addr, header, data_addr| {
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_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
let chunk_size = (header[2] as u64) * 16u64;
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;
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);
// using heuristics to eliminate false positive
if driver.windows_ffi.valid_process_time(create_time) {
break;
}
try_eprocess_ptr += 0x4; // search exhaustively
}
let mut image_name = [0u8; 15];
driver.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name);
let eprocess_name = from_utf8(&image_name)?
.to_string()
.trim_end_matches(char::from(0))
.to_string();
// eprocess_list.push(EprocessPoolChunk {
// pool_addr,
// eprocess_addr: try_eprocess_ptr,
// eprocess_name: eprocess_name,
// create_time: to_epoch(create_time),
// exit_time: to_epoch(exit_time)
// });
println!("pool: {} | eprocess: {}: {}", pool_addr, try_eprocess_ptr, eprocess_name);
Ok(try_eprocess_ptr <= eprocess_valid_end)
})?;
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())
}

12
src/bin/print_pdb.rs Normal file
View File

@ -0,0 +1,12 @@
use std::error::Error;
use lpus::{
driver_state::{DriverState}
};
fn main() -> Result<(), Box<dyn Error>> {
let driver = DriverState::new();
driver.windows_ffi.print_version();
driver.pdb_store.print_default_information();
Ok(())
}

View File

@ -10,7 +10,7 @@ use winapi::um::winioctl::{
METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER
};
use crate::pdb_store::{PdbStore};
use crate::pdb_store::{PdbStore, parse_pdb};
use crate::windows::{WindowsFFI, WindowsVersion};
use crate::ioctl_protocol::{
InputData, OffsetData, DerefAddr, ScanPoolData, /* HideProcess, */
@ -79,12 +79,10 @@ pub struct DriverState {
}
impl DriverState {
pub fn new(pdb_store: PdbStore, windows_ffi: WindowsFFI) -> Self {
pdb_store.print_default_information();
windows_ffi.print_version();
pub fn new() -> Self {
Self {
pdb_store,
windows_ffi
pdb_store: parse_pdb(),
windows_ffi: WindowsFFI::new()
}
}
@ -102,12 +100,12 @@ impl DriverState {
self.windows_ffi.unload_driver()
}
pub fn get_kernel_base(&self) -> BoxResult<u64> {
pub fn get_kernel_base(&self) -> u64 {
let mut ntosbase = 0u64;
self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(),
&mut Nothing, &mut ntosbase);
// println!("ntosbase: 0x{:x}", self.ntosbase);
Ok(ntosbase)
ntosbase
}
pub fn scan_active_head(&self, ntosbase: u64) -> BoxResult<Vec<EprocessPoolChunk>> {
@ -144,9 +142,14 @@ impl DriverState {
Ok(result)
}
pub fn scan_pool<F>(&self, ntosbase: u64, tag: [u8; 4], mut handler: F) -> BoxResult<bool>
where F: FnMut(&DriverState, u64) -> BoxResult<bool>
pub fn scan_pool<F>(&self, tag: &[u8; 4], mut handler: F) -> BoxResult<bool>
where F: FnMut(u64, &[u8], u64) -> BoxResult<bool>
// F(Pool Address, Pool Header Data, Pool Data Address)
// TODO: Pool Header as a real struct
{
let ntosbase = self.get_kernel_base();
// TODO: check valid tag
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
let code = DriverAction::ScanPoolRemote.get_code();
let range = self.get_nonpaged_range(ntosbase)?;
let start_address = range[0];
@ -154,22 +157,23 @@ impl DriverState {
let mut ptr = start_address;
while ptr < end_address {
let mut input = InputData {
scan_range: ScanPoolData::new(&[ptr, end_address], &tag)
scan_range: ScanPoolData::new(&[ptr, end_address], tag)
};
self.windows_ffi.device_io(code, &mut input, &mut ptr);
if ptr >= end_address {
break;
}
ptr += match handler(&self, ptr) {
Ok(success) => {
if success {
}
else {
}
},
Err(e) => println!("Handle error {:?}", e),
// found, ptr += chunk size
// ptr += pool_header_size;
let pool_addr = ptr;
let mut header = vec![0u8; pool_header_size as usize];
self.deref_addr_ptr(pool_addr, header.as_mut_ptr(), pool_header_size);
let success = handler(ptr, &header, pool_addr + pool_header_size)?;
if success {
let chunk_size = (header[2] as u64) * 16u64;
ptr += chunk_size /* pass this chunk */
}
else {
ptr += 0x4 /* search next */
};
}
Ok(true)

View File

@ -67,7 +67,7 @@ pub struct DerefAddr {
pub struct ScanPoolData {
pub start: u64,
pub end: u64,
pub tag: [u8; 4]
pub tag: u32
}
impl ScanPoolData{
@ -75,7 +75,7 @@ impl ScanPoolData{
Self {
start: arr[0],
end: arr[1],
tag: *tag
tag: u32::from_le_bytes(*tag)
}
}
}

7
src/lib.rs Normal file
View File

@ -0,0 +1,7 @@
extern crate chrono;
pub mod pdb_store;
pub mod windows;
pub mod ioctl_protocol;
pub mod driver_state;

View File

@ -1,124 +0,0 @@
extern crate chrono;
mod pdb_store;
mod windows;
mod ioctl_protocol;
mod driver_state;
use std::error::Error;
use std::str::{from_utf8};
// use chrono::prelude::DateTime;
// use chrono::Utc;
// use chrono::{Local, DateTime};
// use std::time::{SystemTime, UNIX_EPOCH, Duration};
use pdb_store::parse_pdb;
use windows::WindowsFFI;
use driver_state::{DriverState, EprocessPoolChunk, to_epoch};
fn to_str_time(_time_ms: u64) -> String {
// if time_ms == 0 {
// return "".to_string();
// }
// let d = UNIX_EPOCH + Duration::from_millis(time_ms);
// let datetime = DateTime::<Utc>::from(d);
// let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string();
// timestamp_str
"".to_string()
}
fn main() -> Result<(), Box<dyn Error>> {
// for windows admin require
// https://github.com/nabijaczleweli/rust-embed-resource
let mut driver = DriverState::new(parse_pdb(), WindowsFFI::new());
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
let ntosbase = driver.get_kernel_base()?;
let pool_header_size = driver.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
let eprocess_tag: [u8; 4] = [80, 114, 111, 99]; // Proc
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_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
let eprocess_scan_head = driver.scan_active_head(ntosbase)?;
let mut eprocess_list: Vec<EprocessPoolChunk> = Vec::new();
driver.scan_pool(ntosbase, eprocess_tag, |dr, pool_addr| {
let mut pool = vec![0u8; pool_header_size as usize];
dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size);
let chunk_size = (pool[2] as u64) * 16u64;
let eprocess_valid_start = pool_addr + pool_header_size;
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;
while try_eprocess_ptr <= eprocess_valid_end {
dr.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time);
dr.deref_addr(try_eprocess_ptr + eprocess_exit_time_offset, &mut exit_time);
if dr.windows_ffi.valid_process_time(create_time) {
break;
}
try_eprocess_ptr += 0x4; // search exhaustively
}
let mut image_name = [0u8; 15];
dr.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name);
let eprocess_name = from_utf8(&image_name)?
.to_string()
.trim_end_matches(char::from(0))
.to_string();
eprocess_list.push(EprocessPoolChunk {
pool_addr,
eprocess_addr: try_eprocess_ptr,
eprocess_name: eprocess_name,
create_time: to_epoch(create_time),
exit_time: to_epoch(exit_time)
});
Ok(try_eprocess_ptr <= eprocess_valid_end)
})?;
let ethread_tag: [u8; 4] = [84, 104, 114, 101]; // Thre
let ethread_create_time_offset = driver.pdb_store.get_offset_r("_ETHREAD.CreateTime")?;
let ethread_exit_time_offset = driver.pdb_store.get_offset_r("_ETHREAD.ExitTime")?;
let ethread_threadname_offset = driver.pdb_store.get_offset_r("_ETHREAD.TheadName")?;
let ethread_size = driver.pdb_store.get_offset_r("_ETHREAD.struct_size")?;
// let mut ethread_list: Vec<EprocessPoolChunk> = Vec::new();
driver.scan_pool(ntosbase, ethread_tag, |dr, pool_addr| {
let mut pool = vec![0u8; pool_header_size as usize];
dr.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size);
let chunk_size = (pool[2] as u64) * 16u64;
let ethread_valid_start = pool_addr + pool_header_size;
let ethread_valid_end = pool_addr + chunk_size - ethread_size;
let mut try_ethread_ptr = ethread_valid_start;
let mut create_time = 0u64;
let mut exit_time = 0u64;
while try_ethread_ptr <= ethread_valid_end {
dr.deref_addr(try_ethread_ptr + ethread_create_time_offset, &mut create_time);
dr.deref_addr(try_ethread_ptr + ethread_exit_time_offset, &mut exit_time);
if dr.windows_ffi.valid_process_time(create_time) {
break;
}
try_ethread_ptr += 0x4; // search exhaustively
}
let mut threadname_ptr = 0u64;
dr.deref_addr(try_ethread_ptr + ethread_threadname_offset, &mut threadname_ptr);
let threadname = dr.get_unicode_string(threadname_ptr)?;
println!("threadname: {}", threadname);
Ok(try_ethread_ptr <= ethread_valid_end)
})?;
// for result in &driver.eprocess_traverse_result {
// println!("- [{}] 0x{:x} {}",
// driver.pool_scan_result.contains(&result),
// result.eprocess_addr, result.eprocess_name);
// }
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
Ok(())
}

View File

@ -299,7 +299,15 @@ pub fn download_pdb() {
pub fn parse_pdb() -> PdbStore {
// TODO: Detect pdb file and ntoskrnl file version differs
// The guid of ntoskrnl and pdb file are different
// Use a folder at %APPDATA% to save pdb files
// %APPDATA%\lpus
// |--ntoskrnl
// |--|--GUID
// |--|--|--ntkrnlmp.pdb
// |--file
// |--|--GUID
// |--|--|--file.pdb
// TODO: Turn function to Result to handle error
if !Path::new(PDBNAME).exists() {
download_pdb();
}