moved functions to modules
This commit is contained in:
parent
71b59861c5
commit
f872b8e14a
501
src/main.rs
501
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<String, u64>;
|
||||
type StructStore = HashMap<String, HashMap<String, (String, u64)>>;
|
||||
|
||||
struct PdbStore {
|
||||
pub symbols: SymbolStore,
|
||||
pub structs: StructStore
|
||||
}
|
||||
|
||||
impl PdbStore {
|
||||
fn get_offset(&self, name: &str) -> Option<u64> {
|
||||
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<u64, String>{
|
||||
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<TypeData>
|
||||
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<u8> = 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::<Vec<String>>()).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();
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
353
src/pdb_store.rs
Normal file
353
src/pdb_store.rs
Normal file
@ -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<String, u64>;
|
||||
type StructStore = HashMap<String, HashMap<String, (String, u64)>>;
|
||||
|
||||
pub struct PdbStore {
|
||||
pub symbols: SymbolStore,
|
||||
pub structs: StructStore
|
||||
}
|
||||
|
||||
impl PdbStore {
|
||||
pub fn get_offset(&self, name: &str) -> Option<u64> {
|
||||
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<u64, String>{
|
||||
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<u8> = 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::<Vec<String>>()).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");
|
||||
}
|
||||
|
177
src/windows.rs
Normal file
177
src/windows.rs
Normal file
@ -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
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user