..
mosaic-rs
Features
- PE/COFF Parser & Loader
- Both ANSI and Wide API variants
- Dynamic Function Resolution using:
- LoadLibrary / GetProcAddress
- API Hashing
- SSNs (resolved via Hell’s Gate)
- Compile-time string constant obfuscation provided by Obfstr
- Anti-Debug / Evasion Techniques
- x86 / x86_64 support
- #![no_std] and no alloc support
Examples
Modular API Hashing
// https://github.com/HindrikStegenga/const-fnv1a-hash
pub struct FNV1A64;
impl const Digest for FNV1A64 {
const OUTPUT_LEN: usize = 8;
fn digest(data: &[u8]) -> [u8; Self::OUTPUT_LEN] {
const FNV_OFFSET_BASIS_64: u64 = 0xcbf29ce484222325;
const FNV_PRIME_64: u64 = 0x00000100000001B3;
let mut hash = FNV_OFFSET_BASIS_64;
let mut i = 0;
while i < data.len() {
hash ^= data[i] as u64;
hash = hash.wrapping_mul(FNV_PRIME_64);
i += 1;
}
hash.to_be_bytes()
}
}
fn message_box() {
type MessageBoxA =
unsafe extern "system" fn(hwnd: isize, lptext: *const u8, *const u8, u32) -> i32;
let library = Library::load("User32.dll").expect("Could not load User32.dll");
let _message_box = library
.get_proc::<FNV1A64, MessageBoxA>(FNV1A64::digest(b"MessageBoxA"))
.expect("Could not get MessageBoxA");
// drop(library);
// unsafe {
// _message_box.call(0, "Hello, World!\0".as_ptr(), "Hello, World!\0".as_ptr(), 0);
// }
}
Resolving and Invoking Syscalls
type NtAllocateVirtualMemory = unsafe extern "system" fn(
ProcessHandle: HANDLE,
BaseAddress: *mut PVOID,
ZeroBits: ULONG_PTR,
RegionSize: PSIZE_T,
AllocationType: ULONG,
Protect: ULONG,
) -> NtResult;
let ssn = Ntdll::new()
.get_ssn::<NtAllocateVirtualMemory>(HashFunction::digest(b"NtAllocateVirtualMemory"))
.unwrap();
let mut addr: *mut core::ffi::c_void = 0 as _;
let mut region_size = 100;
let nt_result = unsafe {
ssn.call(
GetCurrentProcess(),
&mut addr,
0,
&mut region_size,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE,
)
};
if let NtResult::Err(nt_status) = nt_result {
println!(
"NtAllocateVirtualMemory failed with {:#X} ({})",
nt_status.code(),
nt_status.as_error().message()
);
}