use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead};
use super::{
super::{WindowsLuid, WindowsSid, WindowsSidAndAttributes},
FromWindowsObject, WindowsObject, WindowsObjectTypeKind,
};
use crate::{ArchAdapter, WindowsOs, offset};
pub struct WindowsToken<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
vmi: VmiState<'a, WindowsOs<Driver>>,
va: Va,
}
impl<'a, Driver> From<WindowsToken<'a, Driver>> for WindowsObject<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from(value: WindowsToken<'a, Driver>) -> Self {
Self::new(value.vmi, value.va)
}
}
impl<'a, Driver> FromWindowsObject<'a, Driver> for WindowsToken<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from_object(object: WindowsObject<'a, Driver>) -> Result<Option<Self>, VmiError> {
match object.type_kind()? {
Some(WindowsObjectTypeKind::Token) => Ok(Some(Self::new(object.vmi, object.va))),
_ => Ok(None),
}
}
}
impl<Driver> VmiVa for WindowsToken<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn va(&self) -> Va {
self.va
}
}
bitflags::bitflags! {
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct WindowsTokenFlags: u32 {
const HAS_TRAVERSE_PRIVILEGE = 0x0000_0001;
const HAS_BACKUP_PRIVILEGE = 0x0000_0002;
const HAS_RESTORE_PRIVILEGE = 0x0000_0004;
const WRITE_RESTRICTED = 0x0000_0008;
const IS_RESTRICTED = 0x0000_0010;
const SESSION_NOT_REFERENCED = 0x0000_0020;
const SANDBOX_INERT = 0x0000_0040;
const HAS_IMPERSONATE_PRIVILEGE = 0x0000_0080;
const SE_BACKUP_PRIVILEGES_CHECKED = 0x0000_0100;
const VIRTUALIZE_ALLOWED = 0x0000_0200;
const VIRTUALIZE_ENABLED = 0x0000_0400;
const IS_FILTERED = 0x0000_0800;
const UIACCESS = 0x0000_1000;
const NOT_LOW = 0x0000_2000;
const LOWBOX = 0x0000_4000;
const HAS_OWN_CLAIM_ATTRIBUTES = 0x0000_8000;
const PRIVATE_NAMESPACE = 0x0001_0000;
const DO_NOT_USE_GLOBAL_ATTRIBS_FOR_QUERY = 0x0002_0000;
const SPECIAL_ENCRYPTED_OPEN = 0x0004_0000;
const NO_CHILD_PROCESS = 0x0008_0000;
const NO_CHILD_PROCESS_UNLESS_SECURE = 0x0010_0000;
const AUDIT_NO_CHILD_PROCESS = 0x0020_0000;
const ENFORCE_REDIRECTION_TRUST = 0x0040_0000;
const AUDIT_REDIRECTION_TRUST = 0x0080_0000;
const LEARNING_MODE_LOGGING = 0x0100_0000;
const PERMISSIVE_LEARNING_MODE = 0x0300_0000;
const SYSTEM_MANAGED_ADMIN_FULL_TOKEN = 0x0800_0000;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowsTokenType {
Primary,
Impersonation,
Unknown(u32),
}
impl From<u32> for WindowsTokenType {
fn from(value: u32) -> Self {
match value {
1 => Self::Primary,
2 => Self::Impersonation,
_ => Self::Unknown(value),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowsImpersonationLevel {
Anonymous,
Identification,
Impersonation,
Delegation,
Unknown(u32),
}
impl From<u32> for WindowsImpersonationLevel {
fn from(value: u32) -> Self {
match value {
0 => Self::Anonymous,
1 => Self::Identification,
2 => Self::Impersonation,
3 => Self::Delegation,
_ => Self::Unknown(value),
}
}
}
pub struct WindowsTokenSource<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
vmi: VmiState<'a, WindowsOs<Driver>>,
va: Va,
}
impl<Driver> VmiVa for WindowsTokenSource<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn va(&self) -> Va {
self.va
}
}
impl<'a, Driver> WindowsTokenSource<'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 name_bytes(&self) -> Result<[u8; 8], VmiError> {
let TOKEN_SOURCE = offset!(self.vmi, _TOKEN_SOURCE);
debug_assert_eq!(TOKEN_SOURCE.SourceName.size(), 8);
let mut bytes = [0; 8];
self.vmi
.read(self.va + TOKEN_SOURCE.SourceName.offset(), &mut bytes)?;
Ok(bytes)
}
pub fn name(&self) -> Result<String, VmiError> {
let bytes = self.name_bytes()?;
let end = bytes
.iter()
.position(|byte| *byte == 0)
.unwrap_or(bytes.len());
Ok(String::from_utf8_lossy(&bytes[..end])
.trim_end()
.to_string())
}
pub fn identifier(&self) -> Result<WindowsLuid, VmiError> {
let TOKEN_SOURCE = offset!(self.vmi, _TOKEN_SOURCE);
let raw = self
.vmi
.read_u64(self.va + TOKEN_SOURCE.SourceIdentifier.offset())?;
Ok(WindowsLuid::from(raw))
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct WindowsPrivilege(u32);
impl WindowsPrivilege {
pub const CREATE_TOKEN: Self = Self(2);
pub const ASSIGNPRIMARYTOKEN: Self = Self(3);
pub const LOCK_MEMORY: Self = Self(4);
pub const INCREASE_QUOTA: Self = Self(5);
pub const MACHINE_ACCOUNT: Self = Self(6);
pub const TCB: Self = Self(7);
pub const SECURITY: Self = Self(8);
pub const TAKE_OWNERSHIP: Self = Self(9);
pub const LOAD_DRIVER: Self = Self(10);
pub const SYSTEM_PROFILE: Self = Self(11);
pub const SYSTEMTIME: Self = Self(12);
pub const PROF_SINGLE_PROCESS: Self = Self(13);
pub const INC_BASE_PRIORITY: Self = Self(14);
pub const CREATE_PAGEFILE: Self = Self(15);
pub const CREATE_PERMANENT: Self = Self(16);
pub const BACKUP: Self = Self(17);
pub const RESTORE: Self = Self(18);
pub const SHUTDOWN: Self = Self(19);
pub const DEBUG: Self = Self(20);
pub const AUDIT: Self = Self(21);
pub const SYSTEM_ENVIRONMENT: Self = Self(22);
pub const CHANGE_NOTIFY: Self = Self(23);
pub const REMOTE_SHUTDOWN: Self = Self(24);
pub const UNDOCK: Self = Self(25);
pub const SYNC_AGENT: Self = Self(26);
pub const ENABLE_DELEGATION: Self = Self(27);
pub const MANAGE_VOLUME: Self = Self(28);
pub const IMPERSONATE: Self = Self(29);
pub const CREATE_GLOBAL: Self = Self(30);
pub const TRUSTED_CREDMAN_ACCESS: Self = Self(31);
pub const RELABEL: Self = Self(32);
pub const INC_WORKING_SET: Self = Self(33);
pub const TIME_ZONE: Self = Self(34);
pub const CREATE_SYMBOLIC_LINK: Self = Self(35);
pub const DELEGATE_SESSION_USER_IMPERSONATE: Self = Self(36);
pub const fn new(low_part: u32) -> Self {
Self(low_part)
}
pub const fn low_part(self) -> u32 {
self.0
}
pub const fn mask(self) -> u64 {
1 << self.0
}
pub const fn name(self) -> Option<&'static str> {
match self.0 {
2 => Some("SeCreateTokenPrivilege"),
3 => Some("SeAssignPrimaryTokenPrivilege"),
4 => Some("SeLockMemoryPrivilege"),
5 => Some("SeIncreaseQuotaPrivilege"),
6 => Some("SeMachineAccountPrivilege"),
7 => Some("SeTcbPrivilege"),
8 => Some("SeSecurityPrivilege"),
9 => Some("SeTakeOwnershipPrivilege"),
10 => Some("SeLoadDriverPrivilege"),
11 => Some("SeSystemProfilePrivilege"),
12 => Some("SeSystemtimePrivilege"),
13 => Some("SeProfileSingleProcessPrivilege"),
14 => Some("SeIncreaseBasePriorityPrivilege"),
15 => Some("SeCreatePagefilePrivilege"),
16 => Some("SeCreatePermanentPrivilege"),
17 => Some("SeBackupPrivilege"),
18 => Some("SeRestorePrivilege"),
19 => Some("SeShutdownPrivilege"),
20 => Some("SeDebugPrivilege"),
21 => Some("SeAuditPrivilege"),
22 => Some("SeSystemEnvironmentPrivilege"),
23 => Some("SeChangeNotifyPrivilege"),
24 => Some("SeRemoteShutdownPrivilege"),
25 => Some("SeUndockPrivilege"),
26 => Some("SeSyncAgentPrivilege"),
27 => Some("SeEnableDelegationPrivilege"),
28 => Some("SeManageVolumePrivilege"),
29 => Some("SeImpersonatePrivilege"),
30 => Some("SeCreateGlobalPrivilege"),
31 => Some("SeTrustedCredManAccessPrivilege"),
32 => Some("SeRelabelPrivilege"),
33 => Some("SeIncreaseWorkingSetPrivilege"),
34 => Some("SeTimeZonePrivilege"),
35 => Some("SeCreateSymbolicLinkPrivilege"),
36 => Some("SeDelegateSessionUserImpersonatePrivilege"),
_ => None,
}
}
}
impl std::fmt::Debug for WindowsPrivilege {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.name() {
Some(name) => write!(f, "{name}"),
None => write!(f, "UnknownPrivilege({})", self.low_part()),
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct WindowsTokenPrivilege {
pub privilege: WindowsPrivilege,
pub enabled: bool,
pub enabled_by_default: bool,
}
impl<'a, Driver> WindowsToken<'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 session_id(&self) -> Result<u32, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
self.vmi.read_u32(self.va + TOKEN.SessionId.offset())
}
pub fn token_source(&self) -> WindowsTokenSource<'a, Driver> {
let TOKEN = offset!(self.vmi, _TOKEN);
WindowsTokenSource::new(self.vmi, self.va + TOKEN.TokenSource.offset())
}
pub fn authentication_id(&self) -> Result<WindowsLuid, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self
.vmi
.read_u64(self.va + TOKEN.AuthenticationId.offset())?;
Ok(WindowsLuid::from(raw))
}
pub fn token_id(&self) -> Result<WindowsLuid, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self.vmi.read_u64(self.va + TOKEN.TokenId.offset())?;
Ok(WindowsLuid::from(raw))
}
pub fn parent_token_id(&self) -> Result<WindowsLuid, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self.vmi.read_u64(self.va + TOKEN.ParentTokenId.offset())?;
Ok(WindowsLuid::from(raw))
}
pub fn modified_id(&self) -> Result<WindowsLuid, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self.vmi.read_u64(self.va + TOKEN.ModifiedId.offset())?;
Ok(WindowsLuid::from(raw))
}
pub fn originating_logon_session(&self) -> Result<WindowsLuid, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self
.vmi
.read_u64(self.va + TOKEN.OriginatingLogonSession.offset())?;
Ok(WindowsLuid::from(raw))
}
pub fn token_type(&self) -> Result<WindowsTokenType, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self.vmi.read_u32(self.va + TOKEN.TokenType.offset())?;
Ok(WindowsTokenType::from(raw))
}
pub fn impersonation_level(&self) -> Result<WindowsImpersonationLevel, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self
.vmi
.read_u32(self.va + TOKEN.ImpersonationLevel.offset())?;
Ok(WindowsImpersonationLevel::from(raw))
}
pub fn token_flags(&self) -> Result<WindowsTokenFlags, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let raw = self.vmi.read_u32(self.va + TOKEN.TokenFlags.offset())?;
Ok(WindowsTokenFlags::from_bits_retain(raw))
}
pub fn token_in_use(&self) -> Result<bool, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
Ok(self.vmi.read_u8(self.va + TOKEN.TokenInUse.offset())? != 0)
}
pub fn user_and_group_count(&self) -> Result<u32, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
self.vmi
.read_u32(self.va + TOKEN.UserAndGroupCount.offset())
}
pub fn restricted_sid_count(&self) -> Result<u32, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
self.vmi
.read_u32(self.va + TOKEN.RestrictedSidCount.offset())
}
pub fn primary_group(&self) -> Result<WindowsSid<'a, Driver>, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let sid = self
.vmi
.read_va_native(self.va + TOKEN.PrimaryGroup.offset())?;
Ok(WindowsSid::new(self.vmi, sid))
}
pub fn user_and_groups(
&self,
) -> Result<
impl Iterator<Item = Result<WindowsSidAndAttributes<'a, Driver>, VmiError>> + use<'a, Driver>,
VmiError,
> {
let TOKEN = offset!(self.vmi, _TOKEN);
let count = self.user_and_group_count()?;
let base = self
.vmi
.read_va_native(self.va + TOKEN.UserAndGroups.offset())?;
Ok(self.sid_and_attributes(base, count))
}
pub fn restricted_sids(
&self,
) -> Result<
impl Iterator<Item = Result<WindowsSidAndAttributes<'a, Driver>, VmiError>> + use<'a, Driver>,
VmiError,
> {
let TOKEN = offset!(self.vmi, _TOKEN);
let count = self.restricted_sid_count()?;
let base = self
.vmi
.read_va_native(self.va + TOKEN.RestrictedSids.offset())?;
Ok(self.sid_and_attributes(base, count))
}
pub fn privileges_present(&self) -> Result<u64, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let SEP_TOKEN_PRIVILEGES = offset!(self.vmi, _SEP_TOKEN_PRIVILEGES);
self.vmi
.read_u64(self.va + TOKEN.Privileges.offset() + SEP_TOKEN_PRIVILEGES.Present.offset())
}
pub fn privileges_enabled(&self) -> Result<u64, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let SEP_TOKEN_PRIVILEGES = offset!(self.vmi, _SEP_TOKEN_PRIVILEGES);
self.vmi
.read_u64(self.va + TOKEN.Privileges.offset() + SEP_TOKEN_PRIVILEGES.Enabled.offset())
}
pub fn privileges_enabled_by_default(&self) -> Result<u64, VmiError> {
let TOKEN = offset!(self.vmi, _TOKEN);
let SEP_TOKEN_PRIVILEGES = offset!(self.vmi, _SEP_TOKEN_PRIVILEGES);
self.vmi.read_u64(
self.va + TOKEN.Privileges.offset() + SEP_TOKEN_PRIVILEGES.EnabledByDefault.offset(),
)
}
pub fn privileges(&self) -> Result<impl Iterator<Item = WindowsTokenPrivilege>, VmiError> {
let present = self.privileges_present()?;
let enabled = self.privileges_enabled()?;
let enabled_by_default = self.privileges_enabled_by_default()?;
Ok((0..64).filter_map(move |bit| {
let mask = 1u64 << bit;
match present & mask {
0 => None,
_ => Some(WindowsTokenPrivilege {
privilege: WindowsPrivilege::new(bit),
enabled: enabled & mask != 0,
enabled_by_default: enabled_by_default & mask != 0,
}),
}
}))
}
fn sid_and_attributes(
&self,
base: Va,
count: u32,
) -> impl Iterator<Item = Result<WindowsSidAndAttributes<'a, Driver>, VmiError>> + use<'a, Driver>
{
let vmi = self.vmi;
let sizeof_sid_and_attributes = offset!(vmi, _SID_AND_ATTRIBUTES).len() as u64;
(0..u64::from(count)).map(move |index| {
Ok(WindowsSidAndAttributes::new(
vmi,
base + index * sizeof_sid_and_attributes,
))
})
}
}