mirror of
https://github.com/Kudaes/DInvoke_rs
synced 2026-06-08 11:32:25 +00:00
New version 0.2.1 released
- Several QoL changes and code improvements - windows-rs crate version upgraded to 0.62 - New Windows API prototypes, structures and constants added to crate data - HWBP logic fixed to solve the error reported on issue #12 - New crate utils with some frequently required functions
This commit is contained in:
@@ -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"
|
||||
@@ -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<i32> = None; //NtQueryInformationProcess returns a NTSTATUS, which is a i32.
|
||||
let ret: Option<i32>; //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
|
||||
|
||||
+2
-1
@@ -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",
|
||||
|
||||
+137
-12
@@ -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<usize,String>;
|
||||
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
|
||||
}
|
||||
+1
-2
@@ -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"
|
||||
]
|
||||
+227
-164
@@ -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<u8>)> = 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<Vec<usize>, u32>
|
||||
let mut mod_handles: Vec<usize> = 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<Vec<usize>, u32>
|
||||
mod_handles.resize(needed as usize, 0);
|
||||
}
|
||||
|
||||
|
||||
Ok(mod_handles)
|
||||
}
|
||||
}
|
||||
@@ -471,7 +475,7 @@ fn get_module_name(hmodule: usize) -> Result<String,u32>
|
||||
{
|
||||
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<String,u32>
|
||||
{
|
||||
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<String,String> {
|
||||
|
||||
let api_set_map_offset: usize;
|
||||
|
||||
if size_of::<usize>() == 4
|
||||
{
|
||||
if size_of::<usize>() == 4 {
|
||||
api_set_map_offset = 0x38;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
api_set_map_offset = 0x68;
|
||||
}
|
||||
|
||||
@@ -740,8 +728,7 @@ pub fn get_api_mapping() -> HashMap<String,String> {
|
||||
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<String,String> {
|
||||
}
|
||||
}
|
||||
|
||||
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<String,String> {
|
||||
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> = 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<usize>;
|
||||
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<bool>;
|
||||
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<bool>;
|
||||
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<HANDLE>;
|
||||
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<BOOL>;
|
||||
let ret: Option<bool>;
|
||||
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<BOOL>;
|
||||
let ret: Option<bool>;
|
||||
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<usize>;
|
||||
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<i32>;
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ litcrypt2 = "=0.1.2"
|
||||
dinvoke = { path = "../dinvoke" }
|
||||
|
||||
[dependencies.windows]
|
||||
version = "0.51"
|
||||
version = "0.62"
|
||||
features = [
|
||||
"Win32_Foundation"
|
||||
]
|
||||
|
||||
+20
-50
@@ -31,8 +31,7 @@ impl Manager {
|
||||
|
||||
pub fn new_module (&mut self, address: usize, payload: Vec<u8>, decoy: Vec<u8>) -> 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<u8>, decoy: Vec<u8>) -> 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<u8> = 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> = 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> = 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(())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
+397
-148
@@ -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<IMAGE_SECTION_HEADER> = 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::<usize>() == 8)) || (!pe_info.is_32_bit && (size_of::<usize>() == 4))
|
||||
{
|
||||
if (pe_info.is_32_bit && (size_of::<usize>() == 8)) || (!pe_info.is_32_bit && (size_of::<usize>() == 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<String,String> = 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::<u32>() 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::<u16>() 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::<u64>() 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::<u16>() 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::<IMAGE_IMPORT_DESCRIPTOR>() 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<bool>;
|
||||
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::<OBJECT_ATTRIBUTES>() 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<u8> = vec![0; size_of::<IO_STATUS_BLOCK>()];
|
||||
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<PeSectionMap,String>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
let max_size: Vec<u8> =vec![0; size_of::<LARGE_INTEGER>()];
|
||||
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<u8> =vec![0; size_of::<LARGE_INTEGER>()];
|
||||
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<usize>
|
||||
{
|
||||
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::<IMAGE_IMPORT_DESCRIPTOR>() 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::<u32>() 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::<u32>() 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::<u64>() 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::<u64>() 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::<IMAGE_IMPORT_DESCRIPTOR>() 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<usize>
|
||||
{
|
||||
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::<IMAGE_BASE_RELOCATION>() as isize) / 2;
|
||||
|
||||
for i in 0..reloc_count
|
||||
{
|
||||
let reloc_entry_ptr = (reloc_table_ptr as usize + size_of::<IMAGE_BASE_RELOCATION>() as usize + (i * 2) as usize) as *mut u16;
|
||||
let reloc_value = *reloc_entry_ptr;
|
||||
|
||||
let reloc_type = reloc_value >> 12;
|
||||
let reloc_patch = reloc_value & 0xfff;
|
||||
|
||||
if reloc_type != 0 {
|
||||
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>) -> 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<RegionInfo>
|
||||
{
|
||||
let mut out: Vec<RegionInfo> = 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::<MEMORY_BASIC_INFORMATION>());
|
||||
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<RegionInfo>) -> 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> = 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(())
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -16,7 +16,7 @@ winproc = "0.6.4"
|
||||
nanorand = "0.7.0"
|
||||
|
||||
[dependencies.windows]
|
||||
version = "0.51"
|
||||
version = "0.62"
|
||||
features = [
|
||||
"Win32_Foundation"
|
||||
]
|
||||
|
||||
+40
-83
@@ -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<String> = 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<u8>, 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<u8>, 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<u8>, 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<u8>, 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<u8>, 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<u8>, 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<u8>, 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<u8>, 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<u8>, 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<usize> = 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<u8>) ->
|
||||
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<u8>) ->
|
||||
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<u8>) ->
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
]
|
||||
@@ -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<u16>
|
||||
{
|
||||
let mut v: Vec<u16> = s.encode_utf16().collect();
|
||||
v.push(0);
|
||||
v
|
||||
}
|
||||
|
||||
pub fn osstr_to_wide_string(s: &OsStr) -> Vec<u16>
|
||||
{
|
||||
let mut v: Vec<u16> = 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<UNICODE_STRING, &str>
|
||||
{
|
||||
let mut buf: Vec<u16> = 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<usize, String>
|
||||
{
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user