commit 03066e2e5592e81683c38988700590e3080d559b Author: Intege-rs Date: Wed Nov 13 21:41:26 2024 -0500 v0.0.0b diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..99f9c8e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +resolver = "2" +default-members = ["x"] +members = [ + "x", + "sub/core", + "sub/libm", + "sub/pe", + "sub/winu" +] + +[workspace.dependencies] +sub_sample = { path = "sub/sample" } +sub_core = { path = "sub/core" } +sub_libm = { path = "sub/libm" } +sub_pe = { path = "sub/pe" } +sub_winu = { path = "sub/winu" } diff --git a/sub/core/Cargo.toml b/sub/core/Cargo.toml new file mode 100644 index 0000000..014f4b8 --- /dev/null +++ b/sub/core/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "sub_core" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/sub/core/src/arrays.rs b/sub/core/src/arrays.rs new file mode 100644 index 0000000..b6dc3ef --- /dev/null +++ b/sub/core/src/arrays.rs @@ -0,0 +1,80 @@ +use core::fmt::{Debug, Formatter}; + +pub fn fill_with T>(slice: &mut [T], mut func: F) { + slice.iter_mut().enumerate().for_each(|(i,v)|*v = func(i)) +} + + +pub struct FixedVec { + length: usize, + buffer: [core::mem::MaybeUninit;MAX_LEN], +} + +impl FixedVec { + + pub fn new() -> Self { + unsafe { core::mem::zeroed() } + } + + pub fn push(&mut self, value: T) -> Option<()> { + if self.length >= MAX_LEN { return None } + unsafe { *self.buffer[self.length].as_mut_ptr() = value }; + self.length += 1; + Some(()) + } + + pub fn pop(&mut self) -> Option { + if self.length == 0 { return None } + self.length -= 1; + Some(unsafe { self.buffer[self.length].assume_init_read() }) + } + + pub fn extend>(&mut self, mut iter: Iter) -> Result { + let mut count = 0; + loop { + if self.length == MAX_LEN { + return Err(count); + } + match iter.next() { + None => return Ok(count), + Some(value) => { + unsafe { *self.buffer[self.length].as_mut_ptr() = value }; + self.length += 1; + count += 1; + } + } + + } + } + + pub fn as_slice(&self) -> &[T] { + // length can't be larger than MaxLen, use unsafe to dodge the panic + unsafe { core::slice::from_raw_parts(self.buffer.as_ptr() as *const T, self.length) } + } + + pub fn clear(&mut self) { + self.length = 0; + } + +} + +impl Debug for FixedVec { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + Debug::fmt(self.as_slice(), f) + } +} + +impl Drop for FixedVec { + fn drop(&mut self) { + for e in &mut self.buffer[..self.length] { + unsafe { e.assume_init_drop() } + } + } +} + +impl core::fmt::Write for FixedVec { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + _=self.extend(s.as_bytes().iter().cloned()); + Ok(()) + } +} \ No newline at end of file diff --git a/sub/core/src/branching.rs b/sub/core/src/branching.rs new file mode 100644 index 0000000..661e499 --- /dev/null +++ b/sub/core/src/branching.rs @@ -0,0 +1,56 @@ +use core::sync::atomic::Ordering; + +/// Runs code on drop +#[repr(transparent)] +pub struct OnDrop( + // Use a MaybeUninit so we have finer control over when this type is dropped + core::mem::MaybeUninit +); + +impl OnDrop { + + pub fn new(fun: F) -> Self { + Self(core::mem::MaybeUninit::new(fun)) + } + + pub fn cancel(mut self) { + // invoke the functions destructor but not our own + unsafe { self.0.assume_init_drop(); } + core::mem::forget(self); + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.0.assume_init_read()() }; + } +} + +#[repr(transparent)] +pub struct Once(core::sync::atomic::AtomicBool); +impl Once { + pub const fn new() -> Self { + Self(core::sync::atomic::AtomicBool::new(false)) + } + #[inline(always)] + pub fn first(&self) -> bool { + !self.0.swap(true, Ordering::Acquire) + } +} + +pub macro once() { + { + static _ONCE: Once = Once::new(); + _ONCE.first() + } +} + + + + + + + + + + diff --git a/sub/core/src/cast_traits.rs b/sub/core/src/cast_traits.rs new file mode 100644 index 0000000..9213522 --- /dev/null +++ b/sub/core/src/cast_traits.rs @@ -0,0 +1,96 @@ +/// Allows the safe conversion from smaller integer types into larger ones +/// Does not allow signed types to be cast into unsigned types +pub trait Upcast { + fn upcast(self) -> T; +} + +/// Utility trait for casting between types... +pub trait As { + fn cast(self) -> T; +} + +macro_rules! gen_cast { + ($typ1:ty => $($typ2:ty),*) => { + $(impl As<$typ2> for $typ1 { #[inline(always)] fn cast(self) -> $typ2 { self as _ } })* + }; + ($G:ident > $typ1:ty => $($typ2:ty),*) => { + $(impl<$G> As<$typ2> for $typ1 { #[inline(always)] fn cast(self) -> $typ2 { self as _ } })* + } +} + +macro_rules! gen_upcast { + ($from:ty => $into:ty) => { + impl Upcast<$into> for $from { + fn upcast(self) -> $into { + self as $into + } + } + }; +} + +gen_cast!(u8 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(u16 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(u32 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(u64 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(u128 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(i8 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(i16 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(i32 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(i64 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(i128 => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(usize => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(isize => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); + +gen_cast!(T>*const T => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); +gen_cast!(T>*mut T => u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); + +impl As<*const T> for *const F { fn cast(self) -> *const T { self as _ } } +impl As<*mut T> for *const F { fn cast(self) -> *mut T { self as _ } } +impl As<*const T> for *mut F { fn cast(self) -> *const T { self as _ } } +impl As<*mut T> for *mut F { fn cast(self) -> *mut T { self as _ } } +impl As<*const T> for &T { fn cast(self) -> *const T { self as _ } } +impl As<*mut T> for &mut T { fn cast(self) -> *mut T { self as _ } } + +// Unsigned +gen_upcast!(u8 => u8); +gen_upcast!(u8 => u16); +gen_upcast!(u8 => u32); +gen_upcast!(u8 => u64); +gen_upcast!(u16 => u16); +gen_upcast!(u16 => u32); +gen_upcast!(u16 => u64); +gen_upcast!(u32 => u32); +gen_upcast!(u32 => u64); +gen_upcast!(u64 => u64); + +// Signed +gen_upcast!(i8 => i8); +gen_upcast!(i8 => i16); +gen_upcast!(i8 => i32); +gen_upcast!(i8 => i64); +gen_upcast!(i16 => i16); +gen_upcast!(i16 => i32); +gen_upcast!(i16 => i64); +gen_upcast!(i32 => i32); +gen_upcast!(i32 => i64); +gen_upcast!(i64 => i64); + +// Pointer Sized + +gen_upcast!(u8 => usize); +gen_upcast!(i8 => isize); +gen_upcast!(u16 => usize); +gen_upcast!(i16 => isize); + +#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))] +gen_upcast!(u32 => usize); +#[cfg(any(target_pointer_width = "64"))] +gen_upcast!(u64 => usize); + +#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))] +gen_upcast!(i32 => isize); +#[cfg(any(target_pointer_width = "64"))] +gen_upcast!(i64 => isize); + +gen_upcast!(isize => isize); +gen_upcast!(usize => usize); \ No newline at end of file diff --git a/sub/core/src/data.rs b/sub/core/src/data.rs new file mode 100644 index 0000000..c1a5ad6 --- /dev/null +++ b/sub/core/src/data.rs @@ -0,0 +1,49 @@ +use core::cmp::Ordering; +use crate::cast_traits::As; + +/// Converts reference of struct to binary slice +#[inline(always)] +pub fn slicify(value: &T) -> &[u8] { + let ptr = value as *const T as *const u8; + unsafe { core::slice::from_raw_parts(ptr, core::mem::size_of::()) } +} + +/// Converts reference of struct to binary slice +#[inline(always)] +pub unsafe fn slicify_mut(value: &mut T) -> &mut [u8] { + let ptr = value as *mut T as *mut u8; + core::slice::from_raw_parts_mut(ptr, core::mem::size_of::()) +} + + +/// converts a non mutable reference into a mutable one +#[inline(always)] +pub unsafe fn mutify(nr: &T) -> &mut T { + #[allow(invalid_reference_casting)] + &mut *(nr as *const T as *mut T) +} + +/// converts a reference of any lifetime to 'static +#[inline(always)] +pub unsafe fn statify<'a, T>(nr: &'a T) -> &'static T { + &*(nr as *const T) +} + +/// converts mutable a reference of any lifetime to 'static +#[inline(always)] +pub unsafe fn statify_mut<'a, T>(nr: &'a mut T) -> &'static mut T { + &mut *(nr as *mut T) +} + +/// gets the distance between two references +pub fn distance(p1: impl As, p2: impl As) -> usize { + let (p1, p2) = (p1.cast(), p2.cast()); + match p1.cmp(&p2) { + Ordering::Less => p2 - p1, + Ordering::Greater => p1 - p2, + Ordering::Equal => 0, + } +} + + + diff --git a/sub/core/src/ext/iter.rs b/sub/core/src/ext/iter.rs new file mode 100644 index 0000000..56b769e --- /dev/null +++ b/sub/core/src/ext/iter.rs @@ -0,0 +1,62 @@ + +pub trait IterExt: Iterator { + + #[inline] + fn take_until

(self, predicate: P) -> TakeUntil + where + Self: Sized, + P: FnMut(&Self::Item) -> bool, + { + TakeUntil::new(self, predicate) + } + +} + +impl IterExt for T {} + +#[derive(Clone)] +pub struct TakeUntil { + iter: I, + flag: bool, + predicate: P, +} + +impl TakeUntil { + pub(in super) fn new(iter: I, predicate: P) -> TakeUntil { + TakeUntil { iter, flag: false, predicate } + } +} + +impl Iterator for TakeUntil +where + P: FnMut(&I::Item) -> bool, +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.flag { + None + } else { + let x = self.iter.next()?; + if (self.predicate)(&x) { + Some(x) + } else { + self.flag = true; + Some(x) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.flag { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + } +} + + diff --git a/sub/core/src/ext/ptr.rs b/sub/core/src/ext/ptr.rs new file mode 100644 index 0000000..a9eeef2 --- /dev/null +++ b/sub/core/src/ext/ptr.rs @@ -0,0 +1,48 @@ + +pub const fn null() -> T { T::NULL } +pub fn iterate(pointer: T) -> T::IterType { + pointer.into_iter() +} + +pub trait Pointer { + type IterType; + const NULL: Self; + fn into_iter(self) -> Self::IterType; +} + + +pub struct PIter(*const T); +pub struct PIterMut(*mut T); + +impl Iterator for PIter { + type Item = &'static T; + fn next(&mut self) -> Option { + unsafe { + let r = Some(&*self.0); + self.0 = self.0.offset(1isize); + r + } + } +} + +impl Iterator for PIterMut { + type Item = &'static mut T; + fn next(&mut self) -> Option { + unsafe { + let r = Some(&mut *self.0); + self.0 = self.0.offset(1isize); + r + } + } +} +impl Pointer for *const T { + type IterType = PIter; + const NULL: Self = core::ptr::null(); + fn into_iter(self) -> Self::IterType { PIter(self) } +} + +impl Pointer for *mut T { + type IterType = PIterMut; + const NULL: Self = core::ptr::null_mut(); + fn into_iter(self) -> Self::IterType { PIterMut(self) } +} diff --git a/sub/core/src/ffi.rs b/sub/core/src/ffi.rs new file mode 100644 index 0000000..3e6db85 --- /dev/null +++ b/sub/core/src/ffi.rs @@ -0,0 +1,38 @@ + +/// appends zeroes to the end of the string and converts it into a pointer +/// useful for quick ffi +pub macro cstr($str:expr) { + concat!($str,"\0\0").as_ptr() as *const _ +} + + + +/// utility macro for inline c functions +/// +/// | macro | rust | +/// |-----------|----------| +/// | ```cfn!( () -> usize )``` | ``` extern "C" fn() -> usize``` | +/// | ```cfn!( (usize) -> usize )``` | ``` extern "C" fn(usize) -> usize``` | +/// | ```cfn!( (usize) )``` | ``` extern "C" fn(usize)``` | +/// | ```cfn!( (u32, usize, usize) -> u32 )``` | ``` extern "C" fn(u32, usize, usize) -> u32``` | +pub macro cfn($str:expr) { + ( ($($t:ty),*)) => { + extern "C" fn($( $t ),* ) + }; + ( ($($t:ty),*) -> $r:ty) => { + extern "C" fn($( $t ),* ) -> $r + } +} + +#[inline(always)] +pub fn _chain_helper(address: usize, links: [usize;N]) -> usize { + links.iter().fold(address, |b,r| unsafe {*((b + *r) as *const usize)} ) +} + +#[allow(unused)] +use crate::cast_traits::As; +pub macro ptr_chain( $base:expr, $($link:expr),* ) { + _chain_helper(As::::cast($base), [ + $(As::::cast($link)),* + ]) +} \ No newline at end of file diff --git a/sub/core/src/fnv1.rs b/sub/core/src/fnv1.rs new file mode 100644 index 0000000..348fcdb --- /dev/null +++ b/sub/core/src/fnv1.rs @@ -0,0 +1,76 @@ +const INITIAL_STATE: u64 = 0xcbf29ce484222325; +const PRIME: u64 = 0x100000001b3; + +//noinspection DuplicatedCode +pub const fn hash(bytes: &[u8]) -> u64 { + let mut hash = INITIAL_STATE; + let mut i = 0; + while i < bytes.len() { + hash = hash ^ bytes[i] as u64; + hash = hash.wrapping_mul(PRIME); + i += 1; + } + hash +} + +//noinspection DuplicatedCode +pub const fn hash32(bytes: &[u32]) -> u64 { + let mut hash = INITIAL_STATE; + let mut i = 0; + while i < bytes.len() { + hash = hash ^ bytes[i] as u64; + hash = hash.wrapping_mul(PRIME); + i += 1; + } + hash +} + +//noinspection DuplicatedCode +#[inline(always)] +pub const fn hash64(bytes: &[u64]) -> u64 { + let mut hash = INITIAL_STATE; + let mut i = 0; + while i < bytes.len() { + hash = hash ^ bytes[i]; + hash = hash.wrapping_mul(PRIME); + i += 1; + } + hash +} + +//noinspection DuplicatedCode +#[inline(always)] +pub const fn hash_utf8(bytes: &[u8]) -> u64 { + let mut hash = INITIAL_STATE; + let mut i = 0; + while i < bytes.len() { + + let char = match bytes[i] { + 0x40..=0x5A => bytes[i] + 0x20, + _ => bytes[i], + } as u64; + + hash = hash ^ (char); + hash = hash.wrapping_mul(PRIME); + i += 1; + } + hash +} + +//noinspection DuplicatedCode +pub const fn hash_utf16(bytes: &[u16]) -> u64 { + let mut hash = INITIAL_STATE; + let mut i = 0; + while i < bytes.len() { + + let char = match bytes[i] { + 0x40..=0x5A => bytes[i] + 0x20, + _ => bytes[i], + } as u64; + + hash = hash ^ (char); + hash = hash.wrapping_mul(PRIME); + i += 1; + } + hash +} \ No newline at end of file diff --git a/sub/core/src/lib.rs b/sub/core/src/lib.rs new file mode 100644 index 0000000..78ef44c --- /dev/null +++ b/sub/core/src/lib.rs @@ -0,0 +1,58 @@ +#![no_std] #![feature(decl_macro)] #![allow(unused)] + + +// +// Internal modules +// +pub mod cast_traits; +pub mod data; +pub mod arrays; +pub mod branching; +pub mod ffi; + +pub mod ext { + pub mod iter; + pub mod ptr; +} + +pub mod time; + +pub mod fnv1; +pub mod pstruct; + +// +// Export Preludes: +// + +pub mod prelude { + pub use crate::cast_traits::{As, Upcast}; + pub use crate::data::{ + distance, + mutify, + slicify, + slicify_mut, + statify, + statify_mut + }; + pub use crate::arrays::{ + fill_with, + FixedVec, + }; + pub use crate::branching::{ + OnDrop, + Once, + once + }; + pub use crate::ffi::{cfn, cstr, ptr_chain}; + pub use crate::ext::iter::IterExt; + pub use crate::ext::ptr::{Pointer, iterate}; + pub use crate::time::dur; + pub use crate::fnv1::*; + pub use crate::pstruct::struct_offset; +} + +pub mod public { + pub use crate::ext::iter::TakeUntil; + pub use crate::ext::ptr::{PIter, PIterMut}; + pub use crate::pstruct::VirtualOffset; +} diff --git a/sub/core/src/pstruct.rs b/sub/core/src/pstruct.rs new file mode 100644 index 0000000..5611cd1 --- /dev/null +++ b/sub/core/src/pstruct.rs @@ -0,0 +1,99 @@ +#![allow(unused)] + +use core::fmt::{Debug, Display, Formatter, UpperHex}; +use core::marker::PhantomData; +use core::mem::transmute; +use core::ops::{ControlFlow, Deref, DerefMut, Index, IndexMut}; + +pub struct VirtualOffset(PhantomData); + +impl VirtualOffset { + + #[inline(always)] + pub(crate) fn vo_as_ptr(&self) -> *mut T { + ((self as *const _ as usize) + O) as *mut T + } + + #[inline(always)] + pub(crate) fn offset() -> usize { O } + + /// gets a ref to the underlying type + /// just an alias for the deref trait so it doesnt need to be imported + pub fn r#ref(&self) -> &T { + self.deref() + } + +} + +impl Deref for VirtualOffset { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + unsafe { transmute(((self as *const _ as usize) + O) as *const T)} + } +} + +impl DerefMut for VirtualOffset { + + #[inline(always)] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { transmute(((self as *mut _ as usize) + O) as *mut T)} + } +} + +// ============================== +// Index +// ============================== + +impl, const O: usize> Index for VirtualOffset { + type Output = T::Output; + fn index(&self, index: I) -> &Self::Output { + unsafe { &*self.vo_as_ptr() }.index(index) + } +} + +impl, const O: usize> IndexMut for VirtualOffset { + fn index_mut(&mut self, index: I) -> &mut Self::Output { + unsafe { &mut *self.vo_as_ptr() }.index_mut(index) + } +} + +// ============================== +// Display + Debug +// ============================== + +// Proxy the Display trait +impl Display for VirtualOffset { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + self.deref().fmt(f) + } +} + +// Proxy the UpperHex trait +impl UpperHex for VirtualOffset { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + self.deref().fmt(f) + } +} + +// Proxy the Debug trait (in debug builds) +impl Debug for VirtualOffset { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + self.deref().fmt(f) + } +} + +// ============================== +// Macro +// ============================== + +pub macro struct_offset { + ($offset:literal, $type:ty) => { + $crate::VirtualOffset<$type, $offset> + } +} + + + + diff --git a/sub/core/src/time.rs b/sub/core/src/time.rs new file mode 100644 index 0000000..c8d1960 --- /dev/null +++ b/sub/core/src/time.rs @@ -0,0 +1,46 @@ + +#![allow(unused)] + +use core::time::Duration; + +#[allow(nonstandard_style)] +pub mod __time_units { + + pub mod units { + pub(super) type Milli = u64; + pub(super) type Second = u64; + pub(super) type Minute = u64; + pub(super) type Hour = u64; + pub(super) type Day = u64; + pub(super) type Week = u64; + } + + pub mod plural { + use super::units::*; + pub const milliseconds : Milli = 1; + pub const seconds : Second = 1_000; + pub const hours : Hour = 60_000; + pub const minutes : Minute = 3_600_000; + pub const days : Day = 86_400_000; + pub const weeks : Week = 604_800_000; + } + pub mod singular { + use super::units::*; + pub const millisecond : Milli = super::plural::milliseconds; + pub const second : Second = super::plural::seconds; + pub const hour : Hour = super::plural::hours; + pub const minute : Minute = super::plural::minutes; + pub const day : Day = super::plural::days; + pub const week : Week = super::plural::weeks; + } +} + +pub macro dur($($amount:tt $unit:ident $(,)?)+) { + core::time::Duration::from_millis(0u64 $( + ($crate::time::time_unit!( $amount, $unit)) )+ ) +} + +macro time_unit { + (1, $unit:ident) => { $crate::time::__time_units::singular::$unit }, + ($number:literal, $unit:ident) => { $number * $crate::time::__time_units::plural::$unit } +} + diff --git a/sub/libm/Cargo.toml b/sub/libm/Cargo.toml new file mode 100644 index 0000000..24c69d7 --- /dev/null +++ b/sub/libm/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "sub_libm" +version = "0.1.0" +edition = "2021" + +[dependencies] +libm = "*" \ No newline at end of file diff --git a/sub/libm/src/lib.rs b/sub/libm/src/lib.rs new file mode 100644 index 0000000..bdedbff --- /dev/null +++ b/sub/libm/src/lib.rs @@ -0,0 +1,168 @@ +#![no_std] #![feature(core_intrinsics)] #![allow(internal_features)] + +// +// Export Preludes: +// + +pub mod prelude { + pub use crate::Libm; +} + +pub mod public { + pub use libm::*; +} + + +//@formatter:off +pub trait Libm: Sized + Copy { + fn acos (self) -> Self; + fn acosh (self) -> Self; + fn asin (self) -> Self; + fn asinh (self) -> Self; + fn atan (self) -> Self; + fn atanh (self) -> Self; + fn cbrt (self) -> Self; + fn ceil (self) -> Self; + fn cos (self) -> Self; + fn cosh (self) -> Self; + fn erfc (self) -> Self; + fn exp (self) -> Self; + fn exp10 (self) -> Self; + fn exp2 (self) -> Self; + fn expm1 (self) -> Self; + fn fabs (self) -> Self; + fn floor (self) -> Self; + fn log (self) -> Self; + fn log10 (self) -> Self; + fn log1p (self) -> Self; + fn log2 (self) -> Self; + fn rint (self) -> Self; + fn round (self) -> Self; + fn sin (self) -> Self; + fn sinh (self) -> Self; + fn sqrt (self) -> Self; + fn tan (self) -> Self; + fn tanh (self) -> Self; + fn tgamma (self) -> Self; + fn trunc (self) -> Self; + fn ilogb (self) -> i32; + fn frexp (self) -> (Self, i32); + fn sincos (self) -> (Self, Self); + fn scalbn (self, i: i32) -> Self; + fn powi (self, i: i32) -> Self; + fn hypot (self, other: Self) -> Self; + fn atan2 (self, other: Self) -> Self; + fn copysign (self, other: Self) -> Self; + fn fdim (self, other: Self) -> Self; + fn fmax (self, other: Self) -> Self; + fn fmin (self, other: Self) -> Self; + fn fmod (self, other: Self) -> Self; + fn nextafter (self, other: Self) -> Self; + fn pow (self, other: Self) -> Self; + fn remainder (self, other: Self) -> Self; + fn remquo (self, other: Self) -> (Self, i32); + fn fma (self, o1: Self, o2: Self) -> Self; +} + +impl Libm for f64 { + fn acos (self) -> Self { libm::acos(self) } + fn acosh (self) -> Self { libm::acosh(self) } + fn asin (self) -> Self { libm::asin(self) } + fn asinh (self) -> Self { libm::asinh(self) } + fn atan (self) -> Self { libm::atan(self) } + fn atanh (self) -> Self { libm::atanh(self) } + fn cbrt (self) -> Self { libm::cbrt(self) } + fn ceil (self) -> Self { libm::ceil(self) } + fn cos (self) -> Self { libm::cos(self) } + fn cosh (self) -> Self { libm::cosh(self) } + fn erfc (self) -> Self { libm::erfc(self) } + fn exp (self) -> Self { libm::exp(self) } + fn exp10 (self) -> Self { libm::exp10(self) } + fn exp2 (self) -> Self { libm::exp2(self) } + fn expm1 (self) -> Self { libm::expm1(self) } + fn fabs (self) -> Self { libm::fabs(self) } + fn floor (self) -> Self { libm::floor(self) } + fn log (self) -> Self { libm::log(self) } + fn log10 (self) -> Self { libm::log10(self) } + fn log1p (self) -> Self { libm::log1p(self) } + fn log2 (self) -> Self { libm::log2(self) } + fn rint (self) -> Self { libm::rint(self) } + fn round (self) -> Self { libm::round(self) } + fn sin (self) -> Self { libm::sin(self) } + fn sinh (self) -> Self { libm::sinh(self) } + fn sqrt (self) -> Self { libm::sqrt(self) } + fn tan (self) -> Self { libm::tan(self) } + fn tanh (self) -> Self { libm::tanh(self) } + fn tgamma (self) -> Self { libm::tgamma(self) } + fn trunc (self) -> Self { libm::trunc(self) } + fn ilogb (self) -> i32 { libm::ilogb(self) } + fn frexp (self) -> (Self, i32) { libm::frexp(self) } + fn sincos (self) -> (Self, Self) { libm::sincos(self) } + fn scalbn (self, i: i32) -> Self { libm::scalbn(self, i) } + fn hypot (self, other: Self) -> Self { libm::hypot(self, other) } + fn atan2 (self, other: Self) -> Self { libm::atan2(self, other) } + fn copysign (self, other: Self) -> Self { libm::copysign(self, other) } + fn fdim (self, other: Self) -> Self { libm::fdim(self, other) } + fn fmax (self, other: Self) -> Self { libm::fmax(self, other) } + fn fmin (self, other: Self) -> Self { libm::fmin(self, other) } + fn fmod (self, other: Self) -> Self { libm::fmod(self, other) } + fn nextafter (self, other: Self) -> Self { libm::nextafter(self, other) } + fn pow (self, other: Self) -> Self { libm::pow(self, other) } + fn remainder (self, other: Self) -> Self { libm::remainder(self, other) } + fn remquo (self, other: Self) -> (Self, i32) { libm::remquo(self, other) } + fn fma (self, o1: Self, o2: Self) -> Self { libm::fma(self, o1, o2) } + + fn powi(self, i: i32) -> Self { unsafe { core::intrinsics::powif64(self, i) } } + +} + +impl Libm for f32 { + fn acos (self) -> Self { libm::acosf(self) } + fn acosh (self) -> Self { libm::acoshf(self) } + fn asin (self) -> Self { libm::asinf(self) } + fn asinh (self) -> Self { libm::asinhf(self) } + fn atan (self) -> Self { libm::atanf(self) } + fn atanh (self) -> Self { libm::atanhf(self) } + fn cbrt (self) -> Self { libm::cbrtf(self) } + fn ceil (self) -> Self { libm::ceilf(self) } + fn cos (self) -> Self { libm::cosf(self) } + fn cosh (self) -> Self { libm::coshf(self) } + fn erfc (self) -> Self { libm::erfcf(self) } + fn exp (self) -> Self { libm::expf(self) } + fn exp10 (self) -> Self { libm::exp10f(self) } + fn exp2 (self) -> Self { libm::exp2f(self) } + fn expm1 (self) -> Self { libm::expm1f(self) } + fn fabs (self) -> Self { libm::fabsf(self) } + fn floor (self) -> Self { libm::floorf(self) } + fn log (self) -> Self { libm::logf(self) } + fn log10 (self) -> Self { libm::log10f(self) } + fn log1p (self) -> Self { libm::log1pf(self) } + fn log2 (self) -> Self { libm::log2f(self) } + fn rint (self) -> Self { libm::rintf(self) } + fn round (self) -> Self { libm::roundf(self) } + fn sin (self) -> Self { libm::sinf(self) } + fn sinh (self) -> Self { libm::sinhf(self) } + fn sqrt (self) -> Self { libm::sqrtf(self) } + fn tan (self) -> Self { libm::tanf(self) } + fn tanh (self) -> Self { libm::tanhf(self) } + fn tgamma (self) -> Self { libm::tgammaf(self) } + fn trunc (self) -> Self { libm::truncf(self) } + fn ilogb (self) -> i32 { libm::ilogbf(self) } + fn frexp (self) -> (Self, i32) { libm::frexpf(self) } + fn sincos (self) -> (Self, Self) { libm::sincosf(self) } + fn scalbn (self, i: i32) -> Self { libm::scalbnf(self, i) } + fn hypot (self, other: Self) -> Self { libm::hypotf(self, other) } + fn atan2 (self, other: Self) -> Self { libm::atan2f(self, other) } + fn copysign (self, other: Self) -> Self { libm::copysignf(self, other) } + fn fdim (self, other: Self) -> Self { libm::fdimf(self, other) } + fn fmax (self, other: Self) -> Self { libm::fmaxf(self, other) } + fn fmin (self, other: Self) -> Self { libm::fminf(self, other) } + fn fmod (self, other: Self) -> Self { libm::fmodf(self, other) } + fn nextafter (self, other: Self) -> Self { libm::nextafterf(self, other) } + fn pow (self, other: Self) -> Self { libm::powf(self, other) } + fn remainder (self, other: Self) -> Self { libm::remainderf(self, other) } + fn remquo (self, other: Self) -> (Self, i32) { libm::remquof(self, other) } + fn fma (self, o1: Self, o2: Self) -> Self { libm::fmaf(self, o1, o2) } + + fn powi(self, i: i32) -> Self { unsafe { core::intrinsics::powif32(self, i) } } +} diff --git a/sub/pe/Cargo.toml b/sub/pe/Cargo.toml new file mode 100644 index 0000000..fee7c9e --- /dev/null +++ b/sub/pe/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "sub_pe" +version = "0.1.0" +edition = "2021" + +[features] +windows = [] + +[dependencies] +sub_core = { workspace = true } \ No newline at end of file diff --git a/sub/pe/src/exports.rs b/sub/pe/src/exports.rs new file mode 100644 index 0000000..dd992e9 --- /dev/null +++ b/sub/pe/src/exports.rs @@ -0,0 +1,52 @@ +use crate::imagebase::ImageBase; +use crate::structs::*; + +pub struct ExportIter<'a> { + image: &'a ImageBase, + export_dir: &'a ImageExportDirectory, + export_index: usize, +} + +impl<'a> Iterator for ExportIter<'a> { + type Item = (usize, &'static [u8]); + + fn next(&mut self) -> Option { + match self.export_index < self.export_dir.number_of_name_pointers as usize { + true => unsafe { + #[inline(always)] + unsafe fn u8_nul_terminated(ptr: *const u8) -> &'static [u8] { + let mut end = ptr; + while *end != 0 { end = end.add(1) } + let len = (end as usize) - (ptr as usize); + &*core::ptr::slice_from_raw_parts(ptr, len) + } + + let export_functions = self.image.offset(self.export_dir.export_address_table_rva) as *const u32; + let export_names = self.image.offset(self.export_dir.name_pointer_rva) as *const u32; + let export_ordinals = self.image.offset(self.export_dir.ordinal_table_rva) as *const u16; + + let export_name = self.image.offset(*export_names.add(self.export_index)); + let export_ordinal = *export_ordinals.add(self.export_index); + let export_rva = self.image.offset(*export_functions.add(export_ordinal as usize)) as usize; + + self.export_index += 1; + + Some((export_rva, u8_nul_terminated(export_name))) + } + false => None, + } + } +} + +impl ImageBase { + pub unsafe fn exports(&self) -> Option { + let directory = &self.nt_header().optional_header.data_directory[DIRECTORY_ENTRY_EXPORT]; + if directory.size == 0 || directory.virtual_address == 0 { return None; } + let export_directory = &*(self.offset(directory.virtual_address) as *const ImageExportDirectory); + Some(ExportIter { + image: self, + export_dir: export_directory, + export_index: 0, + }) + } +} \ No newline at end of file diff --git a/sub/pe/src/imagebase.rs b/sub/pe/src/imagebase.rs new file mode 100644 index 0000000..4cc8098 --- /dev/null +++ b/sub/pe/src/imagebase.rs @@ -0,0 +1,81 @@ +use core::ops::{Add, Range, Sub}; +use sub_core::cast_traits::Upcast; +use crate::structs::*; + +#[repr(C)] +pub struct ImageBase(()); + +extern "C" { + #[link_name = "__ImageBase"] + static ImageBasePtr: [u8;0]; +} + +impl ImageBase { + + #[inline(always)] + pub fn get() -> &'static ImageBase { + unsafe { &*(ImageBasePtr.as_ptr() as *const ImageBase) } + } + + + #[inline(always)] + pub fn as_ptr(&self) -> usize { + self as *const _ as usize + } + + #[inline(always)] + pub(crate) fn offset>(&self, offset: T) -> *const u8 { + unsafe { (self as *const _ as *const u8).add(offset.upcast()) } + } + + pub unsafe fn dos(&self) -> &ImageDOSHeader { + &*(self as *const _ as *const ImageDOSHeader) + } + + pub unsafe fn dos_mut(&mut self) -> &mut ImageDOSHeader { + &mut *(self as *mut _ as *mut ImageDOSHeader) + } + + pub unsafe fn nt_header(&self) -> &'static ImageNTHeaders64 { + &*(self.offset(self.dos().e_lfanew) as *const ImageNTHeaders64) + } + + pub unsafe fn nt_header_mut(&mut self) -> &'static mut ImageNTHeaders64 { + &mut *(self.offset(self.dos().e_lfanew) as *mut ImageNTHeaders64) + } + + pub unsafe fn sections(&self) -> &[ImageSectionHeader] { + self.nt_header().sections() + } + + pub unsafe fn as_range(&self) -> Range { + self.as_ptr()..self.as_ptr() + self.nt_header().optional_header.size_of_image as usize + } + + pub unsafe fn as_slice(&self) -> &[u8] { + let ptr = self.as_ptr() as *const u8; + let size = self.nt_header().optional_header.size_of_image as usize; + core::slice::from_raw_parts(ptr, size) + } + + pub unsafe fn as_slice_mut(&self) -> &mut [u8] { + let ptr = self.as_ptr() as *mut u8; + let size = self.nt_header().optional_header.size_of_image as usize; + core::slice::from_raw_parts_mut(ptr, size) + } + +} + +impl Add for &ImageBase { + type Output = usize; + fn add(self, rhs: usize) -> Self::Output { + (self as *const _ as usize) + rhs + } +} + +impl Sub for &ImageBase { + type Output = usize; + fn sub(self, rhs: usize) -> Self::Output { + (self as *const _ as usize) + rhs + } +} diff --git a/sub/pe/src/lib.rs b/sub/pe/src/lib.rs new file mode 100644 index 0000000..861e526 --- /dev/null +++ b/sub/pe/src/lib.rs @@ -0,0 +1,28 @@ +#![no_std] + +// +// Internal modules +// + +pub mod structs; + +#[cfg(feature = "windows")] +pub mod imagebase; + +#[cfg(feature = "windows")] +pub mod exports; + +// +// Export Preludes: +// + +pub mod prelude { + #[cfg(feature = "windows")] + pub use crate::imagebase::ImageBase; +} + +pub mod public { + #[cfg(feature = "windows")] + pub use crate::exports::ExportIter; + pub use crate::structs::*; +} diff --git a/sub/pe/src/structs.rs b/sub/pe/src/structs.rs new file mode 100644 index 0000000..3d31cfd --- /dev/null +++ b/sub/pe/src/structs.rs @@ -0,0 +1,199 @@ +// ============================== +// PE stuff +// ============================== + +pub const PE_SIGNATURE: u32 = 0x00004550; +pub const DOS_MAGIC: u16 = 0x5A4D; + +pub const IOH_MAGIC_PE32: u16 = 0x10B; // 32 bit executable +pub const IOH_MAGIC_PE64: u16 = 0x20B; // 64 bit executable +pub const IOH_MAGIC_ROM: u16 = 0x107; // Yes! + +pub const NUMBEROF_DIRECTORY_ENTRIES: usize = 16; + +pub const DIRECTORY_ENTRY_EXPORT: usize = 0x0; // Export Directory +pub const DIRECTORY_ENTRY_IMPORT: usize = 0x1; // Import Directory +pub const DIRECTORY_ENTRY_RESOURCE: usize = 0x2; // Resource Directory +pub const DIRECTORY_ENTRY_EXCEPTION: usize = 0x3; // Exception Directory +pub const DIRECTORY_ENTRY_SECURITY: usize = 0x4; // Security Directory +pub const DIRECTORY_ENTRY_BASERELOC: usize = 0x5; // Base Relocation Table +pub const DIRECTORY_ENTRY_DEBUG: usize = 0x6; // Debug Directory +pub const DIRECTORY_ENTRY_ARCHITECTURE: usize = 0x7; // Architecture Specific Data +pub const DIRECTORY_ENTRY_GLOBALPTR: usize = 0x8; // RVA of GP +pub const DIRECTORY_ENTRY_TLS: usize = 0x9; // TLS Directory +pub const DIRECTORY_ENTRY_LOAD_CONFIG: usize = 0xA; // Load Configuration Directory +pub const DIRECTORY_ENTRY_BOUND_IMPORT: usize = 0xB; // Bound Import Directory in headers +pub const DIRECTORY_ENTRY_IAT: usize = 0xC; // Import Address Table +pub const DIRECTORY_ENTRY_DELAY_IMPORT: usize = 0xD; // Delay Load Import Descriptors +pub const DIRECTORY_ENTRY_COM_DESCRIPTOR: usize = 0xE; // COM Runtime descriptor + +pub const IMAGE_FILE_MACHINE_I386: u16 = 0x014c; +pub const IMAGE_FILE_MACHINE_IA64: u16 = 0x0200; +pub const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664; + + +#[repr(C)] +pub struct ImageDOSHeader { + pub e_magic: u16, + pub e_cblp: u16, + pub e_cp: u16, + pub e_crlc: u16, + pub e_cparhdr: u16, + pub e_minalloc: u16, + pub e_maxalloc: u16, + pub e_ss: u16, + pub e_sp: u16, + pub e_csum: u16, + pub e_ip: u16, + pub e_cs: u16, + pub e_lfarlc: u16, + pub e_ovno: u16, + pub e_res: [u16;4], + pub e_oemid: u16, + pub e_oeminfo: u16, + pub e_res2: [u16;10], + pub e_lfanew: u32, +} + +#[repr(C)] +pub struct ImageNTHeaders64 { + pub signature: u32, + pub file_header: ImageFileHeader, + pub optional_header: ImageOptionalHeader64, +} + +#[repr(C)] +pub struct ImageFileHeader { + pub machine: u16, + pub number_of_sections: u16, + pub timestamp: u32, + pub pointer_to_symbol_table: u32, + pub number_of_symbols: u32, + pub size_of_optional_header: u16, + pub characteristics: u16, +} + +#[repr(C)] +pub struct ImageOptionalHeader64 { + pub magic: u16, + pub major_linker_version: u8, + pub minor_linker_version: u8, + pub size_of_code: u32, + pub size_of_initialized_data: u32, + pub size_of_uninitialized_data: u32, + pub address_of_entry_point: u32, + pub base_of_code: u32, + pub image_base: u64, + pub section_alignment: u32, + pub file_alignment: u32, + pub major_operating_system_version: u16, + pub minor_operating_system_version: u16, + pub major_image_version: u16, + pub minor_image_version: u16, + pub major_subsystem_version: u16, + pub minor_subsystem_version: u16, + pub win32_version_value: u32, + pub size_of_image: u32, + pub size_of_headers: u32, + pub checksum: u32, + pub subsystem: u16, + pub dll_characteristics: u16, + pub size_of_stack_reserve: u64, + pub size_of_stack_commit: u64, + pub size_of_heap_reserve: u64, + pub size_of_heap_commit: u64, + pub loader_flags: u32, + pub number_of_rva_and_sizes: u32, + pub data_directory: [ImageDataDirectory; NUMBEROF_DIRECTORY_ENTRIES] +} + +#[repr(C)] +pub struct ImageDataDirectory { + pub virtual_address: u32, + pub size: u32, +} + +#[repr(C)] +pub struct ImageSectionHeader { + pub name: [u8;8], + pub virtual_size: u32, + pub virtual_address: u32, + pub size_of_raw_data: u32, + pub pointer_to_raw_data: u32, + pub pointer_to_relocations: u32, + pub pointer_to_linenumbers: u32, + pub number_of_relocations: u16, + pub number_of_linenumbers: u16, + pub characteristics: u32, +} + +#[repr(C)] +pub struct ImageImportDescriptor { + pub original_first_thunk: u32, + pub timestamp: u32, + pub forwarder_chain: u32, + pub name: u32, + pub first_thunk: u32, +} + +#[repr(C)] +pub struct ImageBoundImportDescriptor { + pub timestamp: u32, + pub offset_module_name: u16, + pub number_of_module_forwarder_refs: u16, +} + +#[repr(C)] +pub struct ImageImportByName { + pub hint: u16, + pub name: [u8] +} + +#[repr(C)] +pub struct ImageBaseRelocation { + pub virtual_address: u32, + pub size_of_block: u32, +} + +#[repr(C)] +pub struct ImageExportDirectory { + /* 0x00 */pub export_flags: u32, + /* 0x04 */pub timestamp: u32, + /* 0x06 */pub major_version: u16, + /* 0x08 */pub minor_version: u16, + /* 0x0C */pub name_rva: u32, + /* 0x10 */pub ordinal_base: u32, + /* 0x14 */pub address_table_entries: u32, + /* 0x18 */pub number_of_name_pointers: u32, + /* 0x1C */pub export_address_table_rva: u32, + /* 0x20 */pub name_pointer_rva: u32, + /* 0x24 */pub ordinal_table_rva: u32, +} + +#[repr(C)] +pub struct ImageExportAddressEntry { + pub export_rva: u32, + pub forwarder_rva: u32, +} + +impl ImageDataDirectory { + pub fn contains(&self, offset: u32) -> bool { + // offset - self.virtual_address < self.size + offset.overflowing_sub(self.virtual_address).0 < self.size + } +} + +impl ImageNTHeaders64 { + pub fn sections(&self) -> &[ImageSectionHeader] { + let section_base + = ( &self.optional_header as *const _ as usize ) + + self.file_header.size_of_optional_header as usize; + unsafe { + core::slice::from_raw_parts( + section_base as *const ImageSectionHeader, + self.file_header.number_of_sections as usize) + } + } +} + + diff --git a/sub/winu/Cargo.toml b/sub/winu/Cargo.toml new file mode 100644 index 0000000..1dfa74c --- /dev/null +++ b/sub/winu/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "sub_winu" +version = "0.1.0" +edition = "2021" + +[dependencies] +sub_pe.workspace = true +sub_core.workspace = true \ No newline at end of file diff --git a/sub/winu/src/importer.rs b/sub/winu/src/importer.rs new file mode 100644 index 0000000..9612238 --- /dev/null +++ b/sub/winu/src/importer.rs @@ -0,0 +1,35 @@ +use sub_core::fnv1; + +#[inline(always)] +pub unsafe fn find_import_hashed(module_name: u64, func_name: u64) -> Option { + crate::modules::loaded_modules() + .filter( |&(_,slice)|fnv1::hash_utf16(slice) == module_name).next() + .and_then(|(i,_)|i.exports()) + .and_then(|v|{ + v.filter_map(|(p,n)|(fnv1::hash_utf8(n) == func_name).then_some(p)).next() + }) +} + + + +pub macro lazy_import ( $module:literal $($v:vis fn $name:ident($($pname:ident: $ptype:ty),*) $(-> $rtype:ty)?; )* ) { + $( + #[allow(unused, non_snake_case)] #[inline(always)] + $v fn $name($($pname: $ptype),*) $(-> $rtype)? { + type FTYPE = extern "C" fn($($pname: $ptype),*) $(-> $rtype)?; + static mut FUNC: Option = None; + let function = match unsafe { FUNC } { + Some(function) => function, + None => unsafe { + let import = core::mem::transmute($crate::win32::importer::find_import_hashed( + const { x::hash_utf8($module.as_bytes()) }, + const { x::hash_utf8(stringify!($name).as_bytes()) } + ).unwrap_or(0)); + FUNC = Some(import); + import + } + }; + function($($pname),*) + } + )* +} \ No newline at end of file diff --git a/sub/winu/src/lib.rs b/sub/winu/src/lib.rs new file mode 100644 index 0000000..499b780 --- /dev/null +++ b/sub/winu/src/lib.rs @@ -0,0 +1,23 @@ +#![no_std] #![feature(decl_macro)] + + +// +// Internal modules +// +mod modules; +mod tls; +mod importer; + +// +// Export Preludes: +// + +pub mod prelude { + pub use crate::importer::lazy_import; +} + +pub mod public { + pub use crate::importer::find_import_hashed; + pub use crate::tls::*; + pub use crate::modules::*; +} diff --git a/sub/winu/src/modules.rs b/sub/winu/src/modules.rs new file mode 100644 index 0000000..fc595a4 --- /dev/null +++ b/sub/winu/src/modules.rs @@ -0,0 +1,92 @@ +use sub_pe::imagebase::ImageBase; + + +#[inline(always)] +pub unsafe fn find_module(hash: u64) -> Option<&'static ImageBase> { + use sub_core::fnv1::hash_utf16; + loaded_modules() + .find(|(_, n)|hash_utf16(*n) == hash) + .map(|(i,_)|i) +} + +#[inline(always)] +pub unsafe fn process_image() -> &'static ImageBase { + let mut process_exe: *const ImageBase; + core::arch::asm!( + "mov {x}, gs:[60h]", // TEB->PEB + "mov {x}, [{x} + 10h]", // PEB->ImageBaseAddress + x = out(reg) process_exe, + ); + &*process_exe +} + +#[inline(always)] +pub unsafe fn loaded_modules() -> ModuleIter { + let mut module_link: *const LDR_DATA_TABLE_ENTRY; + core::arch::asm!( + "mov {x}, gs:[60h]", // TEB->PEB + "mov {x}, [{x} + 18h]", // PEB->LDR + "mov {x}, [{x} + 10h]", // LDR->InLoadOrderModuleList + x = out(reg) module_link, + ); + ModuleIter { + entry: (*module_link).prev, + head: (*module_link).prev, + } +} + +pub struct ModuleIter { + entry: *const LDR_DATA_TABLE_ENTRY, + head: *const LDR_DATA_TABLE_ENTRY, +} + +impl Iterator for ModuleIter { + type Item = (&'static ImageBase, &'static [u16]); + + fn next(&mut self) -> Option { + unsafe { + self.entry = (&*self.entry).next; + match self.entry == self.head { + true => { None } + false => { + let module = (*self.entry).module; + let name = (*self.entry).name.as_slice(); + Some((&*module,name)) + } + } + } + } +} + + + +/* + FFI STRUCTS + */ +#[repr(C)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct UNICODE_STRING { + pub length: u16, + pub capacity: u16, + pub buffer: *const u16, +} + +#[repr(C)] +#[allow(non_camel_case_types)] +struct LDR_DATA_TABLE_ENTRY { + /* 0x00 */ pub next: *const LDR_DATA_TABLE_ENTRY, + /* 0x08 */ pub prev: *const LDR_DATA_TABLE_ENTRY, + /* 0x10 */ pub reserved2: [usize;4], + /* 0x30 */ pub module: *const ImageBase, + /* 0x38 */ pub entry_point: *const (), + /* 0x40 */ pub reserved3: usize, + /* 0x48 */ pub path: UNICODE_STRING, + /* 0x58 */ pub name: UNICODE_STRING, +} + +impl UNICODE_STRING { + pub fn as_slice(&self) -> &'static [u16] { + unsafe { core::slice::from_raw_parts(self.buffer, (self.length / 2) as usize) } + } +} diff --git a/sub/winu/src/tls.rs b/sub/winu/src/tls.rs new file mode 100644 index 0000000..e1ec1da --- /dev/null +++ b/sub/winu/src/tls.rs @@ -0,0 +1,54 @@ +/// read the value in the given tls slot +pub unsafe fn read_tls(index: u32) -> usize { + let mut tls_slot: usize; + core::arch::asm!( + "mov {x}, gs:[1480h + {y:r} * 8]", + x = out(reg) tls_slot, + y = in(reg) index + ); + tls_slot +} + +/// write a value into the given tls slot +pub unsafe fn write_tls(index: u32, value: usize) { + core::arch::asm!( + "mov gs:[1480h + {y:r} * 8], {x}", + x = in(reg) value, + y = in(reg) index + ); +} + +#[inline(always)] +unsafe fn read_tls_bitmap() -> u64 { + let mut _tls: u64 = 0; + core::arch::asm!( + "mov {x}, gs:[60h]", // TEB->PEB + "mov {x}, [{x} + 80h]", // PEB->TlsBitmap + x = out(reg) _tls, + ); + _tls +} + +#[inline(always)] +unsafe fn write_tls_bitmap(value: u64) { + let peb: u64 = 0; + core::arch::asm!( + "mov {x}, gs:[60h]", // TEB->PEB + "mov [{x} + 80h], {y}", // PEB->TlsBitmap + x = in(reg) peb, + y = in(reg) value, + ); +} + +/// acquires a tls slot +pub unsafe fn acquire_tls() -> Option { + let bitmap = read_tls_bitmap(); + (0..64) + .filter(|i| bitmap & ( 1u64 << i ) == 0) + .inspect(|i|{ write_tls_bitmap(bitmap | ( 1u64 << i)) }).next() +} + +/// free's the given tls slot +pub unsafe fn release_tls(slot: u32) { + write_tls_bitmap(read_tls_bitmap() & !(1 << slot )) +} \ No newline at end of file diff --git a/x/Cargo.toml b/x/Cargo.toml new file mode 100644 index 0000000..42a614e --- /dev/null +++ b/x/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "x" +version = "0.1.0" +edition = "2021" + +[features] +default = ["core"] +core = ["sub_core"] +libm = ["sub_libm"] +pe = ["sub_pe"] + +winuser = ["sub_winu", "pe", "sub_pe/windows"] + +[dependencies] +sub_core = { workspace = true, optional = true } +sub_libm = { workspace = true, optional = true} +sub_pe = { workspace = true, optional = true } +sub_winu = { workspace = true, optional = true } \ No newline at end of file diff --git a/x/src/lib.rs b/x/src/lib.rs new file mode 100644 index 0000000..36576ea --- /dev/null +++ b/x/src/lib.rs @@ -0,0 +1,21 @@ +#![no_std] #![feature(decl_macro)] #![allow(unused)] + + +macro_rules! import { + ($module:ident, $name:ident) => { + pub use $module::prelude::*; + pub use $module::public as $name; + }; + ($module:ident, $name:ident, $feature:literal) => { + #[cfg(feature = $feature)] + pub use $module::prelude::*; + #[cfg(feature = $feature)] + pub use $module::public as $name; + }; +} + + +import!(sub_core, core, "core"); +import!(sub_libm, libm, "libm"); +import!(sub_pe, pe, "pe"); +import!(sub_winu, win, "winuser"); diff --git a/x/tests/test_core.rs b/x/tests/test_core.rs new file mode 100644 index 0000000..57ea7ed --- /dev/null +++ b/x/tests/test_core.rs @@ -0,0 +1,21 @@ + +#[test] +pub fn test_once() { + let mut i = 0; + for _ in 0..3 { + if x::once!() { i+= 1; } + if x::once!() { i+= 1; } + } + assert_eq!(i, 2); +} + + + +#[test] +pub fn test_chain() { + let a = 0x1337; + let b = [None,None,Some(&a)]; + let c = [None,Some(&b), None]; + assert_eq!(0x1337, x::ptr_chain!(&c as *const _, 0x8, 0x10, 0x0)); +} +