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:
Kudaes
2024-04-08 14:31:36 +02:00
parent 35bd2a65f1
commit 4bfdf2487a
6 changed files with 460 additions and 31 deletions
+5 -1
View File
@@ -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" }
+74
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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(&section.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(&section.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(&section.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;
}
}
}