diff --git a/Cargo.toml b/Cargo.toml index a0e69dc..e299948 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ manualmap = { path = "manualmap" } data = { path = "data" } overload = { path = "overload" } dmanager = { path = "dmanager" } +utils = { path = "utils" } [build-dependencies] static_vcruntime = "2.0" \ No newline at end of file diff --git a/README.md b/README.md index cbf7dd4..40f5ca5 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Import this crate into your project by adding the following line to your `cargo. ```rust [dependencies] -dinvoke_rs = "0.2.0" +dinvoke_rs = "0.2.1" ``` # Examples @@ -111,8 +111,6 @@ fn main() { } } } - - ``` ## Executing indirect syscall @@ -129,7 +127,7 @@ fn main() { unsafe { let function_type:NtQueryInformationProcess; - let mut ret: Option = None; //NtQueryInformationProcess returns a NTSTATUS, which is a i32. + let ret: Option; //NtQueryInformationProcess returns a NTSTATUS, which is a i32. let handle = GetCurrentProcess(); let p = PROCESS_BASIC_INFORMATION::default(); let process_information: PVOID = std::mem::transmute(&p); @@ -146,7 +144,7 @@ fn main() { return_length ); - let pbi:*mut PROCESS_BASIC_INFORMATION; + let pbi: *mut PROCESS_BASIC_INFORMATION; match ret { Some(x) => if x == 0 { @@ -159,7 +157,6 @@ fn main() { } } - ``` ## Manual PE mapping @@ -196,7 +193,6 @@ fn main() { } } - ``` ## Overload memory section @@ -234,7 +230,6 @@ fn main() { } } - ``` ## Module fluctuation @@ -286,7 +281,6 @@ fn main() { } } - ``` ## Syscall parameters spoofing @@ -309,14 +303,14 @@ fn main() { let handler = dinvoke_rs::dinvoke::breakpoint_handler as usize; dinvoke_rs::dinvoke::add_vectored_exception_handler(1, handler); - let h = HANDLE {0: -1}; + let h = HANDLE {0: -1 as _}; let handle: *mut HANDLE = std::mem::transmute(&h); let access = THREAD_ALL_ACCESS; let a = OBJECT_ATTRIBUTES::default(); // https://github.com/Kudaes/rust_tips_and_tricks/tree/main#transmute let attributes: *mut OBJECT_ATTRIBUTES = std::mem::transmute(&a); // We set the PID of the remote process let remote_pid = 472isize; - let c = ClientId {unique_process: HANDLE {0: remote_pid}, unique_thread: HANDLE::default()}; + let c = ClientId {unique_process: HANDLE {0: remote_pid as _}, unique_thread: HANDLE::default()}; let client_id: *mut ClientId = std::mem::transmute(&c); // A call to NtOpenProcess is performed through Dinvoke. The parameters will be // automatically spoofed by the function and restored to the original values @@ -328,7 +322,6 @@ fn main() { dinvoke_rs::dinvoke::use_hardware_breakpoints(false); } } - ``` ## Module stomping and Shellcode fluctuation diff --git a/data/Cargo.toml b/data/Cargo.toml index ff4baed..e7681a0 100644 --- a/data/Cargo.toml +++ b/data/Cargo.toml @@ -11,7 +11,7 @@ strip = true winapi = {version = "0.3.9", features = ["ntdef"]} [dependencies.windows] -version = "0.51" +version = "0.62" features = [ "Win32_Foundation", "Win32_Security", @@ -21,6 +21,7 @@ features = [ "Win32_System_Diagnostics_Debug", "Win32_System_Diagnostics_ToolHelp", "Win32_System_WindowsProgramming", + "Win32_System_ApplicationInstallationAndServicing", "Wdk_Foundation", "Win32_Storage_FileSystem", "Win32_System_Memory", diff --git a/data/src/lib.rs b/data/src/lib.rs index 25aa74f..b46257e 100644 --- a/data/src/lib.rs +++ b/data/src/lib.rs @@ -1,18 +1,20 @@ use std::{collections::BTreeMap, ffi::c_void}; -use windows::Win32::{Foundation::{BOOL, HANDLE, HINSTANCE, UNICODE_STRING}, Graphics::Printing::{DOC_INFO_1A, PRINTER_DEFAULTSA}, Security::SECURITY_ATTRIBUTES, System::{Diagnostics::{Debug::{EXCEPTION_RECORD, IMAGE_DATA_DIRECTORY, IMAGE_OPTIONAL_HEADER32, IMAGE_SECTION_HEADER, MINIDUMP_CALLBACK_INFORMATION, MINIDUMP_EXCEPTION_INFORMATION, MINIDUMP_USER_STREAM_INFORMATION}, ToolHelp::THREADENTRY32}, Memory::MEMORY_BASIC_INFORMATION, SystemInformation::SYSTEM_INFO, Threading::{PROCESS_INFORMATION, STARTUPINFOW}, WindowsProgramming::CLIENT_ID, IO::{IO_STATUS_BLOCK, OVERLAPPED}}}; +use windows::Win32::{Foundation::{HANDLE, HINSTANCE, UNICODE_STRING}, Graphics::Printing::{DOC_INFO_1A, PRINTER_DEFAULTSA}, Security::SECURITY_ATTRIBUTES, Storage::FileSystem::FILE_ID_DESCRIPTOR, System::{ApplicationInstallationAndServicing::ACTCTXW, Diagnostics::{Debug::{EXCEPTION_RECORD, IMAGE_DATA_DIRECTORY, IMAGE_OPTIONAL_HEADER32, IMAGE_SECTION_HEADER, + MINIDUMP_CALLBACK_INFORMATION, MINIDUMP_EXCEPTION_INFORMATION, MINIDUMP_USER_STREAM_INFORMATION}, ToolHelp::THREADENTRY32}, IO::{IO_STATUS_BLOCK, OVERLAPPED}, Memory::MEMORY_BASIC_INFORMATION, SystemInformation::SYSTEM_INFO, Threading::{PROCESS_INFORMATION, STARTUPINFOW}, WindowsProgramming::CLIENT_ID}}; use windows::Wdk::Foundation::OBJECT_ATTRIBUTES; use winapi::shared::ntdef::LARGE_INTEGER; pub type PVOID = *mut c_void; pub type DWORD = u32; pub type EAT = BTreeMap; -pub type EntryPoint = extern "system" fn (HINSTANCE, u32, *mut c_void) -> BOOL; +pub type EntryPoint = extern "system" fn (HINSTANCE, u32, *mut c_void) -> bool; pub type QueryInterface = unsafe extern "system" fn (*mut c_void, *const GUID, *mut *mut c_void) -> u32; pub type AddRef = unsafe extern "system" fn(*mut c_void) -> u32; pub type Release = unsafe extern "system" fn(*mut c_void) -> u32; pub type ImpersonateLoggedOnUser = unsafe extern "system" fn (HANDLE) -> bool; pub type RevertToSelf = unsafe extern "system" fn () -> bool; pub type LoadLibraryA = unsafe extern "system" fn (*mut u8) -> usize; +pub type LoadLibraryW = unsafe extern "system" fn (*mut u16) -> usize; pub type FreeLibrary = unsafe extern "system" fn (isize) -> HINSTANCE; pub type CreateToolhelp32Snapshot = unsafe extern "system" fn (u32, u32) -> HANDLE; pub type Thread32First = unsafe extern "system" fn (HANDLE, *mut THREADENTRY32) -> bool; @@ -20,32 +22,33 @@ pub type Thread32Next = unsafe extern "system" fn (HANDLE, *mut THREADENTRY32) - pub type PostThreadMessageA = unsafe extern "system" fn (u32, u32, usize, isize) -> bool; pub type OpenProcess = unsafe extern "system" fn (u32, i32, u32) -> HANDLE; pub type OpenThread = unsafe extern "system" fn (u32, i32, u32) -> HANDLE; -pub type OpenPrintA = unsafe extern "system" fn (*mut u8, *mut HANDLE, *mut PRINTER_DEFAULTSA) -> BOOL; +pub type OpenPrintA = unsafe extern "system" fn (*mut u8, *mut HANDLE, *mut PRINTER_DEFAULTSA) -> bool; pub type StartDocPrinterA = unsafe extern "system" fn (HANDLE, u32, *mut DOC_INFO_1A) -> u32; -pub type GetDefaultPrinterA = unsafe extern "system" fn (*mut u8, *mut u32) -> BOOL; +pub type GetDefaultPrinterA = unsafe extern "system" fn (*mut u8, *mut u32) -> bool; pub type EnumProcesses = unsafe extern "system" fn (*mut u32, u32, *mut u32) -> bool; pub type EnumProcessModules = unsafe extern "system" fn (HANDLE, *mut usize, u32, *mut u32) -> bool; pub type SetPriorityClass = unsafe extern "system" fn (HANDLE, u32) -> bool; pub type SetThreadPriority = unsafe extern "system" fn (HANDLE, u32) -> bool; pub type QueueUserWorkItem = unsafe extern "system" fn (*mut c_void, *mut c_void, u32) -> bool; -pub type InitializeProcThreadAttributeList = unsafe extern "system" fn (PVOID, u32, u32, *mut usize) -> BOOL; -pub type UpdateProcThreadAttribute = unsafe extern "system" fn (PVOID, u32, usize, *const c_void, usize, PVOID, *const usize) -> BOOL; +pub type InitializeProcThreadAttributeList = unsafe extern "system" fn (PVOID, u32, u32, *mut usize) -> bool; +pub type UpdateProcThreadAttribute = unsafe extern "system" fn (PVOID, u32, usize, *const c_void, usize, PVOID, *const usize) -> bool; pub type QueryFullProcessImageNameW = unsafe extern "system" fn (HANDLE, u32, *mut u16, *mut u32) -> i32; pub type MiniDumpWriteDump = unsafe extern "system" fn (HANDLE, u32, HANDLE, u32, *mut MINIDUMP_EXCEPTION_INFORMATION, *mut MINIDUMP_USER_STREAM_INFORMATION, *mut MINIDUMP_CALLBACK_INFORMATION) -> i32; -pub type GetOverlappedResult = unsafe extern "system" fn (HANDLE, *mut OVERLAPPED, *mut u32, bool) -> BOOL; +pub type GetOverlappedResult = unsafe extern "system" fn (HANDLE, *mut OVERLAPPED, *mut u32, bool) -> bool; pub type CreateFileA = unsafe extern "system" fn (*mut u8, u32, u32, *const SECURITY_ATTRIBUTES, u32, u32, HANDLE) -> HANDLE; pub type CreateFileW = unsafe extern "system" fn (*const u16, u32, u32, *const SECURITY_ATTRIBUTES, u32, u32, HANDLE) -> HANDLE; pub type ReadFile = unsafe extern "system" fn (HANDLE, PVOID, u32, *mut u32, *mut OVERLAPPED) -> i32; pub type CreateTransaction = unsafe extern "system" fn (*mut SECURITY_ATTRIBUTES, *mut GUID, u32, u32, u32, u32, *mut u16) -> HANDLE; pub type CreateFileTransactedA = unsafe extern "system" fn (*mut u8, u32, u32, *const SECURITY_ATTRIBUTES, u32, u32, HANDLE, HANDLE, *const u32, PVOID) -> HANDLE; -pub type CreateProcessWithLogon = unsafe extern "system" fn (*const u16, *const u16, *const u16, u32, *const u16, *mut u16, u32, *const c_void, *const u16, *const STARTUPINFOW, *mut PROCESS_INFORMATION) -> BOOL; -pub type RollbackTransaction = unsafe extern "system" fn (HANDLE) -> BOOL; +pub type CreateProcessWithLogon = unsafe extern "system" fn (*const u16, *const u16, *const u16, u32, *const u16, *mut u16, u32, *const c_void, *const u16, *const STARTUPINFOW, *mut PROCESS_INFORMATION) -> bool; +pub type CreateProcessW = unsafe extern "system" fn (*const u16, *const u16, *const SECURITY_ATTRIBUTES, *const SECURITY_ATTRIBUTES, bool, u32, *const c_void, *const u16, *const STARTUPINFOW, *mut PROCESS_INFORMATION) -> bool; +pub type RollbackTransaction = unsafe extern "system" fn (HANDLE) -> bool; pub type GetFileSize = unsafe extern "system" fn (HANDLE, *mut u32) -> u32; pub type CreateFileMapping = unsafe extern "system" fn (HANDLE, *const SECURITY_ATTRIBUTES, u32, u32, u32, *mut u8) -> HANDLE; pub type MapViewOfFile = unsafe extern "system" fn (HANDLE, u32, u32, u32, usize) -> PVOID; -pub type UnmapViewOfFile = unsafe extern "system" fn (PVOID) -> BOOL; +pub type UnmapViewOfFile = unsafe extern "system" fn (PVOID) -> bool; pub type ConvertThreadToFiber = unsafe extern "system" fn (PVOID) -> PVOID; pub type CreateFiber = unsafe extern "system" fn (usize, PVOID, PVOID) -> PVOID; pub type SwitchToFiber = unsafe extern "system" fn (PVOID); @@ -56,10 +59,15 @@ pub type LocalAlloc = unsafe extern "system" fn (u32, usize) -> PVOID; pub type TlsAlloc = unsafe extern "system" fn () -> u32; pub type TlsGetValue = unsafe extern "system" fn (u32) -> PVOID; pub type TlsSetValue = unsafe extern "system" fn (u32, PVOID) -> bool; +pub type CreateActCtxW = unsafe extern "system" fn (*mut ACTCTXW) -> HANDLE; +pub type ActivateActCtx = unsafe extern "system" fn (HANDLE, *mut usize) -> bool; +pub type ResumeThread = unsafe extern "system" fn (HANDLE) -> u32; +pub type GetModuleHandleW = unsafe extern "system" fn (*mut u16) -> isize; pub type GetModuleHandleExA = unsafe extern "system" fn (i32,*const u8,*mut usize) -> bool; pub type GetModuleBaseNameW = unsafe extern "system" fn (HANDLE, usize, *mut u16, u32) -> u32; pub type GetModuleFileNameExW = unsafe extern "system" fn (HANDLE, usize, *mut u16, u32) -> u32; pub type GetSystemInfo = unsafe extern "system" fn (*mut SYSTEM_INFO); +pub type VirtualQuery = unsafe extern "system" fn (*const c_void, *mut MEMORY_BASIC_INFORMATION, usize) -> usize; pub type VirtualQueryEx = unsafe extern "system" fn (HANDLE, *const c_void, *mut MEMORY_BASIC_INFORMATION, usize) -> usize; pub type LptopLevelExceptionFilter = usize; pub type AddVectoredExceptionHandler = unsafe extern "system" fn (first: u32, handle: usize) -> PVOID; @@ -74,6 +82,13 @@ pub type BCryptDecrypt = unsafe extern "system" fn (HANDLE, *mut u8, u32, PVOID, pub type BCryptCloseAlgorithmProvider = unsafe extern "system" fn (HANDLE, u32) -> i32; pub type CryptSignHashW = unsafe extern "system" fn (usize, u32, *mut u16, u32, *mut u8, *mut u32) -> bool; pub type CreateEventW = unsafe extern "system" fn (*const SECURITY_ATTRIBUTES, i32, i32, *const u16) -> HANDLE; +pub type DeviceIoControl = unsafe extern "system" fn (HANDLE, u32, PVOID, u32, PVOID, u32, *mut u32, *mut OVERLAPPED) -> bool; +pub type SetFilePointerEx = unsafe extern "system" fn (HANDLE, i64, *mut i64, u32) -> bool; +pub type OpenFileById = unsafe extern "system" fn(HANDLE, *const FILE_ID_DESCRIPTOR, u32, u32, *const SECURITY_ATTRIBUTES, u32) -> HANDLE; +pub type GetFinalPathNameByHandleW = unsafe extern "system" fn (HANDLE, *mut u16, u32, u32) -> u32; +pub type CreateEnvironmentBlock = unsafe extern "system" fn (*mut PVOID, HANDLE, bool) -> bool; +pub type GetThreadContext = unsafe extern "system" fn (HANDLE, *mut windows::Win32::System::Diagnostics::Debug::CONTEXT) -> bool; +pub type SetThreadContext = unsafe extern "system" fn (HANDLE, *const windows::Win32::System::Diagnostics::Debug::CONTEXT) -> bool; pub type LdrGetProcedureAddress = unsafe extern "system" fn (PVOID, *mut String, u32, *mut PVOID) -> i32; pub type NtCreateTransaction = unsafe extern "system" fn (*mut HANDLE, u32, *mut OBJECT_ATTRIBUTES, *mut GUID, HANDLE, u32, u32, u32, *mut LARGE_INTEGER, *mut UNICODE_STRING) -> i32; pub type NtWriteVirtualMemory = unsafe extern "system" fn (HANDLE, PVOID, PVOID, usize, *mut usize) -> i32; @@ -86,6 +101,7 @@ pub type NtQueryInformationFile = unsafe extern "system" fn (HANDLE, *mut IO_STA pub type NtDuplicateObject = unsafe extern "system" fn (HANDLE, HANDLE, HANDLE, *mut HANDLE, u32, u32, u32) -> i32; pub type NtQueryObject = unsafe extern "system" fn (HANDLE, u32, PVOID, u32, *mut u32) -> i32; pub type NtCreateUserProcess = unsafe extern "system" fn (*mut HANDLE, *mut HANDLE,u32, u32, *mut OBJECT_ATTRIBUTES,*mut OBJECT_ATTRIBUTES, u32, u32, PVOID, *mut PsCreateInfo, *mut PsAttributeList) -> i32; +pub type NtCreateProcessEx = unsafe extern "system" fn (*mut HANDLE, u32, *mut OBJECT_ATTRIBUTES, HANDLE, u32, HANDLE, HANDLE, HANDLE, u32) -> i32; pub type NtOpenFile = unsafe extern "system" fn (*mut HANDLE, u32, *mut OBJECT_ATTRIBUTES, *mut IO_STATUS_BLOCK, u32, u32) -> i32; pub type NtCreateSection = unsafe extern "system" fn (*mut HANDLE, u32, *mut OBJECT_ATTRIBUTES, *mut LARGE_INTEGER, u32, u32, HANDLE) -> i32; pub type NtMapViewOfSection = unsafe extern "system" fn (HANDLE, HANDLE, *mut PVOID, usize, usize, *mut LARGE_INTEGER, *mut usize, u32, u32, u32) -> i32; @@ -101,12 +117,16 @@ pub type NtOpenProcessToken = unsafe extern "system" fn (HANDLE, u32, *mut HANDL pub type NtDuplicateToken = unsafe extern "system" fn (HANDLE, u32, *mut OBJECT_ATTRIBUTES, bool, u32, *mut HANDLE) -> i32; pub type NtCreateKey = unsafe extern "system" fn (*mut HANDLE, u32, *mut OBJECT_ATTRIBUTES, u32, *mut UNICODE_STRING, u32, *mut u32) -> i32; pub type NtSetValueKey = unsafe extern "system" fn (HANDLE, *const UNICODE_STRING, u32, u32, *const c_void, u32) -> i32; +pub type NtCommitTransaction = unsafe extern "system" fn (HANDLE, bool) -> i32; +pub type NtUnmapViewOfSection = unsafe extern "system" fn (HANDLE, PVOID) -> i32; pub type RtlAdjustPrivilege = unsafe extern "system" fn (u32, u8, u8, *mut u8) -> i32; pub type RtlInitUnicodeString = unsafe extern "system" fn (*mut UNICODE_STRING, *const u16) -> () ; pub type RtlZeroMemory = unsafe extern "system" fn (PVOID, usize) -> (); pub type RtlQueueWorkItem = unsafe extern "system" fn (usize, PVOID, u32) -> i32; pub type RtlAddFunctionTable = unsafe extern "system" fn (usize, i32, usize) -> bool; -pub type NtCommitTransaction = unsafe extern "system" fn (HANDLE, bool) -> i32; +pub type RtlDecompressBuffer = unsafe extern "system" fn (u16, *mut u8, u32, *const u8, u32, *mut u32) -> i32; +pub type RtlCreateProcessParametersEx = unsafe extern "system" fn (*mut *mut RtlUserProcessParameters, *mut UNICODE_STRING, *mut UNICODE_STRING, *mut UNICODE_STRING, + *mut UNICODE_STRING, PVOID, *mut UNICODE_STRING, *mut UNICODE_STRING, *mut UNICODE_STRING, *mut UNICODE_STRING, u32) -> i32; pub const JMP_RBX: u16 = 9215; pub const ADD_RSP: u32 = 1489273672;// add rsp,0x58 -> up to 11 parameters @@ -137,6 +157,7 @@ pub const PAGE_EXECUTE: u32 = 0x10; pub const PAGE_EXECUTE_READ: u32 = 0x20; pub const PAGE_EXECUTE_READWRITE: u32 = 0x40; pub const PAGE_EXECUTE_WRITECOPY: u32 = 0x80; +pub const PAGE_GUARD: u32 = 0x100; pub const MEM_COMMIT: u32 = 0x1000; pub const MEM_RESERVE: u32 = 0x2000; @@ -160,7 +181,7 @@ pub const FILE_SHARE_READ: u32 = 0x1; pub const FILE_SHARE_WRITE: u32 = 0x2; pub const FILE_SHARE_DELETE: u32 = 0x4; -//File access flags +// File access flags pub const DELETE: u32 = 0x10000; pub const FILE_READ_DATA: u32 = 0x1; pub const FILE_READ_ATTRIBUTES: u32 = 0x80; @@ -175,6 +196,34 @@ pub const WRITE_OWNER: u32 = 0x80000; pub const SYNCHRONIZE: u32 = 0x100000; pub const FILE_EXECUTE: u32 = 0x20; +// Creation disposition flags +pub const CREATE_NEW: u32 = 1; +pub const CREATE_ALWAYS: u32 = 2; +pub const OPEN_EXISTING: u32 = 3; +pub const OPEN_ALWAYS: u32 = 4; +pub const TRUNCATE_EXISTING: u32 = 5; + +// Flags and Attributes +pub const FILE_ATTRIBUTE_ARCHIVE: u32 = 0x20; +pub const FILE_ATTRIBUTE_ENCRYPTED: u32 = 0x4000; +pub const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2; +pub const FILE_ATTRIBUTE_NORMAL: u32 = 0x80; +pub const FILE_ATTRIBUTE_OFFLINE: u32 = 0x1000; +pub const FILE_ATTRIBUTE_READONLY: u32 = 0x1; +pub const FILE_ATTRIBUTE_SYSTEM: u32 = 0x4; +pub const FILE_ATTRIBUTE_TEMPORARY: u32 = 0x100; +pub const FILE_FLAG_BACKUP_SEMANTICS: u32 = 0x02000000; +pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; +pub const FILE_FLAG_NO_BUFFERING: u32 = 0x20000000; +pub const FILE_FLAG_OPEN_NO_RECALL: u32 = 0x00100000; +pub const FILE_FLAG_OPEN_REPARSE_POINT: u32 = 0x00200000; +pub const FILE_FLAG_OVERLAPPED: u32 = 0x40000000; +pub const FILE_FLAG_POSIX_SEMANTICS: u32 = 0x01000000; +pub const FILE_FLAG_RANDOM_ACCESS: u32 = 0x10000000; +pub const FILE_FLAG_SESSION_AWARE: u32 = 0x00800000; +pub const FILE_FLAG_SEQUENTIAL_SCAN: u32 = 0x08000000; +pub const FILE_FLAG_WRITE_THROUGH: u32 = 0x80000000; + // File open flags pub const FILE_SYNCHRONOUS_IO_NONALERT: u32 = 0x20; pub const FILE_NON_DIRECTORY_FILE: u32 = 0x40; @@ -280,6 +329,20 @@ pub struct PeManualMap { pub pe_info: PeMetadata, } +#[repr(C)] +pub struct PeSectionMap { + pub section_handle: usize, + pub base_address: usize, + pub pe_info: PeMetadata, +} + +#[derive(Debug, Clone, Copy)] +pub struct RegionInfo { // To store the result of a VirtualQuery call + pub base_address: usize, + pub region_size: usize, + pub memory_protection: u32, +} + #[repr(C)] #[derive(Copy, Clone, Default, PartialEq, Debug, Eq)] pub struct ApiSetNamespace { @@ -637,5 +700,67 @@ pub struct ThreadBasicInformation { pub affinity_mask: usize, pub priority: i32, pub base_priority: i32, +} +#[derive(Clone, Copy)] +#[repr(C)] +pub struct RtlUserProcessParameters { + pub maximum_length: u32, + pub length: u32, + pub flags: u32, + pub debug_flags: u32, + pub console_handle: HANDLE, + pub console_flags: u32, + pub standard_input: HANDLE, + pub standard_output: HANDLE, + pub standard_error: HANDLE, + pub current_directory: CURDIR, + pub dll_path: UNICODE_STRING, + pub image_path_name: UNICODE_STRING, + pub command_line: UNICODE_STRING, + pub environment: PVOID, + pub starting_x: u32, + pub starting_y: u32, + pub count_x: u32, + pub count_y: u32, + pub count_chars_x: u32, + pub count_chars_y: u32, + pub fill_attribute: u32, + pub window_flags: u32, + pub show_window_flags: u32, + pub window_title: UNICODE_STRING, + pub desktop_info: UNICODE_STRING, + pub shell_info: UNICODE_STRING, + pub runtime_data: UNICODE_STRING, + pub current_directories: [RtlDriveLetterCurdir; 32], + pub environment_size: usize, + pub environment_version: usize, + pub package_dependency_data: PVOID, + pub process_group_id: u32, + pub loader_threads: u32, + pub redirection_dll_name: UNICODE_STRING, + pub heap_partition_name: UNICODE_STRING, + pub default_threadpool_cpu_set_masks: *mut c_void, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct CURDIR { + pub dos_path: UNICODE_STRING, + pub handle: HANDLE, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct RtlDriveLetterCurdir { + pub flags: u16, + pub length: u16, + pub time_stamp: u32, + pub dos_path: UNICODE_STRING, // I'm not sure this is a UNICODE_STRING but the struct seems to have same size +} + +#[repr(align(16))] +#[derive(Default)] +pub struct AlignedContext { + pub ctx: windows::Win32::System::Diagnostics::Debug::CONTEXT } \ No newline at end of file diff --git a/dinvoke/Cargo.toml b/dinvoke/Cargo.toml index bfac617..4283045 100644 --- a/dinvoke/Cargo.toml +++ b/dinvoke/Cargo.toml @@ -24,13 +24,12 @@ syscall = [] cc = "1.0.83" [dependencies.windows] -version = "0.51" +version = "0.62" features = [ "Win32_Foundation", "Win32_System", "Win32_System_IO", "Win32_System_Kernel", - "Win32_System_Diagnostics_Debug", "Wdk_Foundation", "Win32_System_Threading" ] \ No newline at end of file diff --git a/dinvoke/src/lib.rs b/dinvoke/src/lib.rs index 873376f..ab79577 100644 --- a/dinvoke/src/lib.rs +++ b/dinvoke/src/lib.rs @@ -14,10 +14,8 @@ use std::os::windows::ffi::OsStringExt; use nanorand::{WyRand, Rng}; use winapi::um::psapi::{EnumProcessModules, GetModuleBaseNameW, GetModuleFileNameExW}; use winapi::shared::ntdef::LARGE_INTEGER; -use windows::Win32::Foundation::BOOL; use windows::Win32::Security::SECURITY_ATTRIBUTES; #[cfg(target_arch = "x86_64")] -use windows::Win32::System::Diagnostics::Debug::{GetThreadContext,SetThreadContext}; use windows::Win32::System::Memory::MEMORY_BASIC_INFORMATION; use windows::Win32::System::SystemInformation::SYSTEM_INFO; use windows::Win32::System::Threading::PROCESS_BASIC_INFORMATION; @@ -28,9 +26,9 @@ use windows::Win32::{Foundation::{HANDLE, HINSTANCE,UNICODE_STRING}, System::Thr #[cfg(target_arch = "x86")] use windows::Win32::{Foundation::{HANDLE, HINSTANCE,UNICODE_STRING}, System::Threading::GetCurrentProcess}; #[cfg(all(target_arch = "x86_64", not(feature = "syscall")))] -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_EXECUTE_READWRITE, PAGE_READONLY, PAGE_READWRITE, PROCESS_QUERY_LIMITED_INFORMATION, PVOID, TLS_OUT_OF_INDEXES, MAX_PATH}; +use data::{ApiSetNamespace, ApiSetNamespaceEntry, ApiSetValueEntry, ClientId, EntryPoint, ExceptionHandleFunction, ExceptionPointers, LptopLevelExceptionFilter, NtAllocateVirtualMemoryArgs, NtCreateThreadExArgs, NtOpenProcessArgs, NtProtectVirtualMemoryArgs, NtWriteVirtualMemoryArgs, PeMetadata, PsAttributeList, PsCreateInfo, DLL_PROCESS_ATTACH, EAT, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PAGE_READWRITE, PROCESS_QUERY_LIMITED_INFORMATION, PVOID, TLS_OUT_OF_INDEXES, MAX_PATH}; #[cfg(all(target_arch = "x86_64", feature = "syscall"))] -use data::{ApiSetNamespace, ApiSetNamespaceEntry, ApiSetValueEntry, ClientId, EntryPoint, ExceptionHandleFunction, ExceptionPointers, LptopLevelExceptionFilter, NtAllocateVirtualMemoryArgs, NtCreateThreadExArgs, NtOpenProcessArgs, NtProtectVirtualMemoryArgs, NtWriteVirtualMemoryArgs, PeMetadata, PsAttributeList, PsCreateInfo, CONTEXT, DLL_PROCESS_ATTACH, EAT, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PROCESS_QUERY_LIMITED_INFORMATION, PVOID, TLS_OUT_OF_INDEXES, MAX_PATH}; +use data::{ApiSetNamespace, ApiSetNamespaceEntry, ApiSetValueEntry, ClientId, EntryPoint, ExceptionHandleFunction, ExceptionPointers, LptopLevelExceptionFilter, NtAllocateVirtualMemoryArgs, NtCreateThreadExArgs, NtOpenProcessArgs, NtProtectVirtualMemoryArgs, NtWriteVirtualMemoryArgs, PeMetadata, PsAttributeList, PsCreateInfo, DLL_PROCESS_ATTACH, EAT, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PROCESS_QUERY_LIMITED_INFORMATION, PVOID, TLS_OUT_OF_INDEXES, MAX_PATH}; #[cfg(target_arch = "x86")] use data::{ApiSetNamespace, ApiSetNamespaceEntry, ApiSetValueEntry, ClientId, EntryPoint, LptopLevelExceptionFilter, PeMetadata, PsAttributeList, PsCreateInfo, DLL_PROCESS_ATTACH, EAT, PAGE_EXECUTE_READWRITE, PVOID, TLS_OUT_OF_INDEXES, MAX_PATH}; @@ -39,15 +37,15 @@ static mut HARDWARE_BREAKPOINTS: bool = false; #[cfg(target_arch = "x86_64")] static mut HARDWARE_EXCEPTION_FUNCTION: ExceptionHandleFunction = ExceptionHandleFunction::NtOpenProcess; #[cfg(target_arch = "x86_64")] -static mut NT_ALLOCATE_VIRTUAL_MEMORY_ARGS: NtAllocateVirtualMemoryArgs = NtAllocateVirtualMemoryArgs{handle: HANDLE {0: -1}, base_address: ptr::null_mut()}; +static mut NT_ALLOCATE_VIRTUAL_MEMORY_ARGS: NtAllocateVirtualMemoryArgs = NtAllocateVirtualMemoryArgs{handle: HANDLE {0: -1 as _}, base_address: ptr::null_mut()}; #[cfg(target_arch = "x86_64")] static mut NT_OPEN_PROCESS_ARGS: NtOpenProcessArgs = NtOpenProcessArgs{handle: ptr::null_mut(), access:0, attributes: ptr::null_mut(), client_id: ptr::null_mut()}; #[cfg(target_arch = "x86_64")] -static mut NT_PROTECT_VIRTUAL_MEMORY_ARGS: NtProtectVirtualMemoryArgs = NtProtectVirtualMemoryArgs{handle: HANDLE {0: -1}, base_address: ptr::null_mut(), size: ptr::null_mut(), protection: 0}; +static mut NT_PROTECT_VIRTUAL_MEMORY_ARGS: NtProtectVirtualMemoryArgs = NtProtectVirtualMemoryArgs{handle: HANDLE {0: -1 as _}, base_address: ptr::null_mut(), size: ptr::null_mut(), protection: 0}; #[cfg(target_arch = "x86_64")] -static mut NT_WRITE_VIRTUAL_MEMORY_ARGS: NtWriteVirtualMemoryArgs = NtWriteVirtualMemoryArgs{handle: HANDLE {0: -1}, base_address: ptr::null_mut(), buffer: ptr::null_mut(), size: 0usize}; +static mut NT_WRITE_VIRTUAL_MEMORY_ARGS: NtWriteVirtualMemoryArgs = NtWriteVirtualMemoryArgs{handle: HANDLE {0: -1 as _}, base_address: ptr::null_mut(), buffer: ptr::null_mut(), size: 0usize}; #[cfg(target_arch = "x86_64")] -static mut NT_CREATE_THREAD_EX_ARGS: NtCreateThreadExArgs = NtCreateThreadExArgs{thread:ptr::null_mut(), access: 0, attributes: ptr::null_mut(), process: HANDLE {0: -1}}; +static mut NT_CREATE_THREAD_EX_ARGS: NtCreateThreadExArgs = NtCreateThreadExArgs{thread:ptr::null_mut(), access: 0, attributes: ptr::null_mut(), process: HANDLE {0: -1 as _}}; static mut HOOKED_FUNCTIONS_INFO: Vec<(usize,Vec)> = vec![]; #[cfg(all(target_arch = "x86_64", feature = "syscall"))] @@ -80,10 +78,8 @@ struct Configuration /// Enables or disables the use of exception handlers in /// combination with hardware breakpoints. #[cfg(target_arch = "x86_64")] -pub fn use_hardware_breakpoints(value: bool) -{ - unsafe - { +pub fn use_hardware_breakpoints(value: bool) { + unsafe { HARDWARE_BREAKPOINTS = value; } } @@ -102,22 +98,31 @@ pub fn set_hardware_breakpoint(address: usize) { unsafe { - let mut context = CONTEXT::default(); - context.ContextFlags = 0x100000 | 0x10; // CONTEXT_DEBUG_REGISTERS - let mut lp_context: *mut windows::Win32::System::Diagnostics::Debug::CONTEXT = std::mem::transmute(&context); - let _ = GetThreadContext(GetCurrentThread(), lp_context); + use data::AlignedContext; + use windows::Win32::System::Diagnostics::Debug::CONTEXT_FLAGS; - 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 - (*context).Dr7 = (*context).Dr7 & !(((1 << 2) - 1) << 18); // 0xfff3ffff - (*context).Dr7 = ((*context).Dr7 & !(((1 << 1) - 1) << 0)) | (1 << 0); // 0xfffffffe + let mut ctx = AlignedContext::default(); + ctx.ctx.ContextFlags = CONTEXT_FLAGS(0x100000 | 0x10); // CONTEXT_DEBUG_REGISTERS + let r = get_thread_context(GetCurrentThread(), &mut ctx.ctx); + if !r { + let r = get_last_error(); + println!("{}{}", &lc!("[x] Call to GetThreadContext failed. Error code: "), r); + return; + } - (*context).ContextFlags = 0x100000 | 0x10; - lp_context = std::mem::transmute(context); + (ctx.ctx).Dr0 = address as u64; + (ctx.ctx).Dr6 = 0; + ctx.ctx.Dr7 = ctx.ctx.Dr7 & !(((1 << 2) - 1) << 16); // 0xfffcffff -> Break on instruction execution only + ctx.ctx.Dr7 = ctx.ctx.Dr7 & !(((1 << 2) - 1) << 18); // 0xfff3ffff + ctx.ctx.Dr7 = (ctx.ctx.Dr7 & !(((1 << 1) - 1) << 0)) | (1 << 0); // 0xfffffffe + ctx.ctx.ContextFlags = CONTEXT_FLAGS(0x100000 | 0x10); - let _ = SetThreadContext(GetCurrentThread(), lp_context ); + let r = set_thread_context(GetCurrentThread(), &ctx.ctx ); + if !r { + let r = get_last_error(); + println!("{}{}", &lc!("[x] Call to SetThreadContext failed. Error code: "), r); + return; + } } } @@ -226,7 +231,7 @@ pub fn hook_function(src_address: usize, dst_address: usize) -> bool unsafe { let original_address = src_address; - let handle = HANDLE(-1); + let handle = HANDLE(-1 as _); let base_address: *mut PVOID = std::mem::transmute(&original_address); let size = 4096 as usize; let size: *mut usize = std::mem::transmute(&size); @@ -343,7 +348,7 @@ pub fn unhook_function(address: usize) -> bool } let original_address = unhook_info.0; - let handle = HANDLE(-1); + let handle = HANDLE(-1 as _); let base_address: *mut PVOID = std::mem::transmute(&original_address); let size = 4096 as usize; let size: *mut usize = std::mem::transmute(&size); @@ -436,7 +441,7 @@ fn get_modules_list() -> Result, u32> let mut mod_handles: Vec = Vec::new(); let mut reserved = 0; let mut needed = 0; - let current_process = HANDLE(-1); + let current_process = HANDLE(-1 as _); let current_process: *mut winapi::ctypes::c_void = std::mem::transmute(current_process); // Code extracted from winproc @@ -462,7 +467,6 @@ fn get_modules_list() -> Result, u32> mod_handles.resize(needed as usize, 0); } - Ok(mod_handles) } } @@ -471,7 +475,7 @@ fn get_module_name(hmodule: usize) -> Result { unsafe { - let current_process = HANDLE(-1); + let current_process = HANDLE(-1 as _); let current_process: *mut winapi::ctypes::c_void = std::mem::transmute(current_process); let mut buffer: [u16; MAX_PATH as _] = std::mem::zeroed(); @@ -491,7 +495,7 @@ fn get_module_path(hmodule: usize) -> Result { unsafe { - let current_process = HANDLE(-1); + let current_process = HANDLE(-1 as _); let current_process: *mut winapi::ctypes::c_void = std::mem::transmute(current_process); let mut buffer: [u16; MAX_PATH as _] = std::mem::zeroed(); @@ -538,12 +542,9 @@ pub fn get_function_address(module_base_address: usize, function: &str) -> usize let magic = *(opt_header as *mut i16); let p_export: usize; - if magic == 0x010b - { + if magic == 0x010b { p_export = opt_header + 0x60; - } - else - { + } else { p_export = opt_header + 0x70; } @@ -582,8 +583,7 @@ pub fn get_function_address(module_base_address: usize, function: &str) -> usize let mut ret: usize = 0; - if function_ptr != ptr::null_mut() - { + if function_ptr != ptr::null_mut() { ret = function_ptr as usize; } @@ -602,12 +602,9 @@ fn get_forward_address(function_ptr: *mut u8) -> usize { loop { - if *ptr as char != '\0' - { + if *ptr as char != '\0' { forwarded_names.push(*ptr as char); - } - else - { + } else { break; } @@ -615,16 +612,14 @@ fn get_forward_address(function_ptr: *mut u8) -> usize { c = c - 1; // Assume there wont be an exported address with len > 100 - if c == 0 - { + if c == 0 { return function_ptr as usize; } } let values: Vec<&str> = forwarded_names.split(".").collect(); - if values.len() != 2 - { + if values.len() != 2 { return function_ptr as usize; } @@ -640,12 +635,11 @@ fn get_forward_address(function_ptr: *mut u8) -> usize { let prev_hook = panic::take_hook(); panic::set_hook(Box::new(|_| {})); let result = panic::catch_unwind(|| { - format!("{}{}",&forwarded_module_name[..forwarded_module_name.len() - 2], ".dll"); + let _ = format!("{}{}",&forwarded_module_name[..forwarded_module_name.len() - 2], ".dll"); }); panic::set_hook(prev_hook); - if result.is_err() - { + if result.is_err() { return function_ptr as usize; } @@ -658,21 +652,18 @@ fn get_forward_address(function_ptr: *mut u8) -> usize { None => {forwarded_module_name} }; } - else - { + else { forwarded_module_name = forwarded_module_name + ".dll"; } let mut module = get_module_base_address(&forwarded_module_name); // If the module is not already loaded, we try to load it dynamically calling LoadLibraryA - if module == 0 - { + if module == 0 { module = load_library_a(&forwarded_module_name); } - if module != 0 - { + if module != 0 { return get_function_address(module, &forwarded_export_name); } @@ -700,12 +691,9 @@ pub fn get_api_mapping() -> HashMap { let api_set_map_offset: usize; - if size_of::() == 4 - { + if size_of::() == 4 { api_set_map_offset = 0x38; - } - else - { + } else { api_set_map_offset = 0x68; } @@ -740,8 +728,7 @@ pub fn get_api_mapping() -> HashMap { let api_set_entry_key = format!("{}{}",&api_set_entry_name[..api_set_entry_name.len()-2], ".dll"); let mut set_value_ptr: *mut ApiSetValueEntry = ptr::null_mut(); - if set_entry.value_length == 1 - { + if set_entry.value_length == 1 { let value = (api_set_namespace_ptr as usize + set_entry.value_offset as usize) as *mut u8; set_value_ptr = std::mem::transmute(value); } @@ -767,8 +754,7 @@ pub fn get_api_mapping() -> HashMap { } } - if set_value_ptr == ptr::null_mut() - { + if set_value_ptr == ptr::null_mut() { set_value_ptr = (api_set_namespace_ptr as usize + set_entry.value_offset as usize) as *mut ApiSetValueEntry; } } @@ -782,14 +768,12 @@ pub fn get_api_mapping() -> HashMap { while r < (set_value.value_count / 2 ) { let c = *value_ptr as char; - if c != '\0' - { + if c != '\0' { api_set_value.push(c); r = r + 1; } value_ptr = value_ptr.add(1); - } } @@ -841,12 +825,9 @@ pub fn get_ntdll_eat(module_base_address: usize) -> EAT { let magic = *(opt_header as *mut i16); let p_export: usize; - if magic == 0x010b - { + if magic == 0x010b { p_export = opt_header + 0x60; - } - else - { + } else { p_export = opt_header + 0x70; } @@ -879,7 +860,6 @@ pub fn get_ntdll_eat(module_base_address: usize) -> EAT { function_name = function_name.replace("Zw", "Nt"); eat.insert(function_ptr as usize,function_name ); } - } eat @@ -913,8 +893,7 @@ pub fn get_syscall_id(eat: &EAT, function_name: &str) -> u32 { let mut i = 0; for (_a,b) in eat.iter() { - if b == function_name - { + if b == function_name { return i; } @@ -995,15 +974,13 @@ pub fn prepare_syscall(id: u32, eat: EAT) -> usize { unsafe { - if id == u32::MAX - { + if id == u32::MAX { return 0; } let mut ptr: *mut u8 = std::mem::transmute(&id); - for i in 0..4 - { + for i in 0..4 { sh[4 + i] = *ptr; ptr = ptr.add(1); } @@ -1012,8 +989,7 @@ pub fn prepare_syscall(id: u32, eat: EAT) -> usize { let export = eat.iter().skip(id as usize).next().unwrap(); let mut function_addr = get_function_address(ntdll, export.1); - if function_addr == 0 - { + if function_addr == 0 { return 0; } @@ -1029,8 +1005,7 @@ pub fn prepare_syscall(id: u32, eat: EAT) -> usize { { let index = rng.generate_range(0_usize..=max_range) as usize; - if index < max_range / 5 - { + if index < max_range / 5 { function = s; break; } @@ -1038,28 +1013,24 @@ pub fn prepare_syscall(id: u32, eat: EAT) -> usize { function_addr = get_function_address(ntdll, function); - if function_addr == 0 - { + if function_addr == 0 { return 0; } syscall_addr = find_syscall_address(function_addr); - if syscall_addr != 0 - { + if syscall_addr != 0 { break; } } - if syscall_addr == 0 - { + if syscall_addr == 0 { return 0; } } let mut syscall_ptr: *mut u8 = std::mem::transmute(&syscall_addr); - for j in 0..8 - { + for j in 0..8 { sh[10 + j] = *syscall_ptr; syscall_ptr = syscall_ptr.add(1); } @@ -1074,8 +1045,7 @@ pub fn prepare_syscall(id: u32, eat: EAT) -> usize { let old_protection: *mut u32 = std::mem::transmute(&o); let ret = nt_allocate_virtual_memory(handle, base_address, 0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - if ret != 0 - { + if ret != 0 { return 0; } @@ -1084,17 +1054,14 @@ pub fn prepare_syscall(id: u32, eat: EAT) -> usize { let bytes_written: *mut usize = std::mem::transmute(&b); let ret = nt_write_virtual_memory(handle, *base_address, buffer, nsize, bytes_written); - if ret != 0 - { + if ret != 0 { return 0; } let ret = nt_protect_virtual_memory(handle, base_address, size, PAGE_EXECUTE_READ, old_protection); - let _r = close_handle(handle); - - if ret != 0 - { + + if ret != 0 { return 0; } @@ -1123,19 +1090,17 @@ pub fn call_module_entry_point(pe_info: PeMetadata, module_base_address: usize) let entry_point; if pe_info.is_32_bit { entry_point = module_base_address + pe_info.opt_header_32.AddressOfEntryPoint as usize; - } - else { + } else { entry_point = module_base_address + pe_info.opt_header_64.address_of_entry_point as usize; - } unsafe { let main: EntryPoint = std::mem::transmute(entry_point); - let module = HINSTANCE {0: entry_point as isize}; + let module = HINSTANCE {0: entry_point as _}; let ret = main(module, DLL_PROCESS_ATTACH, ptr::null_mut()); - if !ret.as_bool() { + if !ret { return Err(lc!("[x] Failed to call module's entry point (DllMain -> DLL_PROCESS_ATTACH).")); } @@ -1240,12 +1205,9 @@ pub fn ldr_get_procedure_address (module_handle: usize, function_name: &str, ord let f: UnsafeCell = String::default().into(); let mut fun_name: *mut String = std::mem::transmute(f.get()); - if function_name == "" - { + if function_name == "" { fun_name = ptr::null_mut(); - } - else - { + } else { *fun_name = function_name.to_string(); } @@ -1255,12 +1217,9 @@ pub fn ldr_get_procedure_address (module_handle: usize, function_name: &str, ord match ret { Some(x) => { - if x == 0 - { + if x == 0 { return *return_address as usize; - } - else - { + } else { return 0; } }, @@ -1327,21 +1286,16 @@ pub fn load_library_a_tp(module: &str) -> usize { let load_library = get_function_address(k32, &lc!("LoadLibraryA")); dynamic_invoke!(ntdll,&lc!("RtlQueueWorkItem"),func_ptr,ret,load_library,module_name,0); - match ret { Some(x) => { - if x != 0 - { + if x != 0 { return 0; - } - else - { + } else { use std::{thread, time}; let ten_millis = time::Duration::from_millis(500); thread::sleep(ten_millis); - return get_module_base_address(module); } }, @@ -1380,6 +1334,39 @@ pub fn load_library_a(module: &str) -> usize { } } +/// THIS IMPLEMENTATION IS WRONG, DON'T USE IT +/// USE load_library_a INSTEAD. WILL FIX. +/// +/// Dynamically calls LoadLibraryW. +/// +/// It will return either the module's base address or 0. +/// +/// # Examples +/// +/// ``` +/// let ret = dinvoke::load_library_w("ntdll.dll"); +/// +/// if ret != 0 {println!("ntdll.dll base address is 0x{:X}.", addr)}; +/// ``` +pub fn load_library_w(module: &str) -> usize { + + unsafe + { + let ret: Option; + let func_ptr: data::LoadLibraryW; + let name = CString::new(module.to_string()).expect(""); + let module_name: *mut u16 = std::mem::transmute(name.as_ptr()); // Need a wide char string + let k32 = get_module_base_address(&lc!("kernel32.dll")); + dynamic_invoke!(k32,&lc!("LoadLibraryW"),func_ptr,ret,module_name); + + match ret + { + Some(x) => { return x; }, + None => { return 0; } + } + } +} + /// Frees the loaded dll. The function expects the module's base address. /// /// If the function succeeds, the return value is nonzero. @@ -1408,6 +1395,44 @@ pub fn free_library(module_handle: isize) -> usize { } } +/// Dynamically calls GetThreadContext +/// Second parameter expects a windows::Win32::System::Diagnostics::Debug::CONTEXT structure properly aligned. Check `set_hardware_breakpoint` +/// function to replicate the expected behaviour. +pub fn get_thread_context(thread_handle: HANDLE, context_ptr: *mut windows::Win32::System::Diagnostics::Debug::CONTEXT) -> bool +{ + unsafe + { + let ret: Option; + let func_ptr: data::GetThreadContext; + let module_base_address = get_module_base_address(&lc!("kernel32.dll")); + dynamic_invoke!(module_base_address,&lc!("GetThreadContext"),func_ptr,ret,thread_handle,context_ptr); + + match ret { + Some(x) => return x, + None => return false, + } + } +} + +/// Dynamically calls SetThreadContext +/// Second parameter expects a windows::Win32::System::Diagnostics::Debug::CONTEXT structure properly aligned. Check `set_hardware_breakpoint` +/// function to replicate the expected behaviour. +pub fn set_thread_context(thread_handle: HANDLE, context_ptr: *const windows::Win32::System::Diagnostics::Debug::CONTEXT) -> bool +{ + unsafe + { + let ret: Option; + let func_ptr: data::SetThreadContext; + let module_base_address = get_module_base_address(&lc!("kernel32.dll")); + dynamic_invoke!(module_base_address,&lc!("SetThreadContext"),func_ptr,ret,thread_handle,context_ptr); + + match ret { + Some(x) => return x, + None => return false, + } + } +} + /// Dynamically calls CreateFileA. /// On success, it returns a valid handle to the specified file. Otherwise, a null handle is returned. pub fn create_file_a(name: *mut u8, access: u32, mode: u32, attributes: *const SECURITY_ATTRIBUTES, disposition: u32, flags: u32, template: HANDLE) -> HANDLE { @@ -1421,7 +1446,25 @@ pub fn create_file_a(name: *mut u8, access: u32, mode: u32, attributes: *const S match ret { Some(x) => return x, - None => return HANDLE { 0: 0 } , + None => return HANDLE { 0: ptr::null_mut() } , + } + } +} + +/// Dynamically calls CreateFilew. +/// On success, it returns a valid handle to the specified file. Otherwise, a null handle is returned. +pub fn create_file_w(name: *mut u16, access: u32, mode: u32, attributes: *const SECURITY_ATTRIBUTES, disposition: u32, flags: u32, template: HANDLE) -> HANDLE { + + unsafe + { + let ret: Option; + let func_ptr: data::CreateFileW; + let kernel32 = get_module_base_address(&lc!("kernel32.dll")); + dynamic_invoke!(kernel32,&lc!("CreateFileW"),func_ptr,ret,name,access,mode,attributes,disposition,flags,template); + + match ret { + Some(x) => return x, + None => return HANDLE { 0: ptr::null_mut() } , } } } @@ -1457,7 +1500,7 @@ pub fn create_file_mapping_w(file: HANDLE, attributes: *const SECURITY_ATTRIBUTE match ret { Some(x) => return x, - None => return HANDLE { 0: 0 } , + None => return HANDLE { 0: ptr::null_mut() } , } } } @@ -1486,13 +1529,13 @@ pub fn unmap_view_of_file (base_address: PVOID) -> bool { unsafe { - let ret: Option; + let ret: Option; let func_ptr: data::UnmapViewOfFile; let kernel32 = get_module_base_address(&lc!("kernel32.dll")); dynamic_invoke!(kernel32,&lc!("UnmapViewOfFile"),func_ptr,ret,base_address); match ret { - Some(x) => return x.as_bool(), + Some(x) => return x, None => return false , } } @@ -1504,13 +1547,13 @@ pub fn rollback_transaction(transaction: HANDLE) -> bool { unsafe { - let ret: Option; + let ret: Option; let func_ptr: data::RollbackTransaction; let ktmv = load_library_a(&lc!("KtmW32.dll")); dynamic_invoke!(ktmv,&lc!("RollbackTransaction"),func_ptr,ret,transaction); match ret { - Some(x) => return x.as_bool(), + Some(x) => return x, None => return false , } } @@ -1611,12 +1654,9 @@ pub fn close_handle(handle: HANDLE) -> bool { match ret { Some(x) => { - if x == 0 - { + if x == 0 { return false; - } - else - { + } else { return true; } }, @@ -1790,6 +1830,23 @@ pub fn get_system_info(sysinfo: *mut SYSTEM_INFO) { } } +/// Dynamically calls VirtualQuery. +pub fn virtual_query(page_address: *const c_void, buffer: *mut MEMORY_BASIC_INFORMATION, length: usize) -> usize{ + + unsafe + { + let ret: Option; + let func_ptr: data::VirtualQuery; + let kernel32 = get_module_base_address(&lc!("kernel32.dll")); + dynamic_invoke!(kernel32,&lc!("VirtualQuery"),func_ptr,ret,page_address,buffer,length); + + match ret { + Some(x) => return x, + None => return 0 , + } + } +} + /// Dynamically calls VirtualQueryEx. pub fn virtual_query_ex(process_handle: HANDLE, page_address: *const c_void, buffer: *mut MEMORY_BASIC_INFORMATION, length: usize) -> usize{ @@ -1817,10 +1874,7 @@ pub fn virtual_free(address: PVOID, size: usize, free_type: u32) -> bool { dynamic_invoke!(k32,&lc!("VirtualFree"),func_ptr,ret,address,size,free_type); match ret { - Some(x) => - { - return x; - }, + Some(x) => return x, None => return false, } } @@ -1869,7 +1923,7 @@ pub fn nt_write_virtual_memory (mut handle: HANDLE, base_address: PVOID, mut buf NT_WRITE_VIRTUAL_MEMORY_ARGS.size = size; set_hardware_breakpoint(find_syscall_address(addr)); - handle = HANDLE {0: -1}; + handle = HANDLE {0: -1 as _}; let buff = vec![20]; buffer = std::mem::transmute(buff.as_ptr()); size = buff.len(); @@ -1926,7 +1980,7 @@ pub fn nt_allocate_virtual_memory (mut handle: HANDLE, mut base_address: *mut PV NT_ALLOCATE_VIRTUAL_MEMORY_ARGS.base_address = base_address; set_hardware_breakpoint(find_syscall_address(addr)); - handle = HANDLE {0: -1}; + handle = HANDLE {0: -1 as _}; base_address = ptr::null_mut(); } @@ -1981,7 +2035,7 @@ pub fn nt_protect_virtual_memory (mut handle: HANDLE, mut base_address: *mut PVO NT_PROTECT_VIRTUAL_MEMORY_ARGS.protection = new_protection; set_hardware_breakpoint(find_syscall_address(addr)); - handle = HANDLE {0: -1}; + handle = HANDLE {0: -1 as _}; base_address = ptr::null_mut(); let s = 10usize; size = std::mem::transmute(&s); @@ -2039,12 +2093,12 @@ pub fn nt_open_process (mut handle: *mut HANDLE, mut access: u32, mut attributes NT_OPEN_PROCESS_ARGS.client_id = client_id; set_hardware_breakpoint(find_syscall_address(addr)); - let h = HANDLE {0: -1}; + let h = HANDLE {0: -1 as _}; handle = std::mem::transmute(&h); access = PROCESS_QUERY_LIMITED_INFORMATION; let a = OBJECT_ATTRIBUTES::default(); attributes = std::mem::transmute(&a); - let c = ClientId {unique_process: HANDLE {0: std::process::id() as isize}, unique_thread: HANDLE::default()}; + let c = ClientId {unique_process: HANDLE {0: std::process::id() as _}, unique_thread: HANDLE::default()}; client_id = std::mem::transmute(&c); } @@ -2134,6 +2188,25 @@ pub fn nt_query_information_file(handle: HANDLE, io: *mut IO_STATUS_BLOCK, file_ } } +/// Dynamically calls NtUnmapViewOfSection. +/// +pub fn nt_unmap_view_of_section(handle: HANDLE, base_address: PVOID) -> i32 +{ + unsafe + { + let ret: Option; + let func_ptr: data::NtUnmapViewOfSection; + let kernel32 = get_module_base_address(&lc!("ntdll.dll")); + dynamic_invoke!(kernel32,&lc!("NtUnmapViewOfSection"),func_ptr,ret,handle,base_address); + + match ret { + Some(x) => return x, + None => return -1, + } + } + +} + /// Dynamically calls RtlAdjustPrivilege. /// /// It will return the NTSTATUS value returned by the call. @@ -2266,12 +2339,12 @@ pub fn nt_create_thread_ex (mut thread: *mut HANDLE, mut access: u32, mut attrib NT_CREATE_THREAD_EX_ARGS.process = process; set_hardware_breakpoint(find_syscall_address(addr)); - let h = HANDLE {0: -1}; + let h = HANDLE {0: -1 as _}; thread = std::mem::transmute(&h); access = PROCESS_QUERY_LIMITED_INFORMATION; let a = OBJECT_ATTRIBUTES::default(); attributes = std::mem::transmute(&a); - process = HANDLE {0: -1}; + process = HANDLE {0: -1 as _}; } dynamic_invoke!(ntdll,&lc!("NtCreateThreadEx"),func_ptr,ret,thread,access,attributes,process,function,args,flags,zero,stack,reserve,buffer); @@ -2324,7 +2397,6 @@ pub fn nt_read_virtual_memory (handle: HANDLE, base_address: PVOID, buffer: PVOI } - /// Dynamically calls an exported function from the specified module. /// /// This macro will use the dinvoke crate functions to obtain an exported @@ -2396,13 +2468,10 @@ macro_rules! dynamic_invoke { ($a:expr, $b:expr, $c:expr, $d:expr, $($e:tt)*) => { let function_ptr = $crate::get_function_address($a, $b); - if function_ptr != 0 - { + if function_ptr != 0 { $c = std::mem::transmute(function_ptr); $d = Some($c($($e)*)); - } - else - { + } else { $d = None; } @@ -2444,27 +2513,22 @@ macro_rules! dynamic_invoke { #[macro_export] macro_rules! execute_syscall { - ($a:expr, $b:expr, $c:expr, $($d:tt)*) => { - + ($a:expr, $b:expr, $c:expr, $($d:tt)*) => + { let eat = $crate::get_ntdll_eat($crate::get_module_base_address("ntdll.dll")); let id = $crate::get_syscall_id(&eat, $a); if id != u32::MAX { let function_ptr = $crate::prepare_syscall(id as u32, eat); - if function_ptr != 0 - { + if function_ptr != 0 { $b = std::mem::transmute(function_ptr); $c = Some($b($($d)*)); - } - else - { + } else { $c = None; } let ptr = std::mem::transmute(function_ptr); $crate::virtual_free(ptr, 0, 0x00008000); - } - else - { + } else { $c = None; } } @@ -2474,8 +2538,8 @@ macro_rules! execute_syscall { #[macro_export] macro_rules! indirect_syscall { - ($a:expr, $($x:expr),*) => { - + ($a:expr, $($x:expr),*) => + { unsafe { let mut temp_vec = Vec::new(); @@ -2522,8 +2586,7 @@ pub fn prepare_syscall(function_name: &str) -> (u32, usize) for s in eat.values() { let index = rng.generate_range(0..max_range); - if index < max_range / 5 - { + if index < max_range / 5 { function = s; break; } diff --git a/dmanager/Cargo.toml b/dmanager/Cargo.toml index 06a354c..a34e261 100644 --- a/dmanager/Cargo.toml +++ b/dmanager/Cargo.toml @@ -17,7 +17,7 @@ litcrypt2 = "=0.1.2" dinvoke = { path = "../dinvoke" } [dependencies.windows] -version = "0.51" +version = "0.62" features = [ "Win32_Foundation" ] diff --git a/dmanager/src/lib.rs b/dmanager/src/lib.rs index 2646328..b4911a3 100644 --- a/dmanager/src/lib.rs +++ b/dmanager/src/lib.rs @@ -31,8 +31,7 @@ impl Manager { pub fn new_module (&mut self, address: usize, payload: Vec, decoy: Vec) -> Result<(), String> { - if self.payloads.contains_key(&address) - { + if self.payloads.contains_key(&address) { return Err(lc!("[x] This address is already mapped.")); } @@ -48,8 +47,7 @@ impl Manager { let mut xor_key: u8 = *key_ptr; key_ptr = key_ptr.add(1); - while *key_ptr != '\0' as u8 - { + while *key_ptr != '\0' as u8 { xor_key = xor_key ^ *key_ptr; key_ptr = key_ptr.add(1); } @@ -73,8 +71,7 @@ impl Manager { pub fn new_shellcode (&mut self, address: usize, payload: Vec, decoy: Vec) -> Result<(), String> { - if self.payloads.contains_key(&address) - { + if self.payloads.contains_key(&address) { return Err(lc!("[x] This shellcode is already mapped.")); } @@ -87,8 +84,7 @@ impl Manager { let mut xor_key: u8 = *key_ptr; key_ptr = key_ptr.add(1); - while *key_ptr != '\0' as u8 - { + while *key_ptr != '\0' as u8 { xor_key = xor_key ^ *key_ptr; key_ptr = key_ptr.add(1); } @@ -115,8 +111,7 @@ impl Manager { let mut module_ptr = module.as_ptr(); let mut final_module: Vec = vec![]; - for _i in 0..module.len() - { + for _i in 0..module.len() { final_module.push(*module_ptr ^ key); module_ptr = module_ptr.add(1); } @@ -139,27 +134,21 @@ impl Manager { let decoy_info = self.decoys_metadata.get(&address).unwrap(); let addr: PVOID = std::mem::transmute(address); - let handle = HANDLE {0: -1}; + let handle = HANDLE {0: -1 as _}; let base_address: *mut PVOID = std::mem::transmute(&address); let s: UnsafeCell = i64::default().into(); let size: *mut usize = std::mem::transmute(s.get()); - if decoy_info.is_32_bit - { + if decoy_info.is_32_bit { *size = decoy_info.opt_header_32.SizeOfImage as usize; - } - else - { + } else { *size = decoy_info.opt_header_64.size_of_image as usize; } - 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 - { + if ret != 0 { return Err(lc!("[x] Error changing memory protection.")); } @@ -168,14 +157,12 @@ impl Manager { 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() - { + for i in 0..decrypted_payload.len() { *(decrypted_payload_ptr.add(i)) = 0u8; } } self.counter.insert(address, self.counter[&address] + 1); - } Ok(()) @@ -196,36 +183,29 @@ impl Manager { let pe_info = self.decoys_metadata.get(&address).unwrap(); let addr: PVOID = std::mem::transmute(address); - let handle = HANDLE {0: -1}; + let handle = HANDLE {0: -1 as _}; let base_address: *mut PVOID = std::mem::transmute(&address); let s: UnsafeCell = usize::default().into(); let size: *mut usize = std::mem::transmute(s.get()); - if pe_info.is_32_bit - { + if pe_info.is_32_bit { *size = pe_info.opt_header_32.SizeOfImage as usize; - } - else - { + } else { *size = pe_info.opt_header_64.size_of_image as usize; } - 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); dinvoke::rtl_zero_memory(*base_address, *size); - if ret != 0 - { + if ret != 0 { return Err(lc!("[x] Error changing memory protection.")); } let _r = manualmap::map_to_allocated_memory(decrypted_decoy.as_ptr(), addr, pe_info)?; } - - if self.counter.get(&address).unwrap() >= &1 - { + if self.counter.get(&address).unwrap() >= &1 { self.counter.insert(address, self.counter[&address] - 1); } @@ -246,21 +226,17 @@ impl Manager { let decrypted_decoy = Manager::xor_module(decoy.to_vec(), key); let result = overload::managed_module_stomping(&decrypted_decoy, address, 0); - if !result.is_ok() - { + if !result.is_ok() { return Err(lc!("[x] Error hiding shellcode.")); } } - if self.counter.get(&address).unwrap() >= &1 - { + if self.counter.get(&address).unwrap() >= &1 { self.counter.insert(address, self.counter[&address] - 1); } - } Ok(()) - } pub fn stomp_shellcode(&mut self, address: usize) -> Result<(),String> @@ -274,27 +250,21 @@ impl Manager { 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() - { + unsafe { + for i in 0..decrypted_payload.len() { *(decrypted_payload_ptr.add(i)) = 0u8; } } - if !result.is_ok() - { + if !result.is_ok() { return Err(lc!("[x] Error stomping shellcode.")); } - } self.counter.insert(address, self.counter[&address] + 1); - } Ok(()) - } } \ No newline at end of file diff --git a/manualmap/Cargo.toml b/manualmap/Cargo.toml index fc275f9..ad1a8ac 100644 --- a/manualmap/Cargo.toml +++ b/manualmap/Cargo.toml @@ -15,7 +15,7 @@ os_info = { version = "3.0", default-features = false } winapi = {version = "0.3.9", features = ["ntdef"]} [dependencies.windows] -version = "0.51" +version = "0.62" features = [ "Win32_Foundation", "Win32_Security", diff --git a/manualmap/src/lib.rs b/manualmap/src/lib.rs index 226a3ee..e06adf3 100644 --- a/manualmap/src/lib.rs +++ b/manualmap/src/lib.rs @@ -8,21 +8,17 @@ use std::{fs, ptr}; use std::mem::size_of; use std::ffi::c_void; use winapi::shared::ntdef::LARGE_INTEGER; - +use windows::Win32::System::Memory::MEMORY_BASIC_INFORMATION; +use windows::Win32::System::SystemInformation::SYSTEM_INFO; use windows::Win32::System::SystemServices::{IMAGE_BASE_RELOCATION, IMAGE_IMPORT_DESCRIPTOR}; use windows::Win32::System::Threading::GetCurrentProcess; use windows::Win32::System::WindowsProgramming::{IMAGE_THUNK_DATA32, IMAGE_THUNK_DATA64}; use windows::Win32::{ - Foundation::{HANDLE,UNICODE_STRING}, + Foundation::{HANDLE,UNICODE_STRING, OBJECT_ATTRIBUTE_FLAGS}, System::{Diagnostics::Debug::{IMAGE_OPTIONAL_HEADER32, IMAGE_SECTION_HEADER},IO::IO_STATUS_BLOCK} }; use windows::Wdk::Foundation::OBJECT_ATTRIBUTES; - -use data::{ImageFileHeader, ImageOptionalHeader64, MEM_COMMIT, MEM_RESERVE, - PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY, PAGE_READWRITE, PVOID, PeMetadata, SECTION_MEM_EXECUTE, - SECTION_MEM_READ, SECTION_MEM_WRITE, FILE_EXECUTE, FILE_READ_ATTRIBUTES, SYNCHRONIZE, FILE_READ_DATA, FILE_SHARE_READ, FILE_SHARE_DELETE, - FILE_SYNCHRONOUS_IO_NONALERT, FILE_NON_DIRECTORY_FILE, SECTION_ALL_ACCESS, SEC_IMAGE, PeManualMap}; - +use data::{FILE_EXECUTE, FILE_NON_DIRECTORY_FILE, FILE_READ_ATTRIBUTES, FILE_READ_DATA, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT, ImageFileHeader, ImageOptionalHeader64, MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY, PAGE_GUARD, PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY, PVOID, PeManualMap, PeMetadata, PeSectionMap, RegionInfo, SEC_IMAGE, SECTION_ALL_ACCESS, SECTION_MEM_EXECUTE, SECTION_MEM_READ, SECTION_MEM_WRITE, SYNCHRONIZE}; use litcrypt2::lc; @@ -92,8 +88,7 @@ pub fn manually_map_module (file_ptr: *const u8, clean_dos_headers: bool, run_ca let dwsize; if pe_info.is_32_bit { dwsize = pe_info.opt_header_32.SizeOfImage as usize; - } - else { + } else { dwsize = pe_info.opt_header_64.size_of_image as usize; } @@ -148,8 +143,7 @@ pub fn get_runtime_table(image_ptr: *mut c_void) -> (*mut data::RuntimeFunction, { let mut size: u32 = 0; let module_metadata = get_pe_metadata(image_ptr as *const u8, false); - if !module_metadata.is_ok() - { + if !module_metadata.is_ok() { return (ptr::null_mut(), size); } @@ -198,8 +192,7 @@ pub fn get_pe_metadata (module_ptr: *const u8, check_signature: bool) -> Result< 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); - if pe_metadata.pe != 0x4550 && check_signature - { + if pe_metadata.pe != 0x4550 && check_signature { return Err(lc!("[x] Invalid PE signature.")); } @@ -208,27 +201,23 @@ pub fn get_pe_metadata (module_ptr: *const u8, check_signature: bool) -> Result< let opt_header: *const u16 = (module_ptr as usize + e_lfanew as usize + 0x18) as *const u16; let pe_arch = *(opt_header); - if pe_arch == 0x010B - { + if pe_arch == 0x010B { pe_metadata.is_32_bit = true; let opt_header_content: *const IMAGE_OPTIONAL_HEADER32 = std::mem::transmute(opt_header); pe_metadata.opt_header_32 = *opt_header_content; } - else if pe_arch == 0x020B - { + else if pe_arch == 0x020B { pe_metadata.is_32_bit = false; let opt_header_content: *const ImageOptionalHeader64 = std::mem::transmute(opt_header); pe_metadata.opt_header_64 = *opt_header_content; } - else - { + else { return Err(lc!("[x] Invalid magic value.")); } let mut sections: Vec = vec![]; - for i in 0..pe_metadata.image_file_header.number_of_sections - { + for i in 0..pe_metadata.image_file_header.number_of_sections { let section_ptr = (opt_header as usize + pe_metadata.image_file_header.size_of_optional_header as usize + (i * 0x28) as usize) as *const u8; let section_ptr: *const IMAGE_SECTION_HEADER = std::mem::transmute(section_ptr); sections.push(*section_ptr); @@ -246,24 +235,19 @@ pub fn get_pe_metadata (module_ptr: *const u8, check_signature: bool) -> Result< /// mapped and the module's metadata. pub fn map_module_to_memory(module_ptr: *const u8, image_ptr: *mut c_void, pe_info: &PeMetadata) -> Result<(),String> { - if (pe_info.is_32_bit && (size_of::() == 8)) || (!pe_info.is_32_bit && (size_of::() == 4)) - { + if (pe_info.is_32_bit && (size_of::() == 8)) || (!pe_info.is_32_bit && (size_of::() == 4)) { return Err(lc!("[x] The module architecture does not match the process architecture.")); } let nsize; - if pe_info.is_32_bit - { + if pe_info.is_32_bit { nsize = pe_info.opt_header_32.SizeOfHeaders as usize; - } - else - { + } else { nsize = pe_info.opt_header_64.size_of_headers as usize; } unsafe { - let handle = GetCurrentProcess(); let base_address: *mut c_void = std::mem::transmute(image_ptr); let buffer: *mut c_void = std::mem::transmute(module_ptr); @@ -271,8 +255,7 @@ pub fn map_module_to_memory(module_ptr: *const u8, image_ptr: *mut c_void, pe_in let bytes_written: *mut usize = std::mem::transmute(&written); let ret = dinvoke::nt_write_virtual_memory(handle, base_address, buffer, nsize, bytes_written); - if ret != 0 - { + if ret != 0 { let _r = dinvoke::close_handle(handle); return Err(lc!("[x] Error writing PE headers to the allocated memory.")); } @@ -289,8 +272,7 @@ pub fn map_module_to_memory(module_ptr: *const u8, image_ptr: *mut c_void, pe_in let ret = dinvoke::nt_write_virtual_memory(handle, base_address, buffer, nsize, bytes_written); let _r = dinvoke::close_handle(handle); - if ret != 0 || *bytes_written != nsize - { + if ret != 0 || *bytes_written != nsize { return Err(lc!("[x] Failed to write PE sections to the allocated memory.")) } } @@ -305,18 +287,15 @@ pub fn map_module_to_memory(module_ptr: *const u8, image_ptr: *mut c_void, pe_in /// pointer to the base address where the module is mapped in memory. pub fn relocate_module(pe_info: &PeMetadata, image_ptr: *mut c_void) { - unsafe { - + 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 - { + 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 - { + } 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; } @@ -340,16 +319,12 @@ pub fn relocate_module(pe_info: &PeMetadata, image_ptr: *mut c_void) if reloc_type != 0 { - - if reloc_type == 0x3 - { + 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; let original_ptr = *patch_ptr; let patch = original_ptr + image_delta as i32; *patch_ptr = patch; - } - else - { + } else { let patch_ptr = (module_memory_base as usize + image_base_relocation.VirtualAddress as usize + reloc_patch as usize) as *mut isize; let original_ptr = *patch_ptr; let patch = original_ptr + image_delta as isize; @@ -360,10 +335,7 @@ pub fn relocate_module(pe_info: &PeMetadata, image_ptr: *mut c_void) reloc_table_ptr = (reloc_table_ptr as usize + image_base_relocation.SizeOfBlock as usize) as *mut i32; next_reloc_table_block = *reloc_table_ptr; - } - - } } @@ -377,18 +349,14 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul { let module_memory_base: *mut usize = std::mem::transmute(image_ptr); let image_data_directory; - if pe_info.is_32_bit - { + if pe_info.is_32_bit { image_data_directory = pe_info.opt_header_32.DataDirectory[1]; // ImportTable - } - else - { + } else { image_data_directory = pe_info.opt_header_64.datas_directory[1]; // ImportTable } - if image_data_directory.VirtualAddress == 0 - { - return Ok(()); // No hay import table + if image_data_directory.VirtualAddress == 0 { + return Ok(()); // No import table } let import_table_ptr = (module_memory_base as usize + image_data_directory.VirtualAddress as usize) as *mut usize; @@ -396,8 +364,7 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul let info = os_info::get(); let version = info.version().to_string(); let mut api_set_dict: HashMap = HashMap::new(); - if version >= "10".to_string() - { + if version >= "10".to_string() { api_set_dict = dinvoke::get_api_mapping(); } @@ -413,19 +380,15 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul while c != '\0' { c = *ptr as char; - if c != '\0' - { + if c != '\0' { dll_name.push(c); ptr = ptr.add(1); } } - if dll_name == "" - { + if dll_name == "" { return Ok(()); - } - else - { + } else { let lookup_key = format!("{}{}",&dll_name[..dll_name.len() - 6], ".dll"); if (version >= 10.to_string() && (dll_name.starts_with("api-") || dll_name.starts_with("ext-"))) && api_set_dict.contains_key(&lookup_key) @@ -448,8 +411,7 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul module_handle = dinvoke::load_library_a(&dll_name) as usize; - if module_handle == 0 - { + if module_handle == 0 { return Err(lc!("[x] Unable to find the specified module: {}", dll_name)); } } @@ -465,13 +427,11 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul let image_thunk_data = *image_thunk_data; let ft_itd = (module_memory_base as usize + image_import_descriptor.FirstThunk as usize + i as usize * size_of::() as usize) as *mut i32; - if image_thunk_data.u1.AddressOfData == 0 - { + if image_thunk_data.u1.AddressOfData == 0 { break; } - if image_thunk_data.u1.AddressOfData < 0x80000000 - { + if image_thunk_data.u1.AddressOfData < 0x80000000 { let mut imp_by_name_ptr = (module_memory_base as usize + image_thunk_data.u1.AddressOfData as usize + size_of::() as usize) as *mut u8; let mut import_name: String = "".to_string(); @@ -479,8 +439,7 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul while c != '\0' { c = *imp_by_name_ptr as char; - if c != '\0' - { + if c != '\0' { import_name.push(c); } @@ -489,10 +448,7 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul let func_ptr = dinvoke::get_function_address(module_handle, &import_name); *ft_itd = func_ptr as i32; - - } - else - { + } else { let f_ordinal = (image_thunk_data.u1.AddressOfData & 0xFFFF) as u32; let func_ptr = dinvoke::get_function_address_by_ordinal(module_handle, f_ordinal); let func_ptr = func_ptr as *mut i32; @@ -505,7 +461,6 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul else { let mut i: isize = 0; - loop { let image_thunk_data = (module_memory_base as u64 + image_import_descriptor.Anonymous.OriginalFirstThunk as u64 @@ -515,13 +470,11 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul i as u64 * size_of::() as u64) as *mut isize; - if image_thunk_data.u1.AddressOfData == 0 - { + if image_thunk_data.u1.AddressOfData == 0 { break; } - if image_thunk_data.u1.AddressOfData < 0x8000000000000000 - { + if image_thunk_data.u1.AddressOfData < 0x8000000000000000 { let mut imp_by_name_ptr = (module_memory_base as u64 + image_thunk_data.u1.AddressOfData as u64 + size_of::() as u64) as *mut u8; let mut import_name: String = "".to_string(); @@ -529,8 +482,7 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul while c != '\0' { c = *imp_by_name_ptr as char; - if c != '\0' - { + if c != '\0' { import_name.push(c); } @@ -539,10 +491,7 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul let func_ptr = dinvoke::get_function_address(module_handle, &import_name) as *mut isize; *ft_itd = func_ptr as isize; - } - else - { - + } else { let f_ordinal = (image_thunk_data.u1.AddressOfData & 0xFFFF) as u32; let func_ptr = dinvoke::get_function_address_by_ordinal(module_handle, f_ordinal); *ft_itd = func_ptr as isize; @@ -551,13 +500,11 @@ pub fn rewrite_module_iat(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Resul i = i + 1; } } - } counter = counter + 1; image_import_descriptor_ptr = (import_table_ptr as usize + size_of::() as usize * counter) as *mut IMAGE_IMPORT_DESCRIPTOR; image_import_descriptor = *image_import_descriptor_ptr; - } Ok(()) @@ -573,8 +520,7 @@ fn clean_dos_header (image_ptr: *mut c_void) { let mut base_addr = image_ptr as *mut u8; let pe_header = image_ptr as isize + 0x3C; - while (base_addr as isize) < pe_header - { + while (base_addr as isize) < pe_header { *base_addr = 0; base_addr = base_addr.add(1); } @@ -583,8 +529,7 @@ fn clean_dos_header (image_ptr: *mut c_void) let e_lfanew = *((image_ptr as usize + 0x3C) as *const u32); let pe = image_ptr as isize + e_lfanew as isize; - while (base_addr as isize) < pe - { + while (base_addr as isize) < pe { *base_addr = 0; base_addr = base_addr.add(1); } @@ -604,7 +549,6 @@ pub fn add_runtime_table(pe_info: &PeMetadata, image_ptr: *mut c_void) if s.contains(&lc!(".pdata")) { let entry_count = (section.SizeOfRawData / 12) as i32; // 12 = size_of RUNTIME_FUNCTION - let func: data::RtlAddFunctionTable; let _ret: Option; let k32 = dinvoke::get_module_base_address(&lc!("kernel32.dll")); @@ -613,7 +557,6 @@ pub fn add_runtime_table(pe_info: &PeMetadata, image_ptr: *mut c_void) } } } - } /// Sets correct module section permissions for a manually mapped module. @@ -626,12 +569,9 @@ pub fn set_module_section_permissions(pe_info: &PeMetadata, image_ptr: *mut c_vo { let base_of_code; - if pe_info.is_32_bit - { + if pe_info.is_32_bit { base_of_code = pe_info.opt_header_32.BaseOfCode as usize; - } - else - { + } else { base_of_code = pe_info.opt_header_64.base_of_code as usize; } @@ -651,28 +591,17 @@ pub fn set_module_section_permissions(pe_info: &PeMetadata, image_ptr: *mut c_vo let is_execute = (section.Characteristics.0 & SECTION_MEM_EXECUTE) != 0; let new_protect: u32; - if is_read & !is_write & !is_execute - { + if is_read & !is_write & !is_execute { new_protect = PAGE_READONLY; - } - else if is_read & is_write & !is_execute - { + } else if is_read & is_write & !is_execute { new_protect = PAGE_READWRITE; - } - else if is_read & is_write & is_execute - { + } else if is_read & is_write & is_execute { new_protect = PAGE_EXECUTE_READWRITE; - } - else if is_read & !is_write & is_execute - { + } else if is_read & !is_write & is_execute { new_protect = PAGE_EXECUTE_READ; - } - else if !is_read & !is_write & is_execute - { + } else if !is_read & !is_write & is_execute { new_protect = PAGE_EXECUTE; - } - else - { + } else { return Err(lc!("[x] Unknown section permission.")); } @@ -682,11 +611,8 @@ pub fn set_module_section_permissions(pe_info: &PeMetadata, image_ptr: *mut c_vo let o = u32::default(); let old_protection: *mut u32 = std::mem::transmute(&o); let ret = dinvoke::nt_protect_virtual_memory(handle, base_address, size, new_protect, old_protection); - let _r = dinvoke::close_handle(handle); - - if ret != 0 - { + if ret != 0 { return Err(lc!("[x] Error changing section permission.")); } @@ -705,12 +631,9 @@ pub fn run_tls_callbacks(pe_info: &PeMetadata, image_ptr: *mut c_void) unsafe { let entry_point; - if pe_info.is_32_bit - { + if pe_info.is_32_bit { entry_point = image_ptr as isize + pe_info.opt_header_32.AddressOfEntryPoint as isize; - } - else - { + } else { entry_point = image_ptr as isize + pe_info.opt_header_64.address_of_entry_point as isize; } @@ -721,8 +644,7 @@ pub fn run_tls_callbacks(pe_info: &PeMetadata, image_ptr: *mut c_void) 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 - { + 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); @@ -739,8 +661,7 @@ pub fn map_to_section(module_path: &str) -> Result<(PeManualMap,HANDLE),String> { unsafe { - if !Path::new(&module_path).is_file() - { + if !Path::new(&module_path).is_file() { return Err(lc!("[x] Filepath not found.")); } @@ -755,7 +676,7 @@ pub fn map_to_section(module_path: &str) -> Result<(PeManualMap,HANDLE),String> let mut object_attributes = OBJECT_ATTRIBUTES::default(); object_attributes.Length = size_of::() as u32; object_attributes.ObjectName = object_name; - object_attributes.Attributes = 0x40; // Case Insensitive + object_attributes.Attributes = OBJECT_ATTRIBUTE_FLAGS(0x40); // Case Insensitive let io: Vec = vec![0; size_of::()]; let io: *mut IO_STATUS_BLOCK = std::mem::transmute(io.as_ptr()); @@ -771,8 +692,7 @@ pub fn map_to_section(module_path: &str) -> Result<(PeManualMap,HANDLE),String> FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, ); - if r != 0 - { + if r != 0 { return Err(lc!("[x] Error opening file.")); } @@ -790,8 +710,7 @@ pub fn map_to_section(module_path: &str) -> Result<(PeManualMap,HANDLE),String> *hfile ); - if r != 0 - { + if r != 0 { return Err(lc!("[x] Error creating file section in memory.")); } @@ -803,7 +722,7 @@ pub fn map_to_section(module_path: &str) -> Result<(PeManualMap,HANDLE),String> let view_size: *mut usize = std::mem::transmute(&v); let r = dinvoke::nt_map_view_of_section( *hsection, - HANDLE { 0: -1}, + HANDLE { 0: -1 as _}, base_address, 0, 0, @@ -814,18 +733,15 @@ pub fn map_to_section(module_path: &str) -> Result<(PeManualMap,HANDLE),String> PAGE_READWRITE ); - if r != 0 - { + if r != 0 { return Err(lc!("[x] Error mapping file section.")); } let base_address: *const u8 = std::mem::transmute(*base_address); let sec_object: PeManualMap = PeManualMap { pe_info : get_pe_metadata(base_address, false).unwrap(), base_address : base_address as usize, decoy_module: module_path}; - let _r = dinvoke::close_handle(*hfile); - Ok((sec_object, *hsection)) } } @@ -833,16 +749,349 @@ pub fn map_to_section(module_path: &str) -> Result<(PeManualMap,HANDLE),String> pub fn map_to_allocated_memory (module_ptr: *const u8, image_ptr: *mut c_void, pe_info: &PeMetadata) -> Result<(), String> { map_module_to_memory(module_ptr, image_ptr, &pe_info)?; - relocate_module(&pe_info, image_ptr); - rewrite_module_iat(&pe_info, image_ptr)?; - clean_dos_header(image_ptr); - set_module_section_permissions(&pe_info, image_ptr)?; - add_runtime_table(&pe_info, image_ptr); Ok(()) +} + +/// Manually map a file to a memory section, performing IAT fixing and relocations, leaving the module ready to be executed. +/// This tries to replicate LoadLibrary but allowing you to use a file handle instead of a file name or path. +pub fn map_file_to_section_from_handle(file_handle: HANDLE) -> Result +{ + unsafe + { + let max_size: Vec =vec![0; size_of::()]; + let max_size: *mut LARGE_INTEGER = std::mem::transmute(max_size.as_ptr()); + let section_handle = HANDLE::default(); + let section_handle_ptr: *mut HANDLE = std::mem::transmute(§ion_handle); + let ret = dinvoke::nt_create_section( + section_handle_ptr, + SECTION_ALL_ACCESS, + ptr::null_mut(), + max_size, + PAGE_READONLY, + SEC_IMAGE, + file_handle + ); + + if ret != 0 { + return Err(lc!("[x] Error creating file section in memory.")); + } + + let offset: Vec =vec![0; size_of::()]; + let offset: *mut LARGE_INTEGER = std::mem::transmute(offset.as_ptr()); + let baddr = usize::default(); + let base_address: *mut PVOID = std::mem::transmute(&baddr); + let size = usize::default(); + let view_size: *mut usize = std::mem::transmute(&size); + let ret = dinvoke::nt_map_view_of_section( + *section_handle_ptr, + HANDLE { 0: -1 as _}, + base_address, + 0, + 0, + offset, + view_size, + 0x2, + 0x0, + PAGE_READWRITE + ); + + if ret != 0 { + return Err(lc!("[x] Error mapping file section.")); + } + + let base_address: *const u8 = std::mem::transmute(*base_address); + let return_data: PeSectionMap = PeSectionMap { pe_info : get_pe_metadata(base_address, false).unwrap(), + base_address : base_address as usize, section_handle: (*section_handle_ptr).0 as usize}; + + let mut all_addresses = get_iat_addresses(&return_data.pe_info, base_address as _); + let reloc_addreses = get_reloc_addresses(&return_data.pe_info, base_address as _); + all_addresses.extend(reloc_addreses); + if page_align_sort_dedup(&mut all_addresses) == 0 { + dinvoke::nt_unmap_view_of_section(*section_handle_ptr, base_address as _); + dinvoke::close_handle(*section_handle_ptr); + return Err(lc!("[x] Error detected: page size == 0.")); + } + + let non_writable_regions = collect_non_writable_regions(&all_addresses); + let ret = protect_regions_for_patching(non_writable_regions); + if ret.is_err() + { + dinvoke::nt_unmap_view_of_section(*section_handle_ptr, base_address as _); + dinvoke::close_handle(*section_handle_ptr); + let error = format!("{}{:x}.", lc!("[x] Error changing memory protection. NTSTATUS: "), ret.err().unwrap()); + return Err(error); + } + + rewrite_module_iat(&return_data.pe_info, base_address as _)?; + relocate_module(&return_data.pe_info, base_address as _); + let ret = set_module_section_permissions(&return_data.pe_info, base_address as _); + if ret.is_err() { + dinvoke::nt_unmap_view_of_section(*section_handle_ptr, base_address as _); + dinvoke::close_handle(*section_handle_ptr); + let error = format!("{}{}.", lc!("[x] Call to 'set_module_section_permissions' failed. Error: "), ret.err().unwrap()); + return Err(error); + } + + add_runtime_table(&return_data.pe_info, base_address as _); + + Ok(return_data) + } +} + +fn get_iat_addresses(pe_info: &PeMetadata, image_ptr: *mut c_void) ->Vec +{ + unsafe + { + let mut addresses = vec![]; + let module_memory_base: *mut usize = std::mem::transmute(image_ptr); + let image_data_directory; + if pe_info.is_32_bit { + image_data_directory = pe_info.opt_header_32.DataDirectory[1]; // ImportTable + } else { + image_data_directory = pe_info.opt_header_64.datas_directory[1]; // ImportTable + } + + if image_data_directory.VirtualAddress == 0 { + return addresses; // No import table + } + + let import_table_ptr = (module_memory_base as usize + image_data_directory.VirtualAddress as usize) as *mut usize; + + let mut counter = 0; + let mut image_import_descriptor_ptr = (import_table_ptr as usize + size_of::() as usize * counter) as *mut IMAGE_IMPORT_DESCRIPTOR; + let mut image_import_descriptor = *image_import_descriptor_ptr; + + while image_import_descriptor.Name != 0 + { + let mut dll_name = "".to_string(); + let mut c: char = ' '; + let mut ptr = (module_memory_base as usize + image_import_descriptor.Name as usize) as *mut u8; + while c != '\0' + { + c = *ptr as char; + if c != '\0' { + dll_name.push(c); + ptr = ptr.add(1); + } + } + + if dll_name == "" { + return addresses; + } else { + if pe_info.is_32_bit { + let mut i: isize = 0; + + loop + { + let image_thunk_data = (module_memory_base as usize + image_import_descriptor.Anonymous.OriginalFirstThunk as usize + + i as usize * size_of::() as usize) as *mut IMAGE_THUNK_DATA32; + let image_thunk_data = *image_thunk_data; + let ft_itd = (module_memory_base as usize + image_import_descriptor.FirstThunk as usize + + i as usize * size_of::() as usize) as *mut i32; + addresses.push(ft_itd as usize); + + if image_thunk_data.u1.AddressOfData == 0 { + break; + } + + i = i + 1; + } + } else { + let mut i: isize = 0; + + loop + { + let image_thunk_data = (module_memory_base as u64 + image_import_descriptor.Anonymous.OriginalFirstThunk as u64 + + i as u64 * size_of::() as u64) as *mut IMAGE_THUNK_DATA64; + let image_thunk_data = *image_thunk_data; + let ft_itd = (module_memory_base as u64 + image_import_descriptor.FirstThunk as u64 + + i as u64 * size_of::() as u64) as *mut isize; + addresses.push(ft_itd as usize); + + if image_thunk_data.u1.AddressOfData == 0 { + break; + } + + i = i + 1; + } + } + + } + + counter = counter + 1; + image_import_descriptor_ptr = (import_table_ptr as usize + size_of::() as usize * counter) as *mut IMAGE_IMPORT_DESCRIPTOR; + image_import_descriptor = *image_import_descriptor_ptr; + } + + addresses + } + +} + +fn get_reloc_addresses(pe_info: &PeMetadata, image_ptr: *mut c_void) -> Vec +{ + unsafe + { + let mut addresses = vec![]; + let module_memory_base: *mut usize = std::mem::transmute(image_ptr); + let image_data_directory; + if pe_info.is_32_bit { + image_data_directory = pe_info.opt_header_32.DataDirectory[5]; // BaseRelocationTable + } else { + image_data_directory = pe_info.opt_header_64.datas_directory[5]; // BaseRelocationTable + } + + 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::() as isize) / 2; + + for i in 0..reloc_count + { + let reloc_entry_ptr = (reloc_table_ptr as usize + size_of::() 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 { + let patch_ptr = (module_memory_base as usize + image_base_relocation.VirtualAddress as usize + reloc_patch as usize) as usize; + addresses.push(patch_ptr); + } + } + + reloc_table_ptr = (reloc_table_ptr as usize + image_base_relocation.SizeOfBlock as usize) as *mut i32; + next_reloc_table_block = *reloc_table_ptr; + + } + + addresses + } +} + +fn page_align_sort_dedup(addrs: &mut Vec) -> usize +{ + let mut si: SYSTEM_INFO = unsafe { std::mem::zeroed() }; + dinvoke::get_system_info(&mut si); + + let page_size = si.dwPageSize as usize; + if page_size == 0 { + return 0; + } + + for a in addrs.iter_mut() { + *a = (*a / page_size) * page_size; + } + + // sort + dedup + addrs.sort_unstable(); + addrs.dedup(); + + page_size +} + +#[inline] +fn protection_allows_write(protection: u32) -> bool { + (protection & PAGE_READWRITE) != 0 + || (protection & PAGE_WRITECOPY) != 0 + || (protection & PAGE_EXECUTE_READWRITE) != 0 + || (protection & PAGE_EXECUTE_WRITECOPY) != 0 +} + +// Returns non writable regions so the memory protection can be changed before IAT fixing + relocations +fn collect_non_writable_regions(pages: &[usize]) -> Vec +{ + let mut out: Vec = Vec::new(); + + // Parameter 'pages' should be already sorted + let mut last_region_base: usize = 0; + + for &page_base in pages + { + let mut mbi: MEMORY_BASIC_INFORMATION = unsafe { std::mem::zeroed() }; + + let ret = dinvoke::virtual_query(page_base as _, &mut mbi, size_of::()); + if ret == 0 { + continue; + } + + // Only commited memory + if mbi.State.0 != MEM_COMMIT { + continue; + } + + // We don't touch these pages + if (mbi.Protect.0 & PAGE_NOACCESS) != 0 || (mbi.Protect.0 & PAGE_GUARD) != 0 { + continue; + } + + let region_base = mbi.BaseAddress as usize; + let region_size = mbi.RegionSize; + let region_protect = mbi.Protect; + + // We avoid duplicated info + if region_base == last_region_base { + continue; + } + + // Already writable regions are ignored + if protection_allows_write(region_protect.0) { + last_region_base = region_base; + continue; + } + + out.push(RegionInfo { + base_address: region_base, + region_size: region_size, + memory_protection: region_protect.0, + }); + + last_region_base = region_base; + } + + out +} + +#[inline] +fn is_executable_protect(protection: u32) -> bool { + (protection & 0xF0) != 0 +} + +fn protect_regions_for_patching(regions: Vec) -> Result<(), i32> +{ + unsafe + { + for r in regions.iter() + { + let new_protect = if is_executable_protect(r.memory_protection) { + PAGE_EXECUTE_READWRITE + } else { + PAGE_READWRITE + }; + + let handle = GetCurrentProcess(); + let base_address: *mut PVOID = std::mem::transmute(&r.base_address); + let s: UnsafeCell = isize::default().into(); + let size: *mut usize = std::mem::transmute(s.get()); + *size = r.region_size; + let o = u32::default(); + let old_protection: *mut u32 = std::mem::transmute(&o); + let ret = dinvoke::nt_protect_virtual_memory(handle, base_address, size, new_protect, old_protection); + if ret != 0 { + return Err(ret); + } + } + + Ok(()) + } } \ No newline at end of file diff --git a/overload/Cargo.toml b/overload/Cargo.toml index e7a0cfb..8c2605d 100644 --- a/overload/Cargo.toml +++ b/overload/Cargo.toml @@ -16,7 +16,7 @@ winproc = "0.6.4" nanorand = "0.7.0" [dependencies.windows] -version = "0.51" +version = "0.62" features = [ "Win32_Foundation" ] diff --git a/overload/src/lib.rs b/overload/src/lib.rs index df3ff70..ddff847 100644 --- a/overload/src/lib.rs +++ b/overload/src/lib.rs @@ -28,10 +28,8 @@ fn find_suitable_module(function_size: u32) -> usize for section in pe_metadata.sections { let s = std::str::from_utf8(§ion.Name).unwrap(); - if s.contains(".text") - { - unsafe - { + if s.contains(".text") { + unsafe { if section.Misc.VirtualSize > function_size { suitable_text_sections.push(module_base_address); } @@ -90,8 +88,7 @@ pub fn find_decoy_module (min_size: i64) -> String let p = entry.unwrap(); let path = p.path(); - if !path.is_dir() && path.to_str().unwrap().ends_with(".dll") - { + if !path.is_dir() && path.to_str().unwrap().ends_with(".dll") { let slice:Vec = path.to_str().unwrap().to_string().split("\\").map(str::to_string).collect(); files.push(slice[slice.len() - 1].to_string()); } @@ -103,8 +100,7 @@ pub fn find_decoy_module (min_size: i64) -> String for m in modules { let mut c = 0; - for f in &files - { + for f in &files { if f.to_lowercase() == m.name().unwrap().to_lowercase() { remove.push(c); } @@ -127,8 +123,7 @@ pub fn find_decoy_module (min_size: i64) -> String let size = fs::metadata(&path).unwrap().len() as i64; if size > (min_size * 2) { return path; - } - else { + } else { files.remove(r); } } @@ -155,18 +150,15 @@ pub fn find_decoy_module (min_size: i64) -> String /// ``` pub fn read_and_overload(payload_path: &str, decoy_module_path: &str) -> Result<(PeMetadata,usize), String> { - if !Path::new(payload_path).is_file() { return Err(lc!("[x] Payload file not found.")); } - 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 - { + unsafe { for i in 0..file_content.len() { *(file_content_ptr.add(i)) = 0u8; } @@ -198,8 +190,7 @@ pub fn read_and_overload(payload_path: &str, decoy_module_path: &str) -> Result< pub fn overload_module (file_content: &Vec, decoy_module_path: &str) -> Result<(PeMetadata,usize), String> { let mut decoy_module_path = decoy_module_path.to_string(); - if decoy_module_path != "" - { + if decoy_module_path != "" { if !Path::new(&decoy_module_path).is_file() { return Err(lc!("[x] Decoy file not found.")); } @@ -208,9 +199,7 @@ pub fn overload_module (file_content: &Vec, decoy_module_path: &str) -> Resu if decoy_content.len() < file_content.len() { return Err(lc!("[x] Decoy module is too small to host the payload.")); } - } - else - { + } else { decoy_module_path = find_decoy_module(file_content.len() as i64); if decoy_module_path == "" { return Err(lc!("[x] Failed to find suitable decoy module.")); @@ -218,11 +207,10 @@ pub fn overload_module (file_content: &Vec, decoy_module_path: &str) -> Resu } - let decoy_metadata: (PeManualMap, HANDLE) = manualmap::map_to_section(&decoy_module_path)?; + let decoy_metadata: (PeManualMap, HANDLE) = manualmap::map_to_section(&decoy_module_path)?; + let result: (PeMetadata,usize) = overload_to_section(file_content, decoy_metadata.0)?; - let result: (PeMetadata,usize) = overload_to_section(file_content, decoy_metadata.0)?; - - Ok(result) + Ok(result) } /// Load a payload from memory to an existing memory section. @@ -251,8 +239,7 @@ pub fn overload_to_section (file_content: &Vec, section_metadata: PeManualMa let region_size: usize; if section_metadata.pe_info.is_32_bit { region_size = section_metadata.pe_info.opt_header_32.SizeOfImage as usize; - } - else { + } else { region_size = section_metadata.pe_info.opt_header_64.size_of_image as usize; } @@ -260,7 +247,7 @@ pub fn overload_to_section (file_content: &Vec, section_metadata: PeManualMa let base_address: *mut PVOID = std::mem::transmute(§ion_metadata.base_address); let old_protection: *mut u32 = std::mem::transmute(&u32::default()); let r = dinvoke::nt_protect_virtual_memory( - HANDLE { 0: -1}, + HANDLE { 0: -1 as _}, base_address, size, PAGE_READWRITE, @@ -340,8 +327,7 @@ pub fn managed_overload_module (file_content: Vec, decoy_module_path: &str) let mut decoy_module_path = decoy_module_path.to_string(); let decoy_content; - if decoy_module_path != "" - { + if decoy_module_path != "" { if !Path::new(&decoy_module_path).is_file() { return Err(lc!("[x] Decoy file not found.")); } @@ -350,9 +336,7 @@ pub fn managed_overload_module (file_content: Vec, decoy_module_path: &str) if decoy_content.len() < file_content.len() { return Err(lc!("[x] Decoy module is too small to host the payload.")); } - } - else - { + } else { decoy_module_path = find_decoy_module(file_content.len() as i64); if decoy_module_path == "" { return Err(lc!("[x] Failed to find suitable decoy module.")); @@ -360,11 +344,10 @@ pub fn managed_overload_module (file_content: Vec, decoy_module_path: &str) decoy_content = fs::read(&decoy_module_path).expect(&lc!("[x] Error opening the decoy file.")); } - let decoy_metadata: (PeManualMap, HANDLE) = manualmap::map_to_section(&decoy_module_path)?; + let decoy_metadata: (PeManualMap, HANDLE) = manualmap::map_to_section(&decoy_module_path)?; + let result: (PeMetadata,usize) = overload_to_section(&file_content, decoy_metadata.0)?; - let result: (PeMetadata,usize) = overload_to_section(&file_content, decoy_metadata.0)?; - - Ok((decoy_content, result.1)) + Ok((decoy_content, result.1)) } /// Stomp a shellcode on a loaded module. @@ -439,26 +422,22 @@ pub fn managed_module_stomping(payload_content: &Vec, mut stomp_address: usi { unsafe { - let process_handle = HANDLE(-1); + let process_handle = HANDLE(-1 as _); let size = payload_content.len() as u32; - if size == 0 - { + if size == 0 { return Err(lc!("[x] Invalid payload.")); } if stomp_address == 0 { - if module_base_address != 0 - { + if module_base_address != 0 { let offset = is_suitable(size, module_base_address); if offset != 0 { stomp_address = module_base_address + offset as usize; - } - else { + } else { return Err(lc!("[x] The selected module is not valid to stomp the payload.")); } - } - else { + } else { stomp_address = find_suitable_module(size); } @@ -563,14 +542,10 @@ pub fn generate_template(input_file: &str, output_directory: &str) -> Result<(), let mapped_dll_metadata = manualmap::get_pe_metadata(mapped_dll as _, false).unwrap(); let entry_point; - if mapped_dll_metadata.is_32_bit - { + if mapped_dll_metadata.is_32_bit { entry_point = mapped_dll + mapped_dll_metadata.opt_header_32.AddressOfEntryPoint as usize; - } - else - { + } else { entry_point = mapped_dll + mapped_dll_metadata.opt_header_64.address_of_entry_point as usize; - } let mut tls_callback_vas: Vec = vec![]; @@ -580,8 +555,7 @@ pub fn generate_template(input_file: &str, output_directory: &str) -> Result<(), 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 - { + 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); } @@ -597,8 +571,7 @@ pub fn generate_template(input_file: &str, output_directory: &str) -> Result<(), 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 - { + 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); } @@ -643,8 +616,7 @@ pub fn generate_template(input_file: &str, output_directory: &str) -> Result<(), *entrypoint_addr = dll_main_template; let callback_template = 0xc3 as u8; // Just a ret; instruction to replace Tls Callbacks - for tls_callbacks_rva in tls_callbacks_rvas - { + 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; } @@ -720,22 +692,20 @@ pub fn template_stomping(template_path: &str, payload_content: &mut Vec) -> 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); + let ret = dinvoke::nt_protect_virtual_memory(HANDLE(-1 as _), text_addr_ptr, size, new_protect, old_protection); - if ret != 0 - { + if ret != 0 { let _ = dinvoke::free_library(loaded_dll as isize); return Err(lc!("[x] An error ocurred. Dll released.")); } - let handle = HANDLE(-1); + let handle = HANDLE(-1 as _); 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 - { + if ret != 0 { let _ = dinvoke::free_library(loaded_dll as isize); return Err(lc!("[x] An error ocurred. Dll released.")); } @@ -750,9 +720,8 @@ pub fn template_stomping(template_path: &str, payload_content: &mut Vec) -> 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 ret = dinvoke::nt_protect_virtual_memory(HANDLE(-1 as _), text_addr_ptr, size, new_protect, old_protection); + if ret != 0 { let _ = dinvoke::free_library(loaded_dll as isize); return Err(lc!("[x] An error ocurred. Dll released.")); } @@ -762,7 +731,6 @@ pub fn template_stomping(template_path: &str, payload_content: &mut Vec) -> } Ok((PeMetadata::default(),0)) - } } @@ -777,13 +745,10 @@ fn relocate_text_section(pe_info: &PeMetadata, image_ptr: *mut c_void, start_add 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 - { + 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 - { + } 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; } @@ -807,23 +772,16 @@ fn relocate_text_section(pe_info: &PeMetadata, image_ptr: *mut c_void, start_add if reloc_type != 0 { - - if reloc_type == 0x3 - { + 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) - { + 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 - { + } 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) - { + 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; @@ -834,7 +792,6 @@ fn relocate_text_section(pe_info: &PeMetadata, image_ptr: *mut c_void, start_add reloc_table_ptr = (reloc_table_ptr as usize + image_base_relocation.SizeOfBlock as usize) as *mut i32; next_reloc_table_block = *reloc_table_ptr; - } } } \ No newline at end of file diff --git a/utils/Cargo.toml b/utils/Cargo.toml new file mode 100644 index 0000000..6199a61 --- /dev/null +++ b/utils/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "utils" +version = "0.1.0" +edition = "2021" + +[dependencies] +dinvoke = { path = "../dinvoke" } +data = { path = "../data" } +manualmap = { path = "../manualmap" } +litcrypt2 = "=0.1.2" + +[dependencies.windows] +version = "0.62" +features = [ + "Win32_Foundation", + "Win32_Storage", + "Win32_Storage_FileSystem", + "Win32_Security" +] \ No newline at end of file diff --git a/utils/src/lib.rs b/utils/src/lib.rs new file mode 100644 index 0000000..4f25fc9 --- /dev/null +++ b/utils/src/lib.rs @@ -0,0 +1,77 @@ +#[macro_use] +extern crate litcrypt2; +use_litcrypt!(); + +use std::{ffi::OsStr, os::windows::ffi::OsStrExt, slice}; +use windows::{Win32::Foundation::UNICODE_STRING, core::PWSTR}; + +pub fn str_to_wide_string(s: &str) -> Vec +{ + let mut v: Vec = s.encode_utf16().collect(); + v.push(0); + v +} + +pub fn osstr_to_wide_string(s: &OsStr) -> Vec +{ + let mut v: Vec = s.encode_wide().collect(); + v.push(0); + v +} + +pub fn pwstr_to_string(p: *const u16) -> String +{ + if p.is_null() { + return String::new(); + } + + unsafe + { + let mut len = 0usize; + while *p.add(len) != 0 { + len += 1; + } + + let wide: &[u16] = slice::from_raw_parts(p, len); + String::from_utf16_lossy(wide) + } +} + +pub fn str_to_unicode_string(s: &str) -> Result +{ + let mut buf: Vec = s.encode_utf16().collect(); + buf.push(0); + + let len_bytes = (buf.len() - 1) * 2; + let max_bytes = buf.len() * 2; + + if len_bytes > u16::MAX as usize || max_bytes > u16::MAX as usize { + return Err(""); + } + + let us = UNICODE_STRING { + Length: len_bytes as u16, + MaximumLength: max_bytes as u16, + Buffer: PWSTR(buf.as_mut_ptr()), + }; + + Ok(us) +} + +pub fn get_module_entry_point_addr(module_base_address: usize) -> Result +{ + let pe_info = manualmap::get_pe_metadata(module_base_address as _, false); + if pe_info.is_err() { + return Err(lc!("[x] Could not obtain the PE's metadata.")); + } + + let pe_info = pe_info.unwrap(); + let entry_point; + if pe_info.is_32_bit { + entry_point = module_base_address + pe_info.opt_header_32.AddressOfEntryPoint as usize; + } else { + entry_point = module_base_address + pe_info.opt_header_64.address_of_entry_point as usize; + } + + Ok(entry_point) +} \ No newline at end of file