v0.0.0b
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@@ -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" }
|
||||
6
sub/core/Cargo.toml
Normal file
6
sub/core/Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "sub_core"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
80
sub/core/src/arrays.rs
Normal file
80
sub/core/src/arrays.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use core::fmt::{Debug, Formatter};
|
||||
|
||||
pub fn fill_with<T, F: FnMut(usize) -> T>(slice: &mut [T], mut func: F) {
|
||||
slice.iter_mut().enumerate().for_each(|(i,v)|*v = func(i))
|
||||
}
|
||||
|
||||
|
||||
pub struct FixedVec<const MAX_LEN: usize, T> {
|
||||
length: usize,
|
||||
buffer: [core::mem::MaybeUninit<T>;MAX_LEN],
|
||||
}
|
||||
|
||||
impl<const MAX_LEN: usize, T: Sized> FixedVec<MAX_LEN, T> {
|
||||
|
||||
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<T> {
|
||||
if self.length == 0 { return None }
|
||||
self.length -= 1;
|
||||
Some(unsafe { self.buffer[self.length].assume_init_read() })
|
||||
}
|
||||
|
||||
pub fn extend<Iter: Iterator<Item=T>>(&mut self, mut iter: Iter) -> Result<usize, usize> {
|
||||
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<const MAX_LEN: usize, T: Debug> Debug for FixedVec<MAX_LEN, T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
Debug::fmt(self.as_slice(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_LEN: usize, T> Drop for FixedVec<MAX_LEN, T> {
|
||||
fn drop(&mut self) {
|
||||
for e in &mut self.buffer[..self.length] {
|
||||
unsafe { e.assume_init_drop() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_LEN: usize> core::fmt::Write for FixedVec<MAX_LEN, u8> {
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
_=self.extend(s.as_bytes().iter().cloned());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
56
sub/core/src/branching.rs
Normal file
56
sub/core/src/branching.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
/// Runs code on drop
|
||||
#[repr(transparent)]
|
||||
pub struct OnDrop<F: FnOnce()>(
|
||||
// Use a MaybeUninit so we have finer control over when this type is dropped
|
||||
core::mem::MaybeUninit<F>
|
||||
);
|
||||
|
||||
impl<F: FnOnce()> OnDrop<F> {
|
||||
|
||||
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<F: FnOnce()> Drop for OnDrop<F> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
96
sub/core/src/cast_traits.rs
Normal file
96
sub/core/src/cast_traits.rs
Normal file
@@ -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<T> {
|
||||
fn upcast(self) -> T;
|
||||
}
|
||||
|
||||
/// Utility trait for casting between types...
|
||||
pub trait As<T> {
|
||||
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<F,T> As<*const T> for *const F { fn cast(self) -> *const T { self as _ } }
|
||||
impl<F,T> As<*mut T> for *const F { fn cast(self) -> *mut T { self as _ } }
|
||||
impl<F,T> As<*const T> for *mut F { fn cast(self) -> *const T { self as _ } }
|
||||
impl<F,T> As<*mut T> for *mut F { fn cast(self) -> *mut T { self as _ } }
|
||||
impl<T> As<*const T> for &T { fn cast(self) -> *const T { self as _ } }
|
||||
impl<T> 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);
|
||||
49
sub/core/src/data.rs
Normal file
49
sub/core/src/data.rs
Normal file
@@ -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<T>(value: &T) -> &[u8] {
|
||||
let ptr = value as *const T as *const u8;
|
||||
unsafe { core::slice::from_raw_parts(ptr, core::mem::size_of::<T>()) }
|
||||
}
|
||||
|
||||
/// Converts reference of struct to binary slice
|
||||
#[inline(always)]
|
||||
pub unsafe fn slicify_mut<T>(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::<T>())
|
||||
}
|
||||
|
||||
|
||||
/// converts a non mutable reference into a mutable one
|
||||
#[inline(always)]
|
||||
pub unsafe fn mutify<T>(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<usize>, p2: impl As<usize>) -> usize {
|
||||
let (p1, p2) = (p1.cast(), p2.cast());
|
||||
match p1.cmp(&p2) {
|
||||
Ordering::Less => p2 - p1,
|
||||
Ordering::Greater => p1 - p2,
|
||||
Ordering::Equal => 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
62
sub/core/src/ext/iter.rs
Normal file
62
sub/core/src/ext/iter.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
pub trait IterExt: Iterator {
|
||||
|
||||
#[inline]
|
||||
fn take_until<P>(self, predicate: P) -> TakeUntil<Self, P>
|
||||
where
|
||||
Self: Sized,
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
TakeUntil::new(self, predicate)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<T: Iterator> IterExt for T {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TakeUntil<I, P> {
|
||||
iter: I,
|
||||
flag: bool,
|
||||
predicate: P,
|
||||
}
|
||||
|
||||
impl<I, P> TakeUntil<I, P> {
|
||||
pub(in super) fn new(iter: I, predicate: P) -> TakeUntil<I, P> {
|
||||
TakeUntil { iter, flag: false, predicate }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator, P> Iterator for TakeUntil<I, P>
|
||||
where
|
||||
P: FnMut(&I::Item) -> bool,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<I::Item> {
|
||||
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<usize>) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
48
sub/core/src/ext/ptr.rs
Normal file
48
sub/core/src/ext/ptr.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
pub const fn null<T: Pointer>() -> T { T::NULL }
|
||||
pub fn iterate<T: Pointer>(pointer: T) -> T::IterType {
|
||||
pointer.into_iter()
|
||||
}
|
||||
|
||||
pub trait Pointer {
|
||||
type IterType;
|
||||
const NULL: Self;
|
||||
fn into_iter(self) -> Self::IterType;
|
||||
}
|
||||
|
||||
|
||||
pub struct PIter<T>(*const T);
|
||||
pub struct PIterMut<T>(*mut T);
|
||||
|
||||
impl<T: 'static> Iterator for PIter<T> {
|
||||
type Item = &'static T;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
let r = Some(&*self.0);
|
||||
self.0 = self.0.offset(1isize);
|
||||
r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Iterator for PIterMut<T> {
|
||||
type Item = &'static mut T;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
let r = Some(&mut *self.0);
|
||||
self.0 = self.0.offset(1isize);
|
||||
r
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> Pointer for *const T {
|
||||
type IterType = PIter<T>;
|
||||
const NULL: Self = core::ptr::null();
|
||||
fn into_iter(self) -> Self::IterType { PIter(self) }
|
||||
}
|
||||
|
||||
impl<T> Pointer for *mut T {
|
||||
type IterType = PIterMut<T>;
|
||||
const NULL: Self = core::ptr::null_mut();
|
||||
fn into_iter(self) -> Self::IterType { PIterMut(self) }
|
||||
}
|
||||
38
sub/core/src/ffi.rs
Normal file
38
sub/core/src/ffi.rs
Normal file
@@ -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<const N: usize>(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::<usize>::cast($base), [
|
||||
$(As::<usize>::cast($link)),*
|
||||
])
|
||||
}
|
||||
76
sub/core/src/fnv1.rs
Normal file
76
sub/core/src/fnv1.rs
Normal file
@@ -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
|
||||
}
|
||||
58
sub/core/src/lib.rs
Normal file
58
sub/core/src/lib.rs
Normal file
@@ -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;
|
||||
}
|
||||
99
sub/core/src/pstruct.rs
Normal file
99
sub/core/src/pstruct.rs
Normal file
@@ -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<T, const O: usize>(PhantomData<T>);
|
||||
|
||||
impl<T, const O: usize> VirtualOffset<T, O> {
|
||||
|
||||
#[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<T, const O: usize> Deref for VirtualOffset<T, O> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { transmute(((self as *const _ as usize) + O) as *const T)}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const O: usize> DerefMut for VirtualOffset<T, O> {
|
||||
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { transmute(((self as *mut _ as usize) + O) as *mut T)}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// Index
|
||||
// ==============================
|
||||
|
||||
impl<I, T: Index<I>, const O: usize> Index<I> for VirtualOffset<T, O> {
|
||||
type Output = T::Output;
|
||||
fn index(&self, index: I) -> &Self::Output {
|
||||
unsafe { &*self.vo_as_ptr() }.index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T: IndexMut<I>, const O: usize> IndexMut<I> for VirtualOffset<T, O> {
|
||||
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<T: Display, const O: usize> Display for VirtualOffset<T, O> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
self.deref().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// Proxy the UpperHex trait
|
||||
impl<T: UpperHex, const O: usize> UpperHex for VirtualOffset<T, O> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
self.deref().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// Proxy the Debug trait (in debug builds)
|
||||
impl<T: Debug, const O: usize> Debug for VirtualOffset<T, O> {
|
||||
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>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
46
sub/core/src/time.rs
Normal file
46
sub/core/src/time.rs
Normal file
@@ -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 }
|
||||
}
|
||||
|
||||
7
sub/libm/Cargo.toml
Normal file
7
sub/libm/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "sub_libm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libm = "*"
|
||||
168
sub/libm/src/lib.rs
Normal file
168
sub/libm/src/lib.rs
Normal file
@@ -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) } }
|
||||
}
|
||||
10
sub/pe/Cargo.toml
Normal file
10
sub/pe/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "sub_pe"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
windows = []
|
||||
|
||||
[dependencies]
|
||||
sub_core = { workspace = true }
|
||||
52
sub/pe/src/exports.rs
Normal file
52
sub/pe/src/exports.rs
Normal file
@@ -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<Self::Item> {
|
||||
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<ExportIter> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
81
sub/pe/src/imagebase.rs
Normal file
81
sub/pe/src/imagebase.rs
Normal file
@@ -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<T: Upcast<usize>>(&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<usize> {
|
||||
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<usize> for &ImageBase {
|
||||
type Output = usize;
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
(self as *const _ as usize) + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<usize> for &ImageBase {
|
||||
type Output = usize;
|
||||
fn sub(self, rhs: usize) -> Self::Output {
|
||||
(self as *const _ as usize) + rhs
|
||||
}
|
||||
}
|
||||
28
sub/pe/src/lib.rs
Normal file
28
sub/pe/src/lib.rs
Normal file
@@ -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::*;
|
||||
}
|
||||
199
sub/pe/src/structs.rs
Normal file
199
sub/pe/src/structs.rs
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8
sub/winu/Cargo.toml
Normal file
8
sub/winu/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "sub_winu"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
sub_pe.workspace = true
|
||||
sub_core.workspace = true
|
||||
35
sub/winu/src/importer.rs
Normal file
35
sub/winu/src/importer.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use sub_core::fnv1;
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn find_import_hashed(module_name: u64, func_name: u64) -> Option<usize> {
|
||||
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<FTYPE> = 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),*)
|
||||
}
|
||||
)*
|
||||
}
|
||||
23
sub/winu/src/lib.rs
Normal file
23
sub/winu/src/lib.rs
Normal file
@@ -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::*;
|
||||
}
|
||||
92
sub/winu/src/modules.rs
Normal file
92
sub/winu/src/modules.rs
Normal file
@@ -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<Self::Item> {
|
||||
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) }
|
||||
}
|
||||
}
|
||||
54
sub/winu/src/tls.rs
Normal file
54
sub/winu/src/tls.rs
Normal file
@@ -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<u32> {
|
||||
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 ))
|
||||
}
|
||||
18
x/Cargo.toml
Normal file
18
x/Cargo.toml
Normal file
@@ -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 }
|
||||
21
x/src/lib.rs
Normal file
21
x/src/lib.rs
Normal file
@@ -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");
|
||||
21
x/tests/test_core.rs
Normal file
21
x/tests/test_core.rs
Normal file
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user