Update base code for windows 7, 8, 8.1
Because the tag is different in lower version of Windows, need to
change the tag in scan algorithm
4b29cf1986/volatility/framework/plugins/windows/poolscanner.py (L229)
This commit is contained in:
parent
abb7a70b72
commit
8cb553eb11
@ -1,2 +1,5 @@
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
# CRT static to make run on machine without VC++
|
||||
# https://github.com/rust-lang/rust/pull/66801#issuecomment-558947376
|
||||
# >> "-Clink-args=/subsystem:console,5.02"
|
||||
rustflags = ["-Ctarget-feature=+crt-static"]
|
||||
|
78
README.md
78
README.md
@ -1,6 +1,16 @@
|
||||
# LPUS (A live pool-tag scanning solution)
|
||||
|
||||
This is the frontend to the live pool tag scanning solution, the backend is a driver (which is now closed source).
|
||||
This is the frontend to the live pool tag scanning solution, the backend is a
|
||||
driver (which is now closed source).
|
||||
|
||||
Works on Windows 7 and above (Vista not tested, but 7 ok and 10 ok), and on x64
|
||||
systems only. (I hardcoded the address as u64 so only 64 systems should run this).
|
||||
|
||||
> The binary is runable, without crashing. But I still need to add some
|
||||
manual instructions on referencing the structs and offset on some places.
|
||||
> Windows 10, versions 2018, 2019 and 2020 is tested and works.
|
||||
|
||||
Windows XP is not supported: Windows XP Win32Api is missing here and there.
|
||||
|
||||
## How this works
|
||||
|
||||
@ -21,7 +31,7 @@ use lpus::{
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
driver.scan_pool(b"Tag ", |pool_addr, header, data_addr| {
|
||||
driver.scan_pool(b"Tag ", "_STRUCT_NAME", |pool_addr, header, data_addr| {
|
||||
})?;
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
}
|
||||
@ -33,3 +43,67 @@ Parsing the struct data is up to you.
|
||||
You can use `driver.deref_addr(addr, &value)` to dereference an address in kernel space
|
||||
and `driver.pdb_store.get_offset_r("offset")?` to get an offset from PDB file.
|
||||
|
||||
We also have a set of functions for scanning a specific tag/object.
|
||||
|
||||
- `pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_mutant(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
|
||||
And a list traversing the kernel object:
|
||||
|
||||
- `pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_activehead(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- missing symbols `pub fn traverse_afdendpoint(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
|
||||
## Things to note
|
||||
|
||||
Right now, we only have one symbol file of ntoskrnl.exe. While we may need more
|
||||
symbols, kernel32.sys, win32k.sys, tcpis.sys... This will be a future update
|
||||
where symbols are combined into one big `HashMap` but still retain the module. I
|
||||
haven't tested the debug symbols of others binary, I wonder if the PDB file even
|
||||
exists.
|
||||
|
||||
The pdb file is not restricted in ntoskrnl.exe, I might need to split to a
|
||||
smaller module or such.
|
||||
|
||||
Also the symbols list is parsed directly from the PDB file, but some structs
|
||||
(like the callback routine members or network structs) are missing. Right now a
|
||||
simple hardcoded to add in a struct member is used, but it would break if the
|
||||
OS running have a different layout.
|
||||
|
||||
The HashMap of symbols/struct is now using string and u32 to store member
|
||||
offset and types, this should be changed into something that would be type-safe
|
||||
and more functional.
|
||||
|
||||
I also follow a few Volatility implementation on Rootkit, The art of Memory
|
||||
forensics Chapter 13. Scanning in Windows 10 yields promising result, though I
|
||||
haven't tested on any malware to see if we can have the "same" result.
|
||||
|
||||
At the pace of development, I seperate the binary to functionalities for
|
||||
testing, I would add a CLI and a REPL.
|
||||
|
||||
One last thing, the backend doesn't have any check on address referencing, so
|
||||
one may get a blue screen, eventhough I tried to avoid it, I'm not 100% sure it
|
||||
would not crash the system.
|
||||
|
||||
## Future works
|
||||
|
||||
- [ ] An interactive repl (1)
|
||||
- [ ] More kernel modules symbols (2)
|
||||
- [ ] Implementation of more technique (reference Volatility here)
|
||||
- [ ] Quick and easy way to add manual struct, symbols (3)
|
||||
|
||||
(1) This is quite hard to work out, because we have to make the *types* works.
|
||||
The currently chosen repl is based on Lisp, because lisp is cool. If the repl
|
||||
is online, we can combine everything into one binary.
|
||||
|
||||
(2) We may need to download it all and combine to one `HashMap`, with their
|
||||
types as a specific struct. (Try to avoid string).
|
||||
|
||||
(3) Have no idea on this.
|
||||
|
@ -160,9 +160,12 @@ impl fmt::Display for Address {
|
||||
if let Some(p) = &self.pointer {
|
||||
write!(f, "*({}) + 0x{:x}", *p, self.offset)
|
||||
}
|
||||
else {
|
||||
else if self.offset != 0 {
|
||||
write!(f, "0x{:x} + 0x{:x}", self.base, self.offset)
|
||||
}
|
||||
else {
|
||||
write!(f, "0x{:x}", self.base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,13 +191,12 @@ impl DriverState {
|
||||
}
|
||||
|
||||
let data_addr = Address::from_base(pool_addr.address() + pool_header_size);
|
||||
|
||||
let success = handler(pool_addr, &header, data_addr)?;
|
||||
if success {
|
||||
ptr += chunk_size; /* skip this chunk */
|
||||
ptr += chunk_size; // skip this chunk
|
||||
}
|
||||
else {
|
||||
ptr += 0x4; /* search next */
|
||||
ptr += 0x4; // search next
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
@ -298,7 +297,7 @@ impl DriverState {
|
||||
pub fn get_nonpaged_range(&self, ntosbase: &Address) -> BoxResult<[Address; 2]> {
|
||||
// TODO: Add support for other Windows version here
|
||||
match self.windows_ffi.short_version {
|
||||
WindowsVersion::Windows10FastRing => {
|
||||
WindowsVersion::WindowsFastRing => {
|
||||
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
||||
let path_first_va: String = vec![
|
||||
"_MI_SYSTEM_INFORMATION",
|
||||
@ -335,6 +334,13 @@ impl DriverState {
|
||||
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
||||
Ok([first_va, last_va])
|
||||
},
|
||||
WindowsVersion::Windows7 => {
|
||||
let path_first_va = ntosbase.clone() + self.pdb_store.get_offset_r("MmNonPagedPoolStart")?;
|
||||
let path_last_va = ntosbase.clone() + self.pdb_store.get_offset_r("MiNonPagedPoolEnd")?;
|
||||
let first_va = Address::from_base(self.deref_addr_new(path_first_va.address()));
|
||||
let last_va = Address::from_base(self.deref_addr_new(path_last_va.address()));
|
||||
Ok([first_va, last_va])
|
||||
},
|
||||
_ => {
|
||||
Err("Windows version for nonpaged pool algorithm is not implemented".into())
|
||||
}
|
||||
|
@ -21,8 +21,10 @@ pub struct OffsetData {
|
||||
// TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version
|
||||
impl OffsetData {
|
||||
pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self {
|
||||
// TODO: Fix the backend so that only neccessary fields are used
|
||||
// This is too much, most of the functionality has been move to the frontend
|
||||
match windows_version {
|
||||
WindowsVersion::Windows10FastRing => Self {
|
||||
WindowsVersion::WindowsFastRing => Self {
|
||||
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64),
|
||||
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64),
|
||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||
@ -51,6 +53,20 @@ impl OffsetData {
|
||||
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64),
|
||||
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64),
|
||||
},
|
||||
WindowsVersion::Windows7 => Self {
|
||||
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64),
|
||||
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64),
|
||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64),
|
||||
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation").unwrap_or(0u64),
|
||||
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa").unwrap_or(0u64),
|
||||
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa").unwrap_or(0u64),
|
||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64),
|
||||
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64),
|
||||
},
|
||||
// TODO: Add other version of Windows here
|
||||
// TODO: Warn user of unknown windows version, because BSOD will occur
|
||||
_ => Self {
|
||||
|
14
src/lib.rs
14
src/lib.rs
@ -143,10 +143,13 @@ pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
|
||||
let eprocess_ptr = &try_eprocess_ptr;
|
||||
|
||||
println!("EPROCESS: 0x{:x}", eprocess_ptr.address());
|
||||
|
||||
let pid: u64 = driver.decompose(eprocess_ptr, "_EPROCESS.UniqueProcessId")?;
|
||||
let ppid: u64 = driver.decompose(eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
||||
let image_name: Vec<u8> = driver.decompose_array(eprocess_ptr, "_EPROCESS.ImageFileName", 15)?;
|
||||
let unicode_str_ptr = driver.address_of(eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?;
|
||||
let unicode_str_ptr = driver.address_of(eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")
|
||||
.unwrap_or(0); // ImageFilePointer is Windows 10+
|
||||
|
||||
let eprocess_name =
|
||||
if let Ok(name) = from_utf8(&image_name) {
|
||||
@ -525,7 +528,8 @@ pub fn traverse_activehead(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?;
|
||||
let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
||||
let image_name: Vec<u8> = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?;
|
||||
let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?;
|
||||
let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")
|
||||
.unwrap_or(0);
|
||||
|
||||
let eprocess_name =
|
||||
if let Ok(name) = from_utf8(&image_name) {
|
||||
@ -608,7 +612,8 @@ pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?;
|
||||
let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
||||
let image_name: Vec<u8> = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?;
|
||||
let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?;
|
||||
let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")
|
||||
.unwrap_or(0);
|
||||
|
||||
let eprocess_name =
|
||||
if let Ok(name) = from_utf8(&image_name) {
|
||||
@ -652,7 +657,8 @@ pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?;
|
||||
let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
||||
let image_name: Vec<u8> = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?;
|
||||
let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?;
|
||||
let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")
|
||||
.unwrap_or(0);
|
||||
|
||||
let eprocess_name =
|
||||
if let Ok(name) = from_utf8(&image_name) {
|
||||
|
@ -29,14 +29,17 @@ const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentCont
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum WindowsVersion {
|
||||
Windows7,
|
||||
Windows8,
|
||||
Windows10Legacy,
|
||||
Windows10_2015,
|
||||
Windows10_2016,
|
||||
Windows10_2017,
|
||||
Windows10_2018,
|
||||
Windows10_2019,
|
||||
Windows10_2020,
|
||||
Windows10FastRing,
|
||||
Windows10VersionUnknown
|
||||
WindowsFastRing,
|
||||
WindowsUnknown
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -142,11 +145,19 @@ impl WindowsFFI {
|
||||
rtl_get_version(&mut version_info);
|
||||
|
||||
let short_version = match version_info.dwBuildNumber {
|
||||
// 2600 => WindowsVersion::WindowsXP,
|
||||
// 6000 | 6001 | 6002 => WindowsVersion::WindowsVista,
|
||||
7600 | 7601 => WindowsVersion::Windows7,
|
||||
9200 | 9600 => WindowsVersion::Windows8,
|
||||
10240 => WindowsVersion::Windows10Legacy,
|
||||
10586 => WindowsVersion::Windows10_2015,
|
||||
14393 => WindowsVersion::Windows10_2016,
|
||||
15063 | 16299 => WindowsVersion::Windows10_2017,
|
||||
17134 | 17763 => WindowsVersion::Windows10_2018,
|
||||
18362 | 18363 => WindowsVersion::Windows10_2019,
|
||||
18363 | 18362 => WindowsVersion::Windows10_2019,
|
||||
19041 => WindowsVersion::Windows10_2020,
|
||||
_ if version_info.dwBuildNumber >= 19536 => WindowsVersion::Windows10FastRing,
|
||||
_ => WindowsVersion::Windows10VersionUnknown
|
||||
x if x >= 19536 => WindowsVersion::WindowsFastRing,
|
||||
_ => WindowsVersion::WindowsUnknown
|
||||
};
|
||||
|
||||
Self {
|
||||
|
Loading…
Reference in New Issue
Block a user