use vmi_core::{Pa, Registers as _, Va, VmiError, VmiState, VmiVa, driver::VmiRead};
use super::{WindowsPeb, WindowsPebBase, WindowsWow64Kind};
use crate::{
WindowsOs,
arch::{ArchAdapter, StructLayout, StructLayout32, StructLayout64},
};
pub trait Teb<Layout>
where
Layout: StructLayout,
{
const OFFSET_PROCESS_ENVIRONMENT_BLOCK: u64;
const OFFSET_LAST_ERROR_VALUE: u64;
const OFFSET_LAST_STATUS_VALUE: u64;
const OFFSET_TLS_SLOTS: u64;
}
pub struct TebLayout;
impl Teb<StructLayout32> for TebLayout {
const OFFSET_PROCESS_ENVIRONMENT_BLOCK: u64 = 0x30;
const OFFSET_LAST_ERROR_VALUE: u64 = 0x34;
const OFFSET_LAST_STATUS_VALUE: u64 = 0x0bf4;
const OFFSET_TLS_SLOTS: u64 = 0x0e10;
}
impl Teb<StructLayout64> for TebLayout {
const OFFSET_PROCESS_ENVIRONMENT_BLOCK: u64 = 0x60;
const OFFSET_LAST_ERROR_VALUE: u64 = 0x68;
const OFFSET_LAST_STATUS_VALUE: u64 = 0x1250;
const OFFSET_TLS_SLOTS: u64 = 0x1480;
}
pub struct WindowsTebBase<'a, Driver, Layout>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
Layout: StructLayout,
TebLayout: Teb<Layout>,
{
vmi: VmiState<'a, WindowsOs<Driver>>,
va: Va,
root: Pa,
_marker: std::marker::PhantomData<Layout>,
}
impl<'a, Driver, Layout> WindowsTebBase<'a, Driver, Layout>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
Layout: StructLayout,
TebLayout: Teb<Layout>,
{
pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
Self {
vmi,
va,
root,
_marker: std::marker::PhantomData,
}
}
pub fn peb(&self) -> Result<Option<WindowsPebBase<'a, Driver, Layout>>, VmiError>
where
super::peb::PebLayout: super::peb::Peb<Layout>,
{
let va = Layout::read_va(
self.vmi,
(
self.va + TebLayout::OFFSET_PROCESS_ENVIRONMENT_BLOCK,
self.root,
),
)?;
if va.is_null() {
return Ok(None);
}
Ok(Some(WindowsPebBase::new(self.vmi, va, self.root)))
}
pub fn last_error_value(&self) -> Result<u32, VmiError> {
self.vmi
.read_u32_in((self.va + TebLayout::OFFSET_LAST_ERROR_VALUE, self.root))
}
pub fn last_status_value(&self) -> Result<u32, VmiError> {
self.vmi
.read_u32_in((self.va + TebLayout::OFFSET_LAST_STATUS_VALUE, self.root))
}
pub fn tls_slot(&self, index: usize) -> Result<u64, VmiError> {
const TLS_MINIMUM_AVAILABLE: usize = 64;
debug_assert!(
index < TLS_MINIMUM_AVAILABLE,
"TLS slot index out of bounds: {index}"
);
let offset = TebLayout::OFFSET_TLS_SLOTS + (index as u64) * Layout::ADDRESS_WIDTH;
self.vmi.read_uint_in(
(self.va + offset, self.root),
Layout::ADDRESS_WIDTH as usize,
)
}
}
enum WindowsTebWrapper<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
W32(WindowsTebBase<'a, Driver, StructLayout32>),
W64(WindowsTebBase<'a, Driver, StructLayout64>),
}
impl<'a, Driver> WindowsTebWrapper<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn w32(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
Self::W32(WindowsTebBase::new(vmi, va, root))
}
fn w64(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
Self::W64(WindowsTebBase::new(vmi, va, root))
}
fn native(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va, root: Pa) -> Self {
match vmi.registers().address_width() {
4 => Self::w32(vmi, va, root),
8 => Self::w64(vmi, va, root),
_ => panic!("Unsupported address width"),
}
}
fn peb(&self) -> Result<Option<WindowsPeb<'a, Driver>>, VmiError> {
match self {
Self::W32(inner) => Ok(inner.peb()?.map(WindowsPeb::from)),
Self::W64(inner) => Ok(inner.peb()?.map(WindowsPeb::from)),
}
}
fn last_error_value(&self) -> Result<u32, VmiError> {
match self {
Self::W32(inner) => inner.last_error_value(),
Self::W64(inner) => inner.last_error_value(),
}
}
fn last_status_value(&self) -> Result<u32, VmiError> {
match self {
Self::W32(inner) => inner.last_status_value(),
Self::W64(inner) => inner.last_status_value(),
}
}
fn tls_slot(&self, index: usize) -> Result<u64, VmiError> {
match self {
Self::W32(inner) => inner.tls_slot(index),
Self::W64(inner) => inner.tls_slot(index),
}
}
}
pub struct WindowsTeb<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
inner: WindowsTebWrapper<'a, Driver>,
}
impl<'a, Driver> From<WindowsTebBase<'a, Driver, StructLayout32>> for WindowsTeb<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from(value: WindowsTebBase<'a, Driver, StructLayout32>) -> Self {
Self {
inner: WindowsTebWrapper::W32(value),
}
}
}
impl<'a, Driver> From<WindowsTebBase<'a, Driver, StructLayout64>> for WindowsTeb<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn from(value: WindowsTebBase<'a, Driver, StructLayout64>) -> Self {
Self {
inner: WindowsTebWrapper::W64(value),
}
}
}
impl<Driver> VmiVa for WindowsTeb<'_, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
fn va(&self) -> Va {
match &self.inner {
WindowsTebWrapper::W32(inner) => inner.va,
WindowsTebWrapper::W64(inner) => inner.va,
}
}
}
impl<'a, Driver> WindowsTeb<'a, Driver>
where
Driver: VmiRead,
Driver::Architecture: ArchAdapter<Driver>,
{
pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
Self::with_kind(vmi, va, vmi.translation_root(va), WindowsWow64Kind::Native)
}
pub fn with_kind(
vmi: VmiState<'a, WindowsOs<Driver>>,
va: Va,
root: Pa,
kind: WindowsWow64Kind,
) -> Self {
let inner = match kind {
WindowsWow64Kind::Native => WindowsTebWrapper::native(vmi, va, root),
WindowsWow64Kind::X86 => WindowsTebWrapper::w32(vmi, va, root),
};
Self { inner }
}
pub fn peb(&self) -> Result<Option<WindowsPeb<'a, Driver>>, VmiError> {
self.inner.peb()
}
pub fn last_error_value(&self) -> Result<u32, VmiError> {
self.inner.last_error_value()
}
pub fn last_status_value(&self) -> Result<u32, VmiError> {
self.inner.last_status_value()
}
pub fn tls_slot(&self, index: usize) -> Result<u64, VmiError> {
self.inner.tls_slot(index)
}
}