Rework from last few weeks local

This commit is contained in:
flux
2024-06-12 08:09:24 +01:00
commit 0a2896519b
10 changed files with 480 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
*/target
/target
+5
View File
@@ -0,0 +1,5 @@
{
"cSpell.words": [
"shellcode"
]
}
+7
View File
@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "builder"
version = "0.1.0"
+6
View File
@@ -0,0 +1,6 @@
[package]
name = "builder"
version = "0.1.0"
edition = "2021"
[dependencies]
+3
View File
@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}
+21
View File
@@ -0,0 +1,21 @@
[build]
target = "x86_64-pc-windows-msvc"
rustflags = [
# pre-link
"-Z", "pre-link-arg=/NODEFAULTLIB", # not to use the default libraries
"--emit", "asm", # instructs the compiler to emit assembly code in addition to binary
# post-link
"-C", "link-arg=/ENTRY:main",
"-C", "link-arg=/MERGE:.edata=.rdata",
"-C", "link-arg=/MERGE:.rustc=.data",
"-C", "link-arg=/MERGE:.rdata=.text",
"-C", "link-arg=/MERGE:.pdata=.text",
"-C", "link-arg=/DEBUG:NONE", # disables generation of debug information
"-C", "link-arg=/EMITPOGOPHASEINFO", # generates phase information for profile-guided optimisation
"-C", "target-feature=-mmx,-sse,+soft-float" # disable mmx and sse
]
[unstable]
build-std = ["core", "alloc"]
+7
View File
@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "shellcode"
version = "0.1.0"
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "shellcode"
version = "0.1.0"
edition = "2021"
[dependencies]
[profile.dev]
panic = "abort"
opt-level = "z"
lto = true
[profile.release]
panic = "abort"
opt-level = "z"
lto = true
+79
View File
@@ -0,0 +1,79 @@
#![no_std]
#![no_main]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(overflowing_literals)]
mod resolver;
use core::{arch::asm, ffi::c_void, mem::transmute, panic::PanicInfo, ptr::null};
#[link(name = "vcruntime")]
extern {}
#[link(name = "ucrt")]
extern {}
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
/// FFI binding for MessageBoxA
type MessageBoxA = extern "system" fn(
handle: *const u8,
lp_text: *const u8,
lp_caption: *const u8,
t: usize,
) -> *const c_void;
/// FFI for LoadLibraryA
type LoadLibraryA = extern "system" fn(
lib_name: *const u8,
) -> isize;
/// FFI for
type GetProcAddress = extern "system" fn(
handle: *const usize,
proc_name: *const u8,
) -> *mut c_void;
#[no_mangle]
pub extern "C" fn main() {
// stack strings
let kernel_32 = b"KERNEL32.DLL\0";
let load_library_a = b"LoadLibraryA\0";
let get_proc_addr = b"GetProcAddress\0";
let message_box_a = b"MessageBoxA\0";
let user_32 = b"User32.dll\0";
// get virtual addresses
let load_library_a = resolver::get_function_from_exports(kernel_32, load_library_a).unwrap();
let get_proc_addr = resolver::get_function_from_exports(kernel_32, get_proc_addr).unwrap();
// obtaining User32.dll
let load_library_a: LoadLibraryA = unsafe { transmute(load_library_a.address) };
let user_32_dll = load_library_a(user_32 as *const u8);
let get_proc_address: GetProcAddress = unsafe { transmute(get_proc_addr.address) };
// get msg box fn
let message_box_address = get_proc_address(user_32_dll as *const usize, message_box_a as *const u8);
let message_box_a:MessageBoxA = unsafe { transmute(message_box_address) };
// align the stack to divisible by 16
unsafe { asm!("and rsp, ~0xf") };
let msg = b"Injected!\0";
// unsafe { asm!("int3") };
message_box_a(
null(),
msg as *const u8,
msg as *const u8,
0x0,
);
}
+334
View File
@@ -0,0 +1,334 @@
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
use core::{arch::asm, ffi::c_void, ops::Add, slice::from_raw_parts, str::{from_utf8, from_utf8_mut}};
/// A structure containing the module name, function name, and export address for each function loaded
/// into the portable executable on x64 systems only.
pub struct ExportResolver<'a> {
pub module: &'a str,
pub base_address: usize, // to prevent repeat reads of the peb
pub function: &'a str,
pub address: usize,
}
/// Get the base address of a specified module. Obtains the base address by reading from the TEB -> PEB ->
/// PEB_LDR_DATA -> InMemoryOrderModuleList -> InMemoryOrderLinks -> DllBase
///
/// Returns the DLL base address as a Option<usize>
#[allow(unused_variables)]
#[allow(unused_assignments)]
fn get_module_base(module_name: &[u8]) -> Option<usize> {
let module_name: &str = from_utf8(module_name).unwrap();
let mut peb: usize;
let mut ldr: usize;
let mut in_memory_order_module_list: usize;
let mut current_entry: usize;
unsafe {
// get the peb and module list
asm!(
"mov {peb}, gs:[0x60]",
"mov {ldr}, [{peb} + 0x18]",
"mov {in_memory_order_module_list}, [{ldr} + 0x10]", // points to the Flink
peb = out(reg) peb,
ldr = out(reg) ldr,
in_memory_order_module_list = out(reg) in_memory_order_module_list,
);
// set the current entry to the head of the list
current_entry = in_memory_order_module_list;
// iterate the modules searching for
loop {
// get the attributes we are after of the current entry
let dll_base = *(current_entry.add(0x30) as *const usize);
let module_name_address = *(current_entry.add(0x60) as *const usize);
let module_length = *(current_entry.add(0x58) as *const u16);
// check if the module name address is valid and not zero
if module_name_address != 0 && module_length > 0 {
// read the module name from memory
let dll_name_slice = from_raw_parts(module_name_address as *const u16, (module_length / 2) as usize);
let mut buffer = [0u8; 512];
if let Some(dll_name) = wide_to_str(dll_name_slice, &mut buffer) {
// do we have a match on the module name?
if dll_name.eq_ignore_ascii_case(module_name) {
return Some(dll_base);
}
}
} else {
return None;
}
// dereference current_entry which contains the value of the next LDR_DATA_TABLE_ENTRY (specifically a pointer to LIST_ENTRY
// within the next LDR_DATA_TABLE_ENTRY)
current_entry = *(current_entry as *const usize);
// If we have looped back to the start, break
if current_entry == in_memory_order_module_list {
return None;
}
}
}
}
/// Get the function address of a function in a specified DLL from the DLL Base.
///
/// # Parameters
/// * dll_name -> the name of the DLL / module you are wanting to query
/// * needle -> the function name (case sensitive) of the function you are looking for
///
/// # Returns
/// Option<*const c_void> -> the function address as a pointer
pub fn get_function_from_exports<'a>(dll_name: &'a [u8], needle: &'a [u8]) -> Option<ExportResolver<'a>> {
let dll_name = strip_null_terminator(dll_name);
let needle = strip_null_terminator(&needle);
let needle = from_utf8(&needle).unwrap();
// if the dll_base was already found from a previous search then use that
// otherwise, if it was None, make a call to get_module_base
let dll_base: *mut c_void = match get_module_base(dll_name) {
Some(a) => a as *mut c_void,
None => {
return None;
},
};
let dll_name = from_utf8(dll_name).unwrap();
// check we match the DOS header, cast as pointer to tell the compiler to treat the memory
// address as if it were a IMAGE_DOS_HEADER structure
let dos_header: IMAGE_DOS_HEADER = unsafe { read_memory(dll_base as *const IMAGE_DOS_HEADER) };
if dos_header.e_magic != IMAGE_DOS_SIGNATURE {
return None;
}
// check the NT headers
let nt_headers = unsafe { read_memory(dll_base.offset(dos_header.e_lfanew as isize) as *const IMAGE_NT_HEADERS64) };
if nt_headers.Signature != IMAGE_NT_SIGNATURE {
return None;
}
// get the export directory
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_data_directory
// found from first item in the DataDirectory; then we take the structure in memory at dll_base + RVA
let export_dir_rva = nt_headers.OptionalHeader.DataDirectory[0].VirtualAddress;
let export_offset = unsafe {dll_base.add(export_dir_rva as usize) };
let export_dir: IMAGE_EXPORT_DIRECTORY = unsafe { read_memory(export_offset as *const IMAGE_EXPORT_DIRECTORY) };
// get the addresses we need
let address_of_functions_rva = export_dir.AddressOfFunctions as usize;
let address_of_names_rva = export_dir.AddressOfNames as usize;
let ordinals_rva = export_dir.AddressOfNameOrdinals as usize;
let functions = unsafe { dll_base.add(address_of_functions_rva as usize) } as *const u32;
let names = unsafe { dll_base.add(address_of_names_rva as usize) } as *const u32;
let ordinals = unsafe { dll_base.add(ordinals_rva as usize) } as *const u16;
// get the amount of names to iterate over
let number_of_names = export_dir.NumberOfNames;
for i in 0..number_of_names {
// calculate the RVA of the function name
let name_rva = unsafe { *names.offset(i.try_into().unwrap()) as usize };
// actual memory address of the function name
let name_addr = unsafe { dll_base.add(name_rva) };
// read the function name
let function_name = unsafe {
let char = name_addr as *const u8;
let mut len = 0;
// iterate over the memory until a null terminator is found
while *char.add(len) != 0 {
len += 1;
}
from_raw_parts(char, len)
};
let function_name = from_utf8(function_name).unwrap_or("Invalid UTF-8");
if function_name.eq("Invalid UTF-8") {
return None;
}
// if we have a match on our function name
if function_name.eq(needle) {
// calculate the RVA of the function address
let ordinal = unsafe { *ordinals.offset(i.try_into().unwrap()) as usize };
let fn_rva = unsafe { *functions.add(ordinal) as usize };
// actual memory address of the function address
let fn_addr = unsafe { dll_base.add(fn_rva) } as *const c_void;
let result = ExportResolver {
module: dll_name,
base_address: dll_base as usize,
function: needle,
address: fn_addr as usize,
};
return Some(result);
}
}
None
}
/// Read memory of any type
unsafe fn read_memory<T>(address: *const T) -> T {
core::ptr::read(address)
}
fn wide_to_str<'a>(wide: &[u16], buffer: &'a mut [u8]) -> Option<&'a str> {
let mut len = 0;
for &w in wide {
// convert each u16 character to u8 and store in the byte array
if w == 0 { break; } // stop at null terminator
if w > 0xFF {
return None; // non-ASCII characters are not handled here
}
if len >= buffer.len() {
return None; // buffer overflow protection
}
buffer[len] = w as u8;
len += 1;
}
// Convert the byte array to &str
match from_utf8_mut(&mut buffer[..len]) {
Ok(s) => Some(s),
Err(_) => None,
}
}
fn strip_null_terminator(bytes: &[u8]) -> &[u8] {
if let Some(pos) = bytes.iter().position(|&x| x == 0) {
&bytes[..pos]
} else {
bytes
}
}
#[repr(C, packed(2))]
pub struct IMAGE_DOS_HEADER {
pub e_magic: u16,
pub e_cblp: u16,
pub e_cp: u16,
pub e_crlc: u16,
pub e_cparhdr: u16,
pub e_minalloc: u16,
pub e_maxalloc: u16,
pub e_ss: u16,
pub e_sp: u16,
pub e_csum: u16,
pub e_ip: u16,
pub e_cs: u16,
pub e_lfarlc: u16,
pub e_ovno: u16,
pub e_res: [u16; 4],
pub e_oemid: u16,
pub e_oeminfo: u16,
pub e_res2: [u16; 10],
pub e_lfanew: i32,
}
pub const IMAGE_DOS_SIGNATURE: u16 = 23117u16;
#[repr(C)]
pub struct IMAGE_NT_HEADERS64 {
pub Signature: u32,
pub FileHeader: IMAGE_FILE_HEADER,
pub OptionalHeader: IMAGE_OPTIONAL_HEADER64,
}
#[repr(C)]
pub struct IMAGE_FILE_HEADER {
pub Machine: IMAGE_FILE_MACHINE,
pub NumberOfSections: u16,
pub TimeDateStamp: u32,
pub PointerToSymbolTable: u32,
pub NumberOfSymbols: u32,
pub SizeOfOptionalHeader: u16,
pub Characteristics: IMAGE_FILE_CHARACTERISTICS,
}
#[repr(C, packed(4))]
pub struct IMAGE_OPTIONAL_HEADER64 {
pub Magic: IMAGE_OPTIONAL_HEADER_MAGIC,
pub MajorLinkerVersion: u8,
pub MinorLinkerVersion: u8,
pub SizeOfCode: u32,
pub SizeOfInitializedData: u32,
pub SizeOfUninitializedData: u32,
pub AddressOfEntryPoint: u32,
pub BaseOfCode: u32,
pub ImageBase: u64,
pub SectionAlignment: u32,
pub FileAlignment: u32,
pub MajorOperatingSystemVersion: u16,
pub MinorOperatingSystemVersion: u16,
pub MajorImageVersion: u16,
pub MinorImageVersion: u16,
pub MajorSubsystemVersion: u16,
pub MinorSubsystemVersion: u16,
pub Win32VersionValue: u32,
pub SizeOfImage: u32,
pub SizeOfHeaders: u32,
pub CheckSum: u32,
pub Subsystem: IMAGE_SUBSYSTEM,
pub DllCharacteristics: IMAGE_DLL_CHARACTERISTICS,
pub SizeOfStackReserve: u64,
pub SizeOfStackCommit: u64,
pub SizeOfHeapReserve: u64,
pub SizeOfHeapCommit: u64,
pub LoaderFlags: u32,
pub NumberOfRvaAndSizes: u32,
pub DataDirectory: [IMAGE_DATA_DIRECTORY; 16],
}
#[repr(transparent)]
pub struct IMAGE_FILE_MACHINE(pub u16);
#[repr(transparent)]
pub struct IMAGE_FILE_CHARACTERISTICS(pub u16);
#[repr(transparent)]
pub struct IMAGE_OPTIONAL_HEADER_MAGIC(pub u16);
#[repr(transparent)]
pub struct IMAGE_SUBSYSTEM(pub u16);
#[repr(transparent)]
pub struct IMAGE_DLL_CHARACTERISTICS(pub u16);
#[repr(C)]
pub struct IMAGE_DATA_DIRECTORY {
pub VirtualAddress: u32,
pub Size: u32,
}
pub const IMAGE_NT_SIGNATURE: u32 = 17744u32;
#[repr(C)]
pub struct IMAGE_EXPORT_DIRECTORY {
pub Characteristics: u32,
pub TimeDateStamp: u32,
pub MajorVersion: u16,
pub MinorVersion: u16,
pub Name: u32,
pub Base: u32,
pub NumberOfFunctions: u32,
pub NumberOfNames: u32,
pub AddressOfFunctions: u32,
pub AddressOfNames: u32,
pub AddressOfNameOrdinals: u32,
}