mirror of
https://github.com/EddieIvan01/memexec
synced 2024-06-27 01:10:03 +00:00
158 lines
3.9 KiB
Rust
158 lines
3.9 KiB
Rust
#![cfg(feature = "hook")]
|
|
|
|
use std::hash::Hash;
|
|
use std::mem;
|
|
|
|
#[derive(Debug)]
|
|
pub enum Thunk<'a> {
|
|
Ordinal(isize),
|
|
Name(&'a str),
|
|
}
|
|
|
|
impl<'a> PartialEq for Thunk<'a> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(&Thunk::Ordinal(s), &Thunk::Ordinal(o)) => s == o,
|
|
(&Thunk::Name(s), &Thunk::Name(o)) => s == o,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Eq for Thunk<'a> {}
|
|
|
|
impl<'a> Hash for Thunk<'a> {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
mem::discriminant(self).hash(state);
|
|
match *self {
|
|
Thunk::Ordinal(o) => o.hash(state),
|
|
Thunk::Name(n) => n.hash(state),
|
|
};
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ProcDesc<'a> {
|
|
// Use `String` instead of `&str`,
|
|
// because we need a case conversion in `new` function
|
|
dll: String,
|
|
thunk: Thunk<'a>,
|
|
}
|
|
|
|
impl<'a> PartialEq for ProcDesc<'a> {
|
|
#[inline]
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.dll == other.dll && self.thunk == other.thunk
|
|
}
|
|
}
|
|
|
|
impl<'a> Eq for ProcDesc<'a> {}
|
|
|
|
impl<'a> Hash for ProcDesc<'a> {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
self.dll.hash(state);
|
|
self.thunk.hash(state);
|
|
}
|
|
}
|
|
|
|
impl<'a> ProcDesc<'a> {
|
|
/// Dll name is case insensitive
|
|
pub fn new(dll: &str, thunk: Thunk<'a>) -> ProcDesc<'a> {
|
|
ProcDesc {
|
|
dll: dll.to_ascii_lowercase(),
|
|
thunk: thunk,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Couldn't implement `FromStr` trait here,
|
|
// because the signature of `from_str` doesn't allow an explicit lifetime hint
|
|
impl<'a> From<&'a str> for ProcDesc<'a> {
|
|
fn from(s: &'a str) -> Self {
|
|
match s.find('!') {
|
|
Some(i) => {
|
|
let (dll, proc_name) = s.split_at(i);
|
|
ProcDesc::new(dll, Thunk::Name(&proc_name[1..]))
|
|
}
|
|
None => match s.find('#') {
|
|
Some(i) => {
|
|
let (dll, proc_ord) = s.split_at(i);
|
|
ProcDesc::new(dll, Thunk::Ordinal(proc_ord[1..].parse().unwrap_or(0)))
|
|
}
|
|
// Failure case
|
|
None => ProcDesc {
|
|
dll: String::new(),
|
|
thunk: Thunk::Ordinal(0),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
use std::collections::HashMap;
|
|
use std::os::raw::c_void;
|
|
|
|
trait ProcDescTbl<'a> {
|
|
fn get(&self, proc_desc: &'a ProcDesc) -> Option<&*const c_void>;
|
|
}
|
|
|
|
impl<'a> ProcDescTbl<'a> for HashMap<ProcDesc<'a>, *const c_void> {
|
|
fn get(&self, proc_desc: &'a ProcDesc) -> Option<&*const c_void> {
|
|
self.get(proc_desc)
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
// Implement FNV-1a hash
|
|
#[derive(Debug, Hash)]
|
|
pub struct ProcHash(u64, u64);
|
|
|
|
impl PartialEq for ProcHash {
|
|
#[inline]
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.0 == other.0 && self.1 == other.1
|
|
}
|
|
}
|
|
|
|
impl Eq for ProcHash {}
|
|
|
|
impl ProcHash {
|
|
/// Dll name is case insensitive
|
|
/// ProcHash::new("kernel32.dll", Thunk::Name("CreateProcessW"))
|
|
pub fn new(dll: &str, thunk: Thunk) -> ProcHash {
|
|
// The hash of DLL and thunk is calculated and saved separately,
|
|
// in order to reduce the collision probability
|
|
let mut h1: u64 = 0xcbf29ce484222325;
|
|
|
|
for c in dll.chars() {
|
|
h1 ^= c.to_ascii_lowercase() as u64;
|
|
h1 = h1.wrapping_mul(0x100000001b3);
|
|
}
|
|
|
|
let mut h2: u64 = 0xcbf29ce484222325;
|
|
match thunk {
|
|
Thunk::Ordinal(ord) => {
|
|
// #
|
|
h2 ^= 0x23;
|
|
h2 = h2.wrapping_mul(0x100000001b3);
|
|
h2 ^= ord as u64;
|
|
h2 = h2.wrapping_mul(0x100000001b3);
|
|
}
|
|
Thunk::Name(name) => {
|
|
// !
|
|
h2 ^= 0x21;
|
|
h2 = h2.wrapping_mul(0x100000001b3);
|
|
for c in name.chars() {
|
|
h2 ^= c as u64;
|
|
h2 = h2.wrapping_mul(0x100000001b3);
|
|
}
|
|
}
|
|
}
|
|
|
|
ProcHash(h1, h2)
|
|
}
|
|
}
|
|
*/
|