use super::offsets::TebOffsets;
use crate::arch::segment;
use crate::error::{Result, WraithError};
use crate::version::WindowsVersion;
use core::ptr::NonNull;
pub struct Teb {
ptr: NonNull<u8>,
offsets: &'static TebOffsets,
}
impl Teb {
pub fn current() -> Result<Self> {
let ptr = unsafe { segment::get_teb() };
let ptr = NonNull::new(ptr).ok_or(WraithError::InvalidTebAccess)?;
let version = WindowsVersion::current()?;
let offsets = TebOffsets::for_version(&version)?;
Ok(Self { ptr, offsets })
}
pub fn as_ptr(&self) -> *mut u8 {
self.ptr.as_ptr()
}
pub fn process_id(&self) -> u32 {
unsafe {
let addr = self.ptr.as_ptr().add(self.offsets.client_id);
#[cfg(target_arch = "x86_64")]
{
*(addr as *const u64) as u32
}
#[cfg(target_arch = "x86")]
{
*(addr as *const u32)
}
}
}
pub fn thread_id(&self) -> u32 {
unsafe {
let addr = self.ptr.as_ptr().add(self.offsets.client_id);
#[cfg(target_arch = "x86_64")]
{
let tid_addr = addr.add(8);
*(tid_addr as *const u64) as u32
}
#[cfg(target_arch = "x86")]
{
let tid_addr = addr.add(4);
*(tid_addr as *const u32)
}
}
}
pub fn peb(&self) -> *mut u8 {
unsafe {
let addr = self.ptr.as_ptr().add(self.offsets.peb);
#[cfg(target_arch = "x86_64")]
{
*(addr as *const u64) as *mut u8
}
#[cfg(target_arch = "x86")]
{
*(addr as *const u32) as *mut u8
}
}
}
pub fn last_error(&self) -> u32 {
unsafe {
let addr = self.ptr.as_ptr().add(self.offsets.last_error);
*(addr as *const u32)
}
}
pub fn set_last_error(&mut self, value: u32) {
unsafe {
let addr = self.ptr.as_ptr().add(self.offsets.last_error);
*(addr as *mut u32) = value;
}
}
pub fn stack_base(&self) -> usize {
unsafe {
let addr = self.ptr.as_ptr().add(self.offsets.stack_base);
#[cfg(target_arch = "x86_64")]
{
*(addr as *const u64) as usize
}
#[cfg(target_arch = "x86")]
{
*(addr as *const u32) as usize
}
}
}
pub fn stack_limit(&self) -> usize {
unsafe {
let addr = self.ptr.as_ptr().add(self.offsets.stack_limit);
#[cfg(target_arch = "x86_64")]
{
*(addr as *const u64) as usize
}
#[cfg(target_arch = "x86")]
{
*(addr as *const u32) as usize
}
}
}
}