mirror of
https://git.intege.rs/xlib/x.git
synced 2025-12-05 20:35:01 +00:00
initial
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
|
/proc_macro/target
|
||||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
14
.idea/X.iml
generated
Normal file
14
.idea/X.iml
generated
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="CPP_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/proc_macro/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/proc_macro/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/X.iml" filepath="$PROJECT_DIR$/.idea/X.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "x"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
win32 = []
|
||||||
|
no_relocs = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
xgen = { path = "proc_macro"}
|
||||||
53
proc_macro/Cargo.lock
generated
Normal file
53
proc_macro/Cargo.lock
generated
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xgen"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
16
proc_macro/Cargo.toml
Normal file
16
proc_macro/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "xgen"
|
||||||
|
version = "0.0.0"
|
||||||
|
authors = [""]
|
||||||
|
description = "common macros"
|
||||||
|
keywords = []
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
quote = "1"
|
||||||
|
proc-macro2 = "1.0.66"
|
||||||
|
syn = { version = "1.0", features = ["full"] }
|
||||||
|
|
||||||
12
proc_macro/src/lib.rs
Normal file
12
proc_macro/src/lib.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#![feature(proc_macro_quote)]
|
||||||
|
#![feature(proc_macro_span)]
|
||||||
|
#![feature(custom_inner_attributes)]
|
||||||
|
|
||||||
|
use proc_macro::*;
|
||||||
|
|
||||||
|
mod sigscan;
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn signature(input: TokenStream) -> TokenStream {
|
||||||
|
sigscan::macro_proc(input)
|
||||||
|
}
|
||||||
50
proc_macro/src/sigscan.rs
Normal file
50
proc_macro/src/sigscan.rs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
extern crate proc_macro;
|
||||||
|
use proc_macro::*;
|
||||||
|
use syn::*;
|
||||||
|
|
||||||
|
enum Operation {
|
||||||
|
Byte(u8),
|
||||||
|
Wildcard,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_scanner(operations: Vec<Operation>) -> TokenStream {
|
||||||
|
let mut output: String = "| b: &[u8] | -> Option<usize> {\n".to_string();
|
||||||
|
|
||||||
|
output.push_str(format!("for i in 0..b.len()-{} {{",operations.len()).as_str());
|
||||||
|
for (i,op) in operations.iter().enumerate() {
|
||||||
|
if let Operation::Byte(byte) = op {
|
||||||
|
output.push_str(format!("if b[i+{}] != 0x{:x} {{ continue; }}", i, byte).as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str("return Some(i);");
|
||||||
|
output.push_str("};");
|
||||||
|
|
||||||
|
output.push_str("None}");
|
||||||
|
output.parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn macro_proc(input: TokenStream) -> TokenStream {
|
||||||
|
let input = parse_macro_input!(input as LitStr);
|
||||||
|
let input: String = input.value();
|
||||||
|
|
||||||
|
let mut operations = vec![];
|
||||||
|
|
||||||
|
for hex in input.split(" ") {
|
||||||
|
let op = if hex.eq("?") {
|
||||||
|
Operation::Wildcard
|
||||||
|
} else {
|
||||||
|
match u8::from_str_radix(hex, 16) {
|
||||||
|
Ok(hex) => {
|
||||||
|
Operation::Byte(hex)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
panic!("{}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
operations.push(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
return generate_scanner(operations);
|
||||||
|
}
|
||||||
20
src/branching.rs
Normal file
20
src/branching.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! invoke_once {
|
||||||
|
() => {
|
||||||
|
unsafe {
|
||||||
|
static mut __VALUE: bool = false;
|
||||||
|
if __VALUE { false } else { __VALUE = true; true }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// if this is used inside of an unsafe codeblock
|
||||||
|
// use this branch to avoid the unnecessary unsafe block warning
|
||||||
|
(unsafe) => {
|
||||||
|
{
|
||||||
|
static mut __VALUE: bool = false;
|
||||||
|
if __VALUE { false } else { __VALUE = true; true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
40
src/cffi.rs
Normal file
40
src/cffi.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
/// appends zeroes to the end of the string and converts it into a pointer
|
||||||
|
/// useful for quick ffi
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! cstr {
|
||||||
|
($str:expr) => {
|
||||||
|
concat!($str,"\0\0").as_ptr() as *const i8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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``` |
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! cfn {
|
||||||
|
( ($($t:ty),*)) => {
|
||||||
|
extern "C" fn($( $t ),* )
|
||||||
|
};
|
||||||
|
( ($($t:ty),*) -> $r:ty) => {
|
||||||
|
extern "C" fn($( $t ),* ) -> $r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// utility macro for pointer chains
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ptr_chain {
|
||||||
|
($x: expr, $y:expr) => {{
|
||||||
|
(*core::mem::transmute::<_,*const usize>(core::mem::transmute::<_,usize>($x) + $y))
|
||||||
|
}};
|
||||||
|
|
||||||
|
($x: expr, $y:expr, $( $z:expr ),+ ) => {{
|
||||||
|
$crate::ptr_chain!( $crate::ptr_chain!($x, $y), $( $z ),+ )
|
||||||
|
}};
|
||||||
|
}
|
||||||
40
src/data.rs
Normal file
40
src/data.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
use core::cmp::Ordering;
|
||||||
|
use crate::upcast::IntoUsize;
|
||||||
|
|
||||||
|
//noinspection SpellCheckingInspection
|
||||||
|
/// Converts reference of struct to binary slice
|
||||||
|
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
|
||||||
|
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
|
||||||
|
pub unsafe fn mutify<T>(nr: &T) -> &mut T {
|
||||||
|
&mut *(nr as *const T as *mut T)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// converts a reference of any lifetime to 'static
|
||||||
|
pub unsafe fn statify<'a, T>(nr: &'a T) -> &'static T {
|
||||||
|
&*(nr as *const T)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// converts mutable a reference of any lifetime to 'static
|
||||||
|
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 IntoUsize, p2: impl IntoUsize) -> usize {
|
||||||
|
let (p1, p2) = (p1.into_usize(), p2.into_usize());
|
||||||
|
match p1.cmp(&p2) {
|
||||||
|
Ordering::Less => p2 - p1,
|
||||||
|
Ordering::Greater => p1 - p2,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/hash.rs
Normal file
74
src/hash.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
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
|
||||||
|
pub const fn hash64(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
|
||||||
|
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
|
||||||
|
}
|
||||||
43
src/lib.rs
Normal file
43
src/lib.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#![feature(decl_macro)]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
/// Virtual Struct Offset
|
||||||
|
mod vso;
|
||||||
|
pub use vso::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// upcast trait
|
||||||
|
mod upcast;
|
||||||
|
pub use upcast::Upcast;
|
||||||
|
pub use upcast::IntoUsize;
|
||||||
|
|
||||||
|
/// data manipulation utilities
|
||||||
|
mod data;
|
||||||
|
pub use data::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// utility macros for branching
|
||||||
|
/// invoke_once, etc
|
||||||
|
mod branching;
|
||||||
|
pub use branching::*;
|
||||||
|
|
||||||
|
/// Utility macros for c ffi
|
||||||
|
mod cffi;
|
||||||
|
pub use cffi::*;
|
||||||
|
|
||||||
|
/// win32 utilities
|
||||||
|
#[cfg(feature = "win32")]
|
||||||
|
pub mod win32;
|
||||||
|
|
||||||
|
#[cfg(feature = "win32")]
|
||||||
|
pub use win32::{ image_base, image_header, find_kernel32 };
|
||||||
|
|
||||||
|
|
||||||
|
/// re-export the signature macro
|
||||||
|
pub use xgen::signature;
|
||||||
|
|
||||||
|
mod time;
|
||||||
|
pub use time::*;
|
||||||
|
|
||||||
|
mod hash;
|
||||||
|
pub use hash::*;
|
||||||
52
src/time.rs
Normal file
52
src/time.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#![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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! time_unit2 {
|
||||||
|
(1, $unit:ident) => { $crate::__time_units::singular::$unit };
|
||||||
|
($number:literal, $unit:ident) => { $number * $crate::__time_units::plural::$unit }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
macro time_unit( $number:tt, $unit:ident ) {
|
||||||
|
crate::time_unit2!($number, $unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
macro dur($($amount:tt $unit:ident $(,)?)+) {
|
||||||
|
core::time::Duration::from_millis(0u64 $( + (time_unit!( $amount, $unit)) )+ )
|
||||||
|
}
|
||||||
79
src/upcast.rs
Normal file
79
src/upcast.rs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
pub trait Upcast<T> {
|
||||||
|
fn upcast(self) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoUsize {
|
||||||
|
fn into_usize(self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! gen_upcast {
|
||||||
|
($from:ty => $into:ty) => {
|
||||||
|
impl Upcast<$into> for $from {
|
||||||
|
fn upcast(self) -> $into {
|
||||||
|
self as $into
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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", target_pointer_width = "32"))]
|
||||||
|
gen_upcast!(i32 => isize);
|
||||||
|
|
||||||
|
gen_upcast!(isize => isize);
|
||||||
|
gen_upcast!(usize => usize);
|
||||||
|
|
||||||
|
|
||||||
|
impl IntoUsize for usize {
|
||||||
|
fn into_usize(self) -> usize { self }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoUsize for *const T {
|
||||||
|
fn into_usize(self) -> usize { self as usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoUsize for *mut T {
|
||||||
|
fn into_usize(self) -> usize { self as usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoUsize for &T {
|
||||||
|
fn into_usize(self) -> usize { self as *const _ as usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoUsize for &mut T {
|
||||||
|
fn into_usize(self) -> usize { self as *mut _ as usize }
|
||||||
|
}
|
||||||
100
src/vso.rs
Normal file
100
src/vso.rs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#![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 {
|
||||||
|
return 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)
|
||||||
|
#[cfg(not(feature="production"))]
|
||||||
|
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
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! struct_offset {
|
||||||
|
($offset:literal, $type:ty) => {
|
||||||
|
$crate::VirtualOffset<$type, $offset>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
62
src/win32/importer.rs
Normal file
62
src/win32/importer.rs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
use crate::hash_utf8;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn find_import_hashed(module_name: u64, func_name: u64) -> Option<usize> {
|
||||||
|
crate::win32::loaded_modules()
|
||||||
|
.filter( |&(_,slice)|crate::hash_utf16(slice) == module_name).next()
|
||||||
|
.and_then(|(i,_)|i.exports())
|
||||||
|
.and_then(|v|{
|
||||||
|
v.filter_map(|(p,n)|(hash_utf8(n) == func_name).then_some(p)).next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[cfg(not(feature = "no_relocs"))]
|
||||||
|
macro_rules! 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: FTYPE = __initial;
|
||||||
|
extern "C" fn __initial($($pname: $ptype),*) $(-> $rtype)? {
|
||||||
|
unsafe {
|
||||||
|
let import = $crate::win32::importer::find_import_hashed(
|
||||||
|
$crate::hash_utf8($module.as_bytes()),
|
||||||
|
$crate::hash_utf8(stringify!($name).as_bytes())
|
||||||
|
).unwrap_or(0);
|
||||||
|
FUNC = core::mem::transmute(import);
|
||||||
|
FUNC($($pname),*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe { FUNC($($pname),*) }
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[cfg(feature = "no_relocs")]
|
||||||
|
macro_rules! 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(
|
||||||
|
x::hash_utf8($module.as_bytes()),
|
||||||
|
x::hash_utf8(stringify!($name).as_bytes())
|
||||||
|
).unwrap_or(0));
|
||||||
|
FUNC = Some(import);
|
||||||
|
import
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function($($pname),*)
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
66
src/win32/mod.rs
Normal file
66
src/win32/mod.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
pub mod pe_image;
|
||||||
|
pub mod module_iter;
|
||||||
|
pub mod importer;
|
||||||
|
|
||||||
|
pub use pe_image::*;
|
||||||
|
pub use module_iter::*;
|
||||||
|
|
||||||
|
pub mod tls;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn find_kernel32() -> usize {
|
||||||
|
let mut _k32: usize = 0;
|
||||||
|
core::arch::asm!(
|
||||||
|
"mov {x}, gs:[60h]", // TEB->PEB
|
||||||
|
"mov {x}, [{x} + 18h]", // PEB->LDR
|
||||||
|
"mov {x}, [{x} + 10h]", // LDR->InLoadOrderModuleList
|
||||||
|
"mov {x}, [{x}]",
|
||||||
|
"mov {x}, [{x}]",
|
||||||
|
"mov {x}, [{x} + 30h]",
|
||||||
|
x = out(reg) _k32,
|
||||||
|
);
|
||||||
|
_k32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#[link_name = "__ImageBase"]
|
||||||
|
static ImageBaseDosHeader: ImageDOSHeader;
|
||||||
|
#[link_name = "__ImageBase"]
|
||||||
|
static ImageBasePtr: [u8;0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn image_base() -> &'static ImageBase {
|
||||||
|
unsafe { &*(ImageBasePtr.as_ptr() as *const ImageBase) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn image_header() -> &'static ImageDOSHeader {
|
||||||
|
unsafe { &ImageBaseDosHeader }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn process_executable() -> &'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
|
||||||
|
}
|
||||||
52
src/win32/module_iter.rs
Normal file
52
src/win32/module_iter.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
use crate::win32::ImageBase;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct UNICODE_STRING {
|
||||||
|
pub length: u16,
|
||||||
|
pub capacity: u16,
|
||||||
|
pub buffer: *const u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub 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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ModuleIter {
|
||||||
|
pub entry: *const LDR_DATA_TABLE_ENTRY,
|
||||||
|
pub 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
265
src/win32/pe_image.rs
Normal file
265
src/win32/pe_image.rs
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
// ==============================
|
||||||
|
// PE stuff
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
use crate::upcast::Upcast;
|
||||||
|
|
||||||
|
#[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; ImageBase::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 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 {
|
||||||
|
pub export_flags: u32,
|
||||||
|
pub timestamp: u32,
|
||||||
|
pub major_version: u16,
|
||||||
|
pub minor_version: u16,
|
||||||
|
pub name_rva: u32,
|
||||||
|
pub ordinal_base: u32,
|
||||||
|
pub address_table_entries: u32,
|
||||||
|
pub number_of_name_pointers: u32,
|
||||||
|
pub export_address_table_rva: u32,
|
||||||
|
pub name_pointer_rva: u32,
|
||||||
|
pub ordinal_table_rva: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ImageExportAddressEntry {
|
||||||
|
pub export_rva: u32,
|
||||||
|
pub forwarder_rva: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ImageBase(());
|
||||||
|
|
||||||
|
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 ImageBase {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_ptr(&self) -> usize {
|
||||||
|
self as *const _ as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
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 exports(&self) -> Option<ExportIter> {
|
||||||
|
let directory = &self.nt_header().optional_header.data_directory[ImageBase::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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/win32/tls.rs
Normal file
56
src/win32/tls.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/// 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 & ( 1 << i ) == 0)
|
||||||
|
.inspect(|i|{
|
||||||
|
write_tls_bitmap(bitmap | ( 1 << i))
|
||||||
|
}).next()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// free's the given tls slot
|
||||||
|
pub unsafe fn release_tls(slot: u32) {
|
||||||
|
write_tls_bitmap(read_tls_bitmap() & !(1 << slot ))
|
||||||
|
}
|
||||||
15
tests/test_data.rs
Normal file
15
tests/test_data.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_distance() {
|
||||||
|
|
||||||
|
|
||||||
|
let a = [0u8,2,3];
|
||||||
|
let p1 = &a[0];
|
||||||
|
let p2 = &a[2];
|
||||||
|
assert_eq!(x::distance(p1, p2), 2);
|
||||||
|
assert_eq!(x::distance(p2, p1), 2);
|
||||||
|
assert_eq!(x::distance(p1, p1), 0);
|
||||||
|
}
|
||||||
24
tests/test_image_base.rs
Normal file
24
tests/test_image_base.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
#[link(name = "kernel32")]
|
||||||
|
extern "C" {
|
||||||
|
pub fn GetModuleHandleA(module_name: *const i8) -> &'static x::win32::ImageBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "win32")]
|
||||||
|
pub fn test_image_base() {
|
||||||
|
let a = unsafe { GetModuleHandleA(std::ptr::null()) } as *const _ as usize;
|
||||||
|
let b = x::win32::image_base() as *const _ as usize;
|
||||||
|
assert_eq!(a, b, "image_base didn't match");
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "win32")]
|
||||||
|
pub fn test_image_base2() {
|
||||||
|
let a = unsafe { x::win32::process_executable() } as *const _ as usize;
|
||||||
|
let b = x::win32::image_base() as *const _ as usize;
|
||||||
|
assert_eq!(a, b, "image_base didn't match");
|
||||||
|
}
|
||||||
15
tests/test_lazy_import.rs
Normal file
15
tests/test_lazy_import.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use x::IntoUsize;
|
||||||
|
|
||||||
|
x::lazy_import! { "kernel32.dll"
|
||||||
|
pub fn LoadLibraryA(module_name: *const i8) -> &'static x::win32::ImageBase;
|
||||||
|
pub fn GetModuleHandleA(module_name: *const i8) -> &'static x::win32::ImageBase;
|
||||||
|
pub fn GetLastError() -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "win32")]
|
||||||
|
pub fn test_exports() {
|
||||||
|
let a = LoadLibraryA(x::cstr!("user32.dll"));
|
||||||
|
println!("{} -> {}",a.into_usize(), unsafe { a.nt_header().optional_header.size_of_image });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user