mod directory;
mod file;
mod key;
mod object_type;
mod process;
mod section;
mod thread;
mod token;
use vmi_core::{
Va, VmiError, VmiState, VmiVa,
driver::VmiRead,
os::{ProcessObject, ThreadObject},
};
pub use self::{
directory::WindowsDirectoryObject,
file::WindowsFileObject,
key::WindowsKey,
object_type::WindowsObjectType,
process::WindowsProcess,
section::WindowsSectionObject,
thread::{WindowsThread, WindowsThreadState, WindowsThreadWaitReason},
token::{
WindowsImpersonationLevel, WindowsPrivilege, WindowsToken, WindowsTokenFlags,
WindowsTokenPrivilege, WindowsTokenSource, WindowsTokenType,
},
};
use super::WindowsObjectHeaderNameInfo;
use crate::{WindowsOs, WindowsOsExt, arch::ArchAdapter, offset, symbol};
pub trait FromWindowsObject<'a, Driver>: Sized
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from_object(object: WindowsObject<'a, Driver>) -> Result<Option<Self>, VmiError>;
}
pub struct WindowsObject<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
vmi: VmiState<'a, WindowsOs<Driver>>,
va: Va,
}
impl<'a, Driver> FromWindowsObject<'a, Driver> for WindowsObject<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from_object(object: WindowsObject<'a, Driver>) -> Result<Option<Self>, VmiError> {
Ok(Some(object))
}
}
impl<Driver> VmiVa for WindowsObject<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn va(&self) -> Va {
self.va
}
}
impl<Driver> std::fmt::Debug for WindowsObject<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let name_info = self.name_info();
let typ = self.type_kind();
f.debug_struct("WindowsObject")
.field("typ", &typ)
.field("name_info", &name_info)
.finish()
}
}
impl<'a, Driver> WindowsObject<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
Self { vmi, va }
}
pub fn header(&self) -> Va {
let OBJECT_HEADER = offset!(self.vmi, _OBJECT_HEADER);
self.va - OBJECT_HEADER.Body.offset()
}
pub fn name_info(&self) -> Result<Option<WindowsObjectHeaderNameInfo<'a, Driver>>, VmiError> {
let ObpInfoMaskToOffset = symbol!(self.vmi, ObpInfoMaskToOffset);
let OBJECT_HEADER = offset!(self.vmi, _OBJECT_HEADER);
let info_mask = self
.vmi
.read_u8(self.header() + OBJECT_HEADER.InfoMask.offset())?;
bitflags::bitflags! {
struct InfoFlags: u8 {
const CREATOR_INFO = 0x01;
const NAME_INFO = 0x02;
const HANDLE_INFO = 0x04;
const QUOTA_INFO = 0x08;
const PROCESS_INFO = 0x10;
}
}
let info_flags = InfoFlags::from_bits_truncate(info_mask);
if !info_flags.contains(InfoFlags::NAME_INFO) {
return Ok(None);
}
let mask = info_mask & (InfoFlags::NAME_INFO.bits() | (InfoFlags::NAME_INFO.bits() - 1));
let mask = mask as u64;
let kernel_image_base = self.vmi.os().kernel_image_base()?;
let offset = self
.vmi
.read_u8(kernel_image_base + ObpInfoMaskToOffset + mask)? as u64;
Ok(Some(WindowsObjectHeaderNameInfo::new(
self.vmi,
self.header() - offset,
)))
}
pub fn directory(&self) -> Result<Option<WindowsObject<'a, Driver>>, VmiError> {
let name_info = match self.name_info()? {
Some(name_info) => name_info,
None => return Ok(None),
};
name_info.directory()
}
pub fn name(&self) -> Result<Option<String>, VmiError> {
let name_info = match self.name_info()? {
Some(name_info) => name_info,
None => return Ok(None),
};
Ok(Some(name_info.name()?))
}
pub fn full_path(&self) -> Result<Option<String>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::File(file)) => Ok(Some(file.full_path()?)),
Some(WindowsObjectKind::Key(key)) => Ok(Some(key.full_path()?)),
Some(WindowsObjectKind::Section(section)) => section.full_path(),
_ => {
let name_info = match self.name_info()? {
Some(name_info) => name_info,
None => return Ok(None),
};
Ok(Some(name_info.full_path()?))
}
}
}
pub fn object_type(&self) -> Result<WindowsObjectType<'a, Driver>, VmiError> {
let ObTypeIndexTable = symbol!(self.vmi, ObTypeIndexTable);
let OBJECT_HEADER = offset!(self.vmi, _OBJECT_HEADER);
let object_header = self.va - OBJECT_HEADER.Body.offset();
let type_index = self
.vmi
.read_u8(object_header + OBJECT_HEADER.TypeIndex.offset())?;
let index = match self.vmi.os().object_header_cookie()? {
Some(cookie) => {
let salt = (object_header.0 >> 8) as u8;
type_index ^ salt ^ cookie
}
None => type_index,
};
let index = index as u64;
let kernel_image_base = self.vmi.os().kernel_image_base()?;
let object_type = self.vmi.read_va_native(
kernel_image_base + ObTypeIndexTable + index * 8, )?;
Ok(WindowsObjectType::new(self.vmi, object_type))
}
pub fn type_name(&self) -> Result<String, VmiError> {
self.object_type()?.name()
}
pub fn type_kind(&self) -> Result<Option<WindowsObjectTypeKind>, VmiError> {
self.object_type()?.kind()
}
pub fn kind(&self) -> Result<Option<WindowsObjectKind<'a, Driver>>, VmiError> {
let result = match self.type_kind()? {
Some(WindowsObjectTypeKind::Directory) => {
WindowsObjectKind::Directory(WindowsDirectoryObject::new(self.vmi, self.va))
}
Some(WindowsObjectTypeKind::File) => {
WindowsObjectKind::File(WindowsFileObject::new(self.vmi, self.va))
}
Some(WindowsObjectTypeKind::Key) => {
WindowsObjectKind::Key(WindowsKey::new(self.vmi, self.va))
}
Some(WindowsObjectTypeKind::Process) => {
WindowsObjectKind::Process(WindowsProcess::new(self.vmi, ProcessObject(self.va)))
}
Some(WindowsObjectTypeKind::Section) => {
WindowsObjectKind::Section(WindowsSectionObject::new(self.vmi, self.va))
}
Some(WindowsObjectTypeKind::Thread) => {
WindowsObjectKind::Thread(WindowsThread::new(self.vmi, ThreadObject(self.va)))
}
Some(WindowsObjectTypeKind::Token) => {
WindowsObjectKind::Token(WindowsToken::new(self.vmi, self.va))
}
Some(WindowsObjectTypeKind::Type) => {
WindowsObjectKind::Type(WindowsObjectType::new(self.vmi, self.va))
}
_ => return Ok(None),
};
Ok(Some(result))
}
pub fn as_directory(&self) -> Result<Option<WindowsDirectoryObject<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::Directory(directory)) => Ok(Some(directory)),
_ => Ok(None),
}
}
pub fn as_file(&self) -> Result<Option<WindowsFileObject<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::File(file)) => Ok(Some(file)),
_ => Ok(None),
}
}
pub fn as_key(&self) -> Result<Option<WindowsKey<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::Key(key)) => Ok(Some(key)),
_ => Ok(None),
}
}
pub fn as_process(&self) -> Result<Option<WindowsProcess<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::Process(process)) => Ok(Some(process)),
_ => Ok(None),
}
}
pub fn as_section(&self) -> Result<Option<WindowsSectionObject<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::Section(section)) => Ok(Some(section)),
_ => Ok(None),
}
}
pub fn as_thread(&self) -> Result<Option<WindowsThread<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::Thread(thread)) => Ok(Some(thread)),
_ => Ok(None),
}
}
pub fn as_token(&self) -> Result<Option<WindowsToken<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::Token(token)) => Ok(Some(token)),
_ => Ok(None),
}
}
pub fn as_type(&self) -> Result<Option<WindowsObjectType<'a, Driver>>, VmiError> {
match self.kind()? {
Some(WindowsObjectKind::Type(object_type)) => Ok(Some(object_type)),
_ => Ok(None),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WindowsObjectTypeKind {
ActivationObject,
ActivityReference,
Adapter,
AlpcPort,
Callback,
Composition,
Controller,
CoreMessaging,
CoverageSampler,
CpuPartition,
DebugObject,
Desktop,
Device,
Directory,
DmaAdapter,
Driver,
DxgkCompositionObject,
DxgkDisplayManagerObject,
DxgkSharedBundleObject,
DxgkSharedKeyedMutexObject,
DxgkSharedProtectedSessionObject,
DxgkSharedResource,
DxgkSharedSwapChainObject,
DxgkSharedSyncObject,
EnergyTracker,
EtwConsumer,
EtwRegistration,
EtwSessionDemuxEntry,
Event,
File,
FilterCommunicationPort,
FilterConnectionPort,
IoCompletion,
IoCompletionReserve,
IoRing,
IRTimer,
Job,
Key,
KeyedEvent,
Mutant,
NdisCmState,
Partition,
PcwObject,
PowerRequest,
Port,
Process,
ProcessStateChange,
Profile,
PsSiloContextNonPaged,
PsSiloContextPaged,
RawInputManager,
RegistryTransaction,
Section,
Semaphore,
Session,
SymbolicLink,
Thread,
ThreadStateChange,
Timer,
TmEn,
TmRm,
TmTm,
TmTx,
Token,
TpWorkerFactory,
Type,
UserApcReserve,
WaitCompletionPacket,
WindowStation,
WmiGuid,
}
#[derive(Debug, PartialEq, Eq)]
pub struct ParseObjectTypeError;
impl std::str::FromStr for WindowsObjectTypeKind {
type Err = ParseObjectTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
use WindowsObjectTypeKind::*;
match s {
"ActivationObject" => Ok(ActivationObject),
"ActivityReference" => Ok(ActivityReference),
"Adapter" => Ok(Adapter),
"ALPC Port" => Ok(AlpcPort),
"Callback" => Ok(Callback),
"Composition" => Ok(Composition),
"Controller" => Ok(Controller),
"CoreMessaging" => Ok(CoreMessaging),
"CoverageSampler" => Ok(CoverageSampler),
"CpuPartition" => Ok(CpuPartition),
"DebugObject" => Ok(DebugObject),
"Desktop" => Ok(Desktop),
"Device" => Ok(Device),
"Directory" => Ok(Directory),
"DmaAdapter" => Ok(DmaAdapter),
"Driver" => Ok(Driver),
"DxgkCompositionObject" => Ok(DxgkCompositionObject),
"DxgkDisplayManagerObject" => Ok(DxgkDisplayManagerObject),
"DxgkSharedBundleObject" => Ok(DxgkSharedBundleObject),
"DxgkSharedKeyedMutexObject" => Ok(DxgkSharedKeyedMutexObject),
"DxgkSharedProtectedSessionObject" => Ok(DxgkSharedProtectedSessionObject),
"DxgkSharedResource" => Ok(DxgkSharedResource),
"DxgkSharedSwapChainObject" => Ok(DxgkSharedSwapChainObject),
"DxgkSharedSyncObject" => Ok(DxgkSharedSyncObject),
"EnergyTracker" => Ok(EnergyTracker),
"EtwConsumer" => Ok(EtwConsumer),
"EtwRegistration" => Ok(EtwRegistration),
"EtwSessionDemuxEntry" => Ok(EtwSessionDemuxEntry),
"Event" => Ok(Event),
"File" => Ok(File),
"FilterCommunicationPort" => Ok(FilterCommunicationPort),
"FilterConnectionPort" => Ok(FilterConnectionPort),
"IoCompletion" => Ok(IoCompletion),
"IoCompletionReserve" => Ok(IoCompletionReserve),
"IoRing" => Ok(IoRing),
"IRTimer" => Ok(IRTimer),
"Job" => Ok(Job),
"Key" => Ok(Key),
"KeyedEvent" => Ok(KeyedEvent),
"Mutant" => Ok(Mutant),
"NdisCmState" => Ok(NdisCmState),
"Partition" => Ok(Partition),
"PcwObject" => Ok(PcwObject),
"PowerRequest" => Ok(PowerRequest),
"Port" => Ok(Port),
"Process" => Ok(Process),
"ProcessStateChange" => Ok(ProcessStateChange),
"Profile" => Ok(Profile),
"PsSiloContextNonPaged" => Ok(PsSiloContextNonPaged),
"PsSiloContextPaged" => Ok(PsSiloContextPaged),
"RawInputManager" => Ok(RawInputManager),
"RegistryTransaction" => Ok(RegistryTransaction),
"Section" => Ok(Section),
"Semaphore" => Ok(Semaphore),
"Session" => Ok(Session),
"SymbolicLink" => Ok(SymbolicLink),
"Thread" => Ok(Thread),
"ThreadStateChange" => Ok(ThreadStateChange),
"Timer" => Ok(Timer),
"TmEn" => Ok(TmEn),
"TmRm" => Ok(TmRm),
"TmTm" => Ok(TmTm),
"TmTx" => Ok(TmTx),
"Token" => Ok(Token),
"TpWorkerFactory" => Ok(TpWorkerFactory),
"Type" => Ok(Type),
"UserApcReserve" => Ok(UserApcReserve),
"WaitCompletionPacket" => Ok(WaitCompletionPacket),
"WindowStation" => Ok(WindowStation),
"WmiGuid" => Ok(WmiGuid),
_ => Err(ParseObjectTypeError),
}
}
}
pub enum WindowsObjectKind<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
Directory(WindowsDirectoryObject<'a, Driver>),
File(WindowsFileObject<'a, Driver>),
Key(WindowsKey<'a, Driver>),
Process(WindowsProcess<'a, Driver>),
Section(WindowsSectionObject<'a, Driver>),
Thread(WindowsThread<'a, Driver>),
Token(WindowsToken<'a, Driver>),
Type(WindowsObjectType<'a, Driver>),
}