dyncvoke 0.1.0

Dynamically invoke unmanaged Windows APIs via PEB walking, indirect syscalls, and call-stack spoofing
# Dyncvoke


Rust crate for indirect syscalls, dynamic API resolution, and call stack spoofing on Windows. Call NT functions without putting their names in your import table and without going through inline hooks on ntdll.

## Features


- ✅ Indirect syscalls via Tartarus Gate (Hell's, Halo's, Tartarus prologues).
- ✅ Call stack spoofing in `Synthetic` and `Desync` modes.
- ✅ Uniform macros: `syscall!`, `do_syscall!`, `spoof!`, `spoof_syscall!`.
- ✅ Manual PE mapping, section overloading, module fluctuation, syscall parameter spoofing.
-`#![no_std]` (with `alloc`), MSVC and GNU toolchains, x86_64.

## Layout


```
dyncvoke_core        sys module, dynamic invocation, nt_* wrappers
dyncvoke_core::sys   Tartarus Gate and the variadic do_syscall gateway
manualmap            PE mapping with relocations and IAT rewriting
overload             section overloading, module stomping, template stomping
dmanager             module fluctuation manager
spoof                call stack spoofing, synthetic and desync modes
data                 shared types and FFI signatures
```

## Adding it


```toml
[dependencies]
dyncvoke = "0.1"
```

Windows x86_64 only (`x86_64-pc-windows-msvc` or `x86_64-pc-windows-gnu`). GNU spoof builds need NASM on `PATH`. Full API docs: [docs.rs/dyncvoke](https://docs.rs/dyncvoke).

```toml
dyncvoke = { version = "0.1", features = ["full"] }
```

Git:

```toml
[dependencies]
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke.git" }
```

Feature flags:

- `syscall` (default). Indirect syscall path.
- `manualmap`. PE manual mapping. Implies `syscall`.
- `overload`. Section overloading and module stomping. Implies `manualmap`.
- `dmanager`. Module fluctuation manager. Implies `overload`.
- `spoof`. Call stack spoofing, synthetic mode.
- `spoof-desync`. Same as `spoof` but flips desync mode on.
- `full`. Everything above.

## Usage


All four call macros (`syscall!`, `do_syscall!`, `spoof!`, `spoof_syscall!`) take the same shape. Every argument is cast `as usize` and transmuted to `*mut c_void` inside the macro. Return type is `Result<*mut c_void, _>` (or `*mut c_void` for `do_syscall!`). Recover NTSTATUS with `.unwrap() as i32`.

### Spoofed indirect syscall


```rust
use spoof::spoof_syscall;
use core::ffi::c_void;
use core::ptr::null_mut;

let mut addr: *mut c_void = null_mut();
let mut size: usize = 1 << 12;

let status = spoof_syscall!(
    "NtAllocateVirtualMemory",
    -1isize,
    &mut addr as *mut _,
    0usize,
    &mut size as *mut _,
    0x3000u32,
    0x04u32
).unwrap() as i32;
```

### Spoofed function call


```rust
use dyncvoke::dyncvoke_core::{get_module_base_address, get_function_address};
use spoof::spoof;

let kernel32 = get_module_base_address("kernel32.dll");
let win_exec = get_function_address(kernel32, "WinExec");

let cmd = c"calc.exe";
let _ = unsafe { spoof!(win_exec, cmd.as_ptr(), 1u32) };
```

### Indirect syscall without stack spoofing


```rust
use dyncvoke::dyncvoke_core::syscall;
use core::ffi::c_void;
use core::ptr::null_mut;

let mut p_tmp_address: *mut c_void = null_mut();
let mut s_chunk: usize = 0x1000;
let mut old_prot: u32 = 0;

let status = syscall!(
    "NtProtectVirtualMemory",
    -1isize as *mut c_void,
    &mut p_tmp_address as *mut *mut c_void as *mut c_void,
    &mut s_chunk as *mut usize as *mut c_void,
    0x20u32 as *mut c_void,
    &mut old_prot as *mut u32 as *mut c_void,
    null_mut::<c_void>(),
    null_mut::<c_void>(),
    null_mut::<c_void>(),
    null_mut::<c_void>(),
    null_mut::<c_void>(),
    null_mut::<c_void>(),
)
.ok()
.unwrap() as i32;
```

### Cached SSN dispatch


```rust
use dyncvoke::dyncvoke_core::{do_syscall, resolve_syscall};

let (ssn, addr) = resolve_syscall("NtClose").unwrap();
let status = do_syscall!(ssn, addr, handle) as i32;
```

### Manual mapping


```rust
use dyncvoke::manualmap;

let (_pe_info, base) = manualmap::read_and_map_module(
    r"C:\Windows\System32\ntdll.dll",
    true,   // scrub DOS magic
    false   // skip TLS callbacks
).unwrap();
```

### Section overloading


```rust
use dyncvoke::overload;

let payload = your_download_function();
let result = overload::overload_module(&payload, "").unwrap();
```

### Module fluctuation


```rust
use dyncvoke::{overload, dmanager::Manager};

let mut manager = Manager::new();
let m = overload::managed_read_and_overload(
    r"c:\windows\system32\payload.dll",
    r"c:\windows\system32\cdp.dll"
).unwrap();

manager.new_module(m.1, m.0.0, m.0.1).unwrap();
manager.map_module(m.1).unwrap();
// ... call into the payload ...
manager.hide_module(m.1).unwrap();
```

### Syscall parameter spoofing (hardware breakpoints + VEH)


```rust
use dyncvoke::dyncvoke_core::{
    use_hardware_breakpoints, add_vectored_exception_handler,
    nt_open_process, breakpoint_handler,
};
use dyncvoke::data::{HANDLE, OBJECT_ATTRIBUTES, ClientId};

unsafe {
    use_hardware_breakpoints(true);
    add_vectored_exception_handler(1, breakpoint_handler as usize);

    let mut handle: HANDLE = core::ptr::null_mut();
    let attrs = OBJECT_ATTRIBUTES::default();
    let client_id = ClientId {
        unique_process: target_pid as HANDLE,
        unique_thread: core::ptr::null_mut(),
    };

    let _ = nt_open_process(
        &mut handle,
        0x1F03FF,
        &attrs as *const _ as *mut _,
        &client_id as *const _ as *mut _,
    );

    use_hardware_breakpoints(false);
}
```

## Credits 


- [ DInvoke_rs ]https://github.com/Kudaes/DInvoke_rs/tree/main
- [ uwd ]https://github.com/joaoviictorti/uwd.git

## Publishing


Inner crates are published as `dyncvoke-data`, `dyncvoke-core`, `dyncvoke-manualmap`, `dyncvoke-overload`, `dyncvoke-dmanager`, and `dyncvoke-spoof`. Publish in that order, then `dyncvoke`. Wait for each crate to hit the index before the next `cargo publish`.

```
cargo publish -p dyncvoke-data
cargo publish -p dyncvoke-core
cargo publish -p dyncvoke-manualmap
cargo publish -p dyncvoke-spoof
cargo publish -p dyncvoke-overload
cargo publish -p dyncvoke-dmanager
cargo publish -p dyncvoke
```

## License


[MIT LICENSE](./LICENSE)