mirror of
https://github.com/Kudaes/DInvoke_rs
synced 2026-06-08 11:32:25 +00:00
Indirect syscalls added + code enhancement
This commit is contained in:
@@ -5,12 +5,12 @@ Rust port of [Dinvoke](https://github.com/TheWover/DInvoke). DInvoke_rs may be u
|
||||
Features:
|
||||
* Dynamically resolve and invoke undocumented Windows APIs from Rust.
|
||||
* Primitives allowing for strategic API hook evasion.
|
||||
* Direct syscall execution from Rust (x64).
|
||||
* Indirect syscalls. **x64 only**
|
||||
* Manually map PE modules from disk or directly from memory.
|
||||
* PE headers parsing.
|
||||
* Map PE modules into sections backed by arbitrary modules on disk.
|
||||
* Module fluctuation to hide mapped PEs (concurrency supported).
|
||||
* Syscall parameters spoofing through exception handlers + hardware breakpoints (x64).
|
||||
* Map PE modules into sections backed by arbitrary modules on disk. **Not Opsec**
|
||||
* Module fluctuation to hide mapped PEs (concurrency supported). **Not Opsec**
|
||||
* Syscall parameters spoofing through exception filter + hardware breakpoints. **x64 only**
|
||||
|
||||
# Credit
|
||||
All the credits go to the creators of the original C# implementation of this tool:
|
||||
@@ -24,11 +24,12 @@ I just created this port as a way to learn Rust myself and with the idea of faci
|
||||
|
||||
Since we are using [LITCRYPT](https://github.com/anvie/litcrypt.rs) plugin to obfuscate string literals, it is required to set up the environment variable LITCRYPT_ENCRYPT_KEY before compiling the code:
|
||||
|
||||
set LITCRYPT_ENCRYPT_KEY="yoursupersecretkey"
|
||||
C:\Users\User\Desktop\DInvoke.rs\dinvoke_rs> set LITCRYPT_ENCRYPT_KEY="yoursupersecretkey"
|
||||
|
||||
After that, you can open the project using your favorite IDE.
|
||||
After that, you can open the project using your favorite IDE and start implementing your own code using all the functionalities offered by DInvoke_rs.
|
||||
|
||||
code .
|
||||
C:\Users\User\Desktop\DInvoke.rs\dinvoke_rs> code .
|
||||
|
||||
# Example 1 - Resolving Exported Unmanaged APIs
|
||||
|
||||
The example below demonstrates how to use DInvoke_rs to dynamically find and call exports of a DLL.
|
||||
@@ -101,8 +102,8 @@ fn main() {
|
||||
|
||||
```
|
||||
|
||||
# Example 3 - Executing direct syscall
|
||||
In the next example, we use DInvoke_rs to execute the syscall that corresponds to function NtQueryInformationProcess. Since the macro dinvoke::execute_syscall!() dynamically allocates and executes the shellcode required to perform the desired syscall, all hooks present in ntdll.dll are bypassed.
|
||||
# Example 3 - Executing indirect syscall
|
||||
In the next example, we use DInvoke_rs to execute the syscall that corresponds to the function NtQueryInformationProcess. Since the macro dinvoke::execute_syscall!() dynamically allocates and executes the shellcode required to perform the desired syscall, all hooks present in ntdll.dll are bypassed. The memory allocated is release once the syscall returns, avoiding the permanent presence of memory pages with execution permission.
|
||||
|
||||
```rust
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "bindings"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[profile.dev.package.bindings]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "data"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[profile.dev.package.data]
|
||||
|
||||
@@ -19,6 +19,7 @@ pub type CreateFileTransactedA = unsafe extern "system" fn (*mut u8, u32, u32, *
|
||||
HANDLE, *const u32, PVOID) -> HANDLE;
|
||||
pub type GetLastError = unsafe extern "system" fn () -> u32;
|
||||
pub type CloseHandle = unsafe extern "system" fn (HANDLE) -> i32;
|
||||
pub type VirtualFree = unsafe extern "system" fn (PVOID, usize, u32) -> bool;
|
||||
pub type LptopLevelExceptionFilter = usize;
|
||||
pub type SetUnhandledExceptionFilter = unsafe extern "system" fn (filter: LptopLevelExceptionFilter) -> LptopLevelExceptionFilter;
|
||||
pub type LdrGetProcedureAddress = unsafe extern "system" fn (PVOID, *mut String, u32, *mut PVOID) -> i32;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "dinvoke"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[profile.dev.package.dinvoke]
|
||||
@@ -14,4 +14,5 @@ data = { path = "../data" }
|
||||
libc = "0.2.101"
|
||||
winproc = "0.6.4"
|
||||
litcrypt = "0.3"
|
||||
winapi = "*"
|
||||
winapi = "*"
|
||||
rand = "*"
|
||||
@@ -18,6 +18,7 @@ use libc::c_void;
|
||||
use litcrypt::lc;
|
||||
use winproc::Process;
|
||||
use winapi::shared::ntdef::LARGE_INTEGER;
|
||||
use rand::Rng;
|
||||
|
||||
static mut HARDWARE_BREAKPOINTS: bool = false;
|
||||
static mut HARDWARE_EXCEPTION_FUNCTION: ExceptionHandleFunction = ExceptionHandleFunction::NtOpenProcess;
|
||||
@@ -588,7 +589,7 @@ pub fn get_ntdll_eat(module_base_address: isize) -> EAT {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_syscall_id(eat:EAT, function_name: &str) -> i32 {
|
||||
pub fn get_syscall_id(eat: &EAT, function_name: &str) -> i32 {
|
||||
|
||||
let mut i = 0;
|
||||
for (_a,b) in eat.iter()
|
||||
@@ -627,14 +628,14 @@ pub fn get_syscall_id(eat:EAT, function_name: &str) -> i32 {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn prepare_syscall(id: u32) -> isize {
|
||||
pub fn prepare_syscall(id: u32, eat: EAT) -> isize {
|
||||
|
||||
let mut sh: [u8;11] =
|
||||
let mut sh: [u8;21] =
|
||||
[
|
||||
0x4C, 0x8B, 0xD1,
|
||||
0xB8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0F, 0x05,
|
||||
0xC3
|
||||
0x49, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x41, 0xFF, 0xE3
|
||||
];
|
||||
|
||||
unsafe
|
||||
@@ -647,6 +648,35 @@ pub fn prepare_syscall(id: u32) -> isize {
|
||||
ptr = ptr.add(1);
|
||||
}
|
||||
|
||||
let max_range = eat.len();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut function = &"".to_string();
|
||||
for s in eat.values()
|
||||
{
|
||||
let index = rng.gen_range(0..max_range);
|
||||
if index < max_range / 10
|
||||
{
|
||||
function = s;
|
||||
}
|
||||
}
|
||||
|
||||
let ntdll = get_module_base_address(&lc!("ntdll.dll"));
|
||||
let mut function_addr = get_function_address(ntdll, function);
|
||||
|
||||
if function_addr == 0
|
||||
{
|
||||
function_addr = get_function_address_by_ordinal(ntdll, id);
|
||||
}
|
||||
|
||||
let syscall_addr = find_syscall_address(function_addr as usize);
|
||||
let mut syscall_ptr: *mut u8 = std::mem::transmute(&syscall_addr);
|
||||
|
||||
for j in 0..8
|
||||
{
|
||||
sh[10 + j] = *syscall_ptr;
|
||||
syscall_ptr = syscall_ptr.add(1);
|
||||
}
|
||||
|
||||
let handle = GetCurrentProcess();
|
||||
let base_address: *mut PVOID = std::mem::transmute(&usize::default());
|
||||
let nsize: usize = sh.len() as usize;
|
||||
@@ -940,6 +970,25 @@ pub fn close_handle(handle: HANDLE) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Dynamically calls VirtualFree.
|
||||
pub fn virtual_free(address: PVOID, size: usize, free_type: u32) -> bool {
|
||||
unsafe
|
||||
{
|
||||
let ret: Option<bool>;
|
||||
let func_ptr: data::VirtualFree;
|
||||
let ntdll = get_module_base_address(&lc!("kernel32.dll"));
|
||||
dynamic_invoke!(ntdll,&lc!("VirtualFree"),func_ptr,ret,address,size,free_type);
|
||||
|
||||
match ret {
|
||||
Some(x) =>
|
||||
{
|
||||
return x;
|
||||
},
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Dynamically calls NtWriteVirtualMemory.
|
||||
///
|
||||
/// It will return the NTSTATUS value returned by the call.
|
||||
@@ -1334,13 +1383,13 @@ macro_rules! dynamic_invoke {
|
||||
};
|
||||
}
|
||||
|
||||
/// Dynamically execute a direct syscall.
|
||||
/// Dynamically execute an indirect syscall.
|
||||
///
|
||||
/// This function expects as parameters the name of the Nt function whose syscall
|
||||
/// wants to be executed, a variable with the function header, an Option variable with the same
|
||||
/// inner type that the original syscall would return and all the parameters expected by the syscall.
|
||||
///
|
||||
/// # Examples - Executing NtQueryInformationProcess with direct syscall
|
||||
/// # Examples - Executing NtQueryInformationProcess with indirect syscall
|
||||
///
|
||||
/// ```ignore
|
||||
/// let function_type:NtQueryInformationProcess;
|
||||
@@ -1369,10 +1418,10 @@ macro_rules! execute_syscall {
|
||||
($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);
|
||||
let id = $crate::get_syscall_id(&eat, $a);
|
||||
if id != -1
|
||||
{
|
||||
let function_ptr = $crate::prepare_syscall(id as u32);
|
||||
let function_ptr = $crate::prepare_syscall(id as u32, eat);
|
||||
if function_ptr != 0
|
||||
{
|
||||
$b = std::mem::transmute(function_ptr);
|
||||
@@ -1382,6 +1431,8 @@ macro_rules! execute_syscall {
|
||||
{
|
||||
$c = None;
|
||||
}
|
||||
let ptr: PVOID = std::mem::transmute(function_ptr);
|
||||
$crate::virtual_free(ptr, 0, 0x00008000);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "manualmap"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[profile.dev.package.manualmap]
|
||||
|
||||
Reference in New Issue
Block a user