├── .gitignore ├── Cargo.toml ├── README.md ├── examples ├── 01.minimal │ ├── Cargo.toml │ ├── driver.rs │ └── exports.def ├── 02.unload │ ├── Cargo.toml │ ├── driver.rs │ └── exports.def ├── 03.urandom │ ├── Cargo.toml │ ├── build.cmd │ ├── builddbg.cmd │ ├── buildrel.cmd │ ├── driver.rs │ └── exports.def ├── README.md ├── build.rs └── screenshots │ ├── winxp-2016-04-11-20-30-41.png │ ├── winxp-2016-04-11-20-32-43.png │ └── winxp-2016-04-11-20-46-14.png └── src ├── alloc ├── Cargo.toml ├── alloc.rs └── pool.rs ├── basedef.rs ├── crt.rs ├── debug.rs ├── device_object.rs ├── dpc.rs ├── driver_object.rs ├── event.rs ├── file_object.rs ├── irp.rs ├── irql.rs ├── lang.rs ├── lib.rs ├── macros.rs ├── object.rs ├── pool.rs ├── rtl.rs ├── shared.rs ├── status.rs ├── string.rs ├── thread.rs └── time.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "winapi-kmd" 3 | version = "0.1.0" 4 | description = "Windows Kernel Mode support library." 5 | keywords = ["windows", "ffi", "drivers", "wdk", "ddk", "Four-F"] 6 | 7 | authors = ["pravic "] 8 | repository = "https://github.com/pravic/winapi-kmd-rs" 9 | documentation = "http://pravic.github.io/winapi-kmd-rs" 10 | readme = "README.md" 11 | license = "MIT" 12 | 13 | [lib] 14 | name = "km" 15 | crate-type = ["rlib"] 16 | 17 | [dependencies] 18 | alloc_system = { path="src/alloc" } 19 | core = { path= "../libcore", version="*" } 20 | collections = { path = "../libcollections" } 21 | 22 | [profile.release] 23 | opt-level = 3 24 | debug = true 25 | rpath = false 26 | lto = true 27 | debug-assertions = false 28 | codegen-units = 4 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Windows Kernel-Mode Drivers written in Rust 2 | 3 | [![Join the chat at https://gitter.im/pravic/winapi-kmd-rs](https://badges.gitter.im/pravic/winapi-kmd-rs.png)](https://gitter.im/pravic/winapi-kmd-rs) 4 | 5 | This library is just a proof-of-concept of the windows kernel-mode drivers, which can be written in Rust programming language. 6 | 7 | It contains the types, constants and bindings for the [Windows Driver Kit](https://en.wikipedia.org/wiki/Windows_Driver_Kit) 8 | with target OS starting from Windows XP (x86/x64). 9 | 10 | 11 | ### Getting started 12 | 13 | To compile you need the following: 14 | 15 | * Nightly Rust with MSVC ABI starting from 2016-04-12 (?), which supports "[is-like-msvc](https://github.com/rust-lang/rust/pull/32823)" target flavor. 16 | * MSVC itself, either VS 2015 or just MSVC Build Tools. 17 | * Rust environment for the Windows drivers: [kmd-env-rs](https://github.com/pravic/kmd-env-rs). 18 | 19 | As workaround you can compile drivers as `#[crate_type="staticlib"]` and link them manually (see *examples/03.urandom/build.cmd*). 20 | 21 | 22 | Setting up: 23 | 24 | ``` 25 | git clone https://github.com/pravic/kmd-env-rs . 26 | git submodule init 27 | git submodule update --recursive 28 | ``` 29 | 30 | [Set](https://github.com/rust-lang-nursery/multirust-rs#directory-overrides) the nightly-msvc Rust toolchain for this repository: 31 | 32 | `rustup override add nightly-i686-msvc` 33 | 34 | Try to compile example: 35 | 36 | ``` 37 | cd km\examples\01.minimal\ 38 | cargo build --release 39 | ``` 40 | 41 | By default, it compiles to x86 mode. 42 | If you need x64, either change `kmd-env-rs/.cargo/config` as following: 43 | 44 | ``` 45 | [build] 46 | target = "x86_64-sys-windows-msvc" 47 | ... 48 | ``` 49 | 50 | or use [RUST_TARGET_PATH](https://github.com/rust-lang/rfcs/blob/master/text/0131-target-specification.md): 51 | 52 | ``` 53 | set RUST_TARGET_PATH=C:/path/to/kmd-env-rs/.cargo` 54 | cargo build --release --target i686-sys-windows-msvc 55 | cargo build --release --target x86_64-sys-windows-msvc 56 | ``` 57 | 58 | 59 | 60 | ### Examples 61 | 62 | See [examples](https://github.com/pravic/winapi-kmd-rs/tree/master/examples) folder with a driver samples and screenshots. 63 | 64 | 65 | ### [Reference documentation](http://pravic.github.io/winapi-kmd-rs/). 66 | 67 | 68 | #### Acknowledges 69 | 70 | In memory of [Four-F](https://web.archive.org/web/20130530073702/http://www.freewebs.com/four-f/) - the author of tutorials about kernel mode drivers 71 | development in assembly language (2002-2005). 72 | -------------------------------------------------------------------------------- /examples/01.minimal/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust.drv.examples.minimal" 3 | description = "Minimal Windows kernel driver sample." 4 | version = "0.1.0" 5 | authors = ["pravic "] 6 | readme = "../README.md" 7 | 8 | build = "../build.rs" 9 | 10 | [lib] 11 | path = "driver.rs" 12 | name = "minimal" 13 | crate-type = ["dylib"] 14 | 15 | test = false 16 | bench = false 17 | 18 | [profile.release] 19 | opt-level = 3 20 | debug = true 21 | rpath = false 22 | lto = true 23 | debug-assertions = false 24 | 25 | [dependencies] 26 | winapi-kmd = { path = "../../../km", version="*" } 27 | core = { path = "../../../libcore", version = "*" } 28 | -------------------------------------------------------------------------------- /examples/01.minimal/driver.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "dylib"] 2 | #![no_std] 3 | #![allow(bad_style)] 4 | 5 | #[macro_use] extern crate km; 6 | 7 | use core::mem; 8 | use km::*; 9 | 10 | #[no_mangle] 11 | pub extern "system" fn DriverEntry(driver: *mut km::DRIVER_OBJECT, _path: *const km::string::UnicodeString) -> Status 12 | { 13 | KdPrint!("[rs] hello, rust!\n"); 14 | let cb = mem::size_of::(); 15 | KdPrint!("[rs] we are DriverObject at 0x%p, sizeof 0x%X (%d bytes), expected size 0xA8 or 0x150\n", driver, cb, cb); 16 | return Status::unsuccessful; // return error to unload driver now 17 | } 18 | -------------------------------------------------------------------------------- /examples/01.minimal/exports.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DriverEntry 3 | 4 | -------------------------------------------------------------------------------- /examples/02.unload/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust.drv.examples.unload" 3 | description = "Simple Windows kernel driver which can be unloaded." 4 | version = "0.1.0" 5 | authors = ["pravic "] 6 | readme = "../README.md" 7 | 8 | build = "../build.rs" 9 | 10 | [lib] 11 | path = "driver.rs" 12 | name = "unload" 13 | crate-type = ["dylib"] 14 | 15 | test = false 16 | bench = false 17 | 18 | [profile.release] 19 | opt-level = 3 20 | debug = true 21 | rpath = false 22 | lto = true 23 | debug-assertions = false 24 | 25 | [dependencies] 26 | winapi-kmd = { path = "../../../km", version="*" } 27 | core = { path = "../../../libcore", version = "*" } 28 | -------------------------------------------------------------------------------- /examples/02.unload/driver.rs: -------------------------------------------------------------------------------- 1 | #![crate_type = "dylib"] 2 | #![no_std] 3 | #![allow(bad_style)] 4 | 5 | #[macro_use] extern crate km; 6 | 7 | use core::mem; 8 | use km::*; 9 | 10 | #[no_mangle] 11 | pub extern "system" fn DriverEntry(driver: &mut km::DRIVER_OBJECT, _path: *const km::string::UnicodeString) -> Status { 12 | 13 | KdPrint!("[rs] hello, rust!\n"); 14 | KdPrint!("[rs] we are DriverObject at 0x%p, sizeof %d\n", driver as *mut km::DRIVER_OBJECT , mem::size_of::()); 15 | 16 | driver.DriverUnload = Some(DriverUnload); 17 | return Status::success; 18 | } 19 | 20 | extern "system" fn DriverUnload(_obj: &mut km::DRIVER_OBJECT) { 21 | KdPrint!("[rs] unload.\n"); 22 | } 23 | -------------------------------------------------------------------------------- /examples/02.unload/exports.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DriverEntry 3 | 4 | -------------------------------------------------------------------------------- /examples/03.urandom/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust.drv.examples.urandom" 3 | description = "Windows kernel driver sample which creates `\\\\.\\urandom` device." 4 | version = "0.1.0" 5 | authors = ["pravic "] 6 | readme = "../README.md" 7 | 8 | build = "../build.rs" 9 | 10 | [lib] 11 | path = "driver.rs" 12 | name = "urandom" 13 | crate-type = ["dylib"] 14 | 15 | test = false 16 | bench = false 17 | 18 | [profile.release] 19 | opt-level = 3 20 | debug = true 21 | rpath = false 22 | lto = true 23 | debug-assertions = false 24 | 25 | [dependencies] 26 | winapi-kmd = { path = "../../../km", version="*" } 27 | core = { path = "../../../libcore", version = "*" } 28 | collections = { path = "../../../libcollections" } 29 | alloc = { path = "../../../liballoc" } 30 | alloc_system= { path = "../../src/alloc"} 31 | -------------------------------------------------------------------------------- /examples/03.urandom/build.cmd: -------------------------------------------------------------------------------- 1 | call "%VS140COMNTOOLS%vsvars32.bat" 2 | @set KIND=release 3 | @set NAME=urandom 4 | 5 | cargo build --%KIND% 6 | 7 | set LFLAGS=/NOLOGO /INCREMENTAL:NO /MANIFEST:NO /NODEFAULTLIB /SUBSYSTEM:NATIVE /DRIVER /RELEASE /DEBUG /NXCOMPAT /DYNAMICBASE /FIXED:No 8 | set LLIBS=ntoskrnl.lib hal.lib 9 | set RFLAGS=/OPT:REF /OPT:ICF 10 | rem cpu-specific 11 | set LPATH=/LIBPATH:"..\..\..\native\win7\i386" 12 | set LFLAGS=%LFLAGS% /MACHINE:X86 /entry:DriverEntry@8 13 | set TDIR=target\i686-sys-windows-msvc\%KIND% 14 | link.exe %LFLAGS% %RFLAGS% %LPATH% %LLIBS% %TDIR%\%NAME%.lib /OUT:%TDIR%\%NAME%.sys 15 | @pause 16 | -------------------------------------------------------------------------------- /examples/03.urandom/builddbg.cmd: -------------------------------------------------------------------------------- 1 | call "%VS140COMNTOOLS%vsvars32.bat" 2 | @set KIND=debug 3 | @set NAME=urandom 4 | 5 | cargo build 6 | 7 | set LFLAGS=/NOLOGO /INCREMENTAL:NO /MANIFEST:NO /NODEFAULTLIB /SUBSYSTEM:NATIVE /DRIVER /RELEASE /DEBUG /NXCOMPAT /DYNAMICBASE /FIXED:No 8 | set LLIBS=ntoskrnl.lib hal.lib 9 | set RFLAGS=/OPT:REF,ICF 10 | rem cpu-specific 11 | set LPATH=/LIBPATH:"..\..\..\native\win7\i386" 12 | set LFLAGS=%LFLAGS% /MACHINE:X86 /entry:DriverEntry@8 13 | set TDIR=target\i686-sys-windows-msvc\%KIND% 14 | link.exe %LFLAGS% %RFLAGS% %LPATH% %LLIBS% %TDIR%\%NAME%.lib /OUT:%TDIR%\%NAME%.sys 15 | @pause 16 | -------------------------------------------------------------------------------- /examples/03.urandom/buildrel.cmd: -------------------------------------------------------------------------------- 1 | call "%VS140COMNTOOLS%vsvars32.bat" 2 | @set KIND=release 3 | @set NAME=urandom 4 | 5 | cargo build --%KIND% %* 6 | 7 | set LFLAGS=/NOLOGO /INCREMENTAL:NO /MANIFEST:NO /NODEFAULTLIB /SUBSYSTEM:NATIVE /DRIVER /RELEASE /DEBUG /NXCOMPAT /DYNAMICBASE /FIXED:No 8 | set LLIBS=ntoskrnl.lib hal.lib 9 | set RFLAGS=/OPT:REF /OPT:ICF 10 | rem cpu-specific 11 | set LPATH=/LIBPATH:"..\..\..\native\win7\i386" 12 | set LFLAGS=%LFLAGS% /MACHINE:X86 /entry:DriverEntry@8 13 | set TDIR=target\i686-sys-windows-msvc\%KIND% 14 | link.exe %LFLAGS% %RFLAGS% %LPATH% %LLIBS% %TDIR%\lib%NAME%.lib /OUT:%TDIR%\%NAME%.sys 15 | @pause 16 | -------------------------------------------------------------------------------- /examples/03.urandom/driver.rs: -------------------------------------------------------------------------------- 1 | #![feature(collections)] 2 | 3 | #![no_std] 4 | #![allow(bad_style)] 5 | 6 | #[macro_use] extern crate km; 7 | #[macro_use] extern crate collections; 8 | 9 | use km::*; 10 | use km::irp::IRP_MJ; 11 | 12 | use core::mem; 13 | use core::ptr; 14 | 15 | 16 | // Helper for converting b"string" to UNICODE_STRING 17 | fn a2u(s: &[u8]) -> UnicodeString { 18 | let a = AnsiString::from(s); 19 | let mut u = UnicodeString::default(); 20 | unsafe { RtlAnsiStringToUnicodeString(&mut u, &a, true) }; 21 | return u; 22 | } 23 | 24 | // Our per-device settings payload 25 | struct DEVICE_PARAMS 26 | { 27 | pub name: UNICODE_STRING, 28 | pub link: UNICODE_STRING, 29 | } 30 | 31 | impl Drop for DEVICE_PARAMS 32 | { 33 | fn drop(&mut self) { 34 | unsafe { 35 | RtlFreeUnicodeString(&mut self.name); 36 | RtlFreeUnicodeString(&mut self.link); 37 | } 38 | } 39 | } 40 | 41 | 42 | #[no_mangle] 43 | pub extern "system" fn DriverEntry(driver: &mut km::DRIVER_OBJECT, _path: &km::string::UnicodeString) -> NTSTATUS 44 | { 45 | KdPrint!("[rs] hello, rust!\n"); 46 | KdPrint!("[rs] we are DriverObject at 0x%p, sizeof 0x%X (expected size 0xA8 or 0x150)\n", 47 | driver as *mut km::DRIVER_OBJECT, mem::size_of::()); 48 | 49 | driver.DriverUnload = Some(DriverUnload); 50 | 51 | KdPrint!("[rs] make params\n"); 52 | let params = DEVICE_PARAMS { name: a2u(b"\\Device\\RandomUDev\0"), link: a2u(b"\\??\\urandom\0"), }; 53 | 54 | // create device 55 | KdPrint!("[rs] create device `%ws` (%d bytes len)\n", params.name.Buffer, params.name.Length as u32); 56 | let mut device: *mut DEVICE_OBJECT = ptr::null_mut(); 57 | check_unsafe!(IoCreateDevice(driver, mem::size_of::() as u32, ¶ms.name, 34, 0, false, &mut device)); 58 | 59 | // store out custom params to DeviceExtension allocated memory 60 | KdPrint!("[rs] store params at device\n"); 61 | let device = unsafe { &mut *device }; 62 | let pparams = device.DeviceExtension as *mut DEVICE_PARAMS; 63 | let params = unsafe { 64 | ptr::write(pparams, params); 65 | &*pparams 66 | }; 67 | 68 | // create symlink 69 | KdPrint!("[rs] create symlink `%ws`\n", params.link.Buffer); 70 | let st = unsafe { IoCreateSymbolicLink(¶ms.link, ¶ms.name) }; 71 | if st.is_err() { 72 | DriverUnload(driver); 73 | return st; 74 | } 75 | 76 | // setup I/O processing handlers 77 | driver.MajorFunction[IRP_MJ::CREATE as usize] = Some(DispatchCreateClose); 78 | driver.MajorFunction[IRP_MJ::CLOSE as usize] = Some(DispatchCreateClose); 79 | driver.MajorFunction[IRP_MJ::READ as usize] = Some(DispatchRead); 80 | device.Flags |= DEVICE_FLAGS::DO_BUFFERED_IO as u32; 81 | 82 | KdPrint!("[rs] loaded.\n"); 83 | return Status::success; 84 | } 85 | 86 | extern "system" fn DriverUnload(driver: &mut km::DRIVER_OBJECT) 87 | { 88 | KdPrint!("[rs] unload:\n"); 89 | unsafe { 90 | // for each created device (driver.DeviceObject->NextDevice linked list) 91 | // delete symbolic link and delete device itself 92 | let mut pdevice = driver.DeviceObject; 93 | while !pdevice.is_null() { 94 | KdPrint_u!("[rs] free device\n"); 95 | let device = &mut *pdevice; 96 | if !device.DeviceExtension.is_null() { 97 | KdPrint_u!("[rs] drop params\n"); 98 | let params = &mut *(device.DeviceExtension as *mut DEVICE_PARAMS); 99 | IoDeleteSymbolicLink(¶ms.link); 100 | drop(params); 101 | } 102 | KdPrint_u!("[rs] delete device\n"); 103 | pdevice = device.NextDevice; 104 | IoDeleteDevice(device); 105 | } 106 | } 107 | KdPrint!("[rs] unloaded.\n"); 108 | } 109 | 110 | extern "system" fn DispatchCreateClose(_device: &mut DEVICE_OBJECT, irp: &mut IRP) -> NTSTATUS { 111 | let code = { irp.get_current_stack_location().MajorFunction }; 112 | if code == IRP_MJ::CREATE as u8 { 113 | KdPrint!("[rs] dispatch create\n"); 114 | } else { 115 | KdPrint!("[rs] dispatch close\n"); 116 | } 117 | irp.IoStatus.Information = 0; 118 | return irp.complete_request(Status::success); 119 | } 120 | 121 | extern "system" fn DispatchRead(device: &mut DEVICE_OBJECT, irp: &mut IRP) -> NTSTATUS 122 | { 123 | KdPrint!("[rs] dispatch read\n"); 124 | if (device.Flags & DEVICE_FLAGS::DO_BUFFERED_IO as u32) == 0 { 125 | KdPrint!("[rs] error: nonbuffered io!\n"); 126 | return irp.complete_request(Status::unsuccessful); 127 | } 128 | 129 | // process IRP request 130 | let size = 131 | { 132 | let io = irp.get_current_stack_location(); 133 | let args = io.ParametersRead(); 134 | args.Length as usize 135 | }; 136 | KdPrint!("[rs] read size %d\n", size as i32); 137 | 138 | if size == 0 { 139 | KdPrint!("[rs] error: empty buffer!\n"); 140 | return irp.complete_request(Status::unsuccessful); 141 | } 142 | 143 | KdPrint!("[rs] generate random\n"); 144 | let buf = irp.SystemBuffer; // AssociatedIrp.SystemBuffer union. 145 | let r = GenerateRandom(buf, size); 146 | let st = if let Ok(size) = r { 147 | irp.IoStatus.Information = size; 148 | Status::success 149 | } else { 150 | r.err().unwrap() 151 | }; 152 | return irp.complete_request(st); 153 | } 154 | 155 | // RtlRandom: Random number generator based on MacLaren and Marsaglia. 156 | // RtlRandomEx is twice as fast and produces better random numbers 157 | // since the period of the random numbers generated is comparatively higher. 158 | fn GenerateRandom(buffer: PVOID, size: usize) -> Result { 159 | let mut seed = km::time::QueryTickCount() as u32; 160 | let data = buffer as *mut u32; 161 | let dwords = size / 4; 162 | let tail = size % 4; 163 | KdPrint!("[rs] generate random for %d bytes as %d words and %d padding\n", size as u32, dwords as u32, tail as u32); 164 | unsafe { 165 | let mut i = 0; 166 | while i < dwords { 167 | let word = km::rtl::RtlRandomEx(&mut seed); 168 | *data.offset(i as isize) = word; 169 | i += 1; 170 | } 171 | if tail != 0 { 172 | let word = km::rtl::RtlRandomEx(&mut seed); 173 | km::crt::memcpy(data.offset(dwords as isize) as *mut u8, &word as *const u32 as *const u8, tail); 174 | } 175 | } 176 | KdPrint!("[rs] generate complete\n"); 177 | return Ok(size); 178 | } 179 | -------------------------------------------------------------------------------- /examples/03.urandom/exports.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DriverEntry 3 | 4 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ## Compatibility 2 | 3 | All examples tested against Windows XP SP3, Windows XP x64 SP2, Windows 7 x64 SP2, Windows 10 x64 and ReactOS 0.4.0. 4 | 5 | 6 | ## 01.minimal 7 | 8 | Minimal Windows kernel driver written in Rust. [DriverEntry](https://msdn.microsoft.com/en-us/library/windows/hardware/ff544113%28v=vs.85%29.aspx) just prints `hello` and quits immediately. 9 | 10 | 11 | ## 02.unload 12 | 13 | Simple kernel driver which supports [unloading](https://msdn.microsoft.com/en-us/library/windows/hardware/ff564886%28v=vs.85%29.aspx). 14 | 15 | 16 | ## 03.urandom 17 | 18 | [devrandom](https://github.com/pravic/ontl/tree/master/samples/devrandom) driver sample which has been ported to Rust. 19 | 20 | It creates `\\.\urandom` device, which can produce random data like `/dev/urandom`, but insecure. 21 | 22 | This sample shows how to create a [Device Object](https://msdn.microsoft.com/en-us/library/windows/hardware/ff548014%28v=vs.85%29.aspx), assotiate it with user-mode visible [name](https://msdn.microsoft.com/en-us/library/windows/hardware/ff556420%28v=vs.85%29.aspx) and process [I/O requests](https://msdn.microsoft.com/en-us/library/windows/hardware/ff544248%28v=vs.85%29.aspx) from user-mode applications. 23 | 24 | 25 | ### Screenshots 26 | 27 | [![Registered device](http://savepic.su/7182468m.png)](http://savepic.su/7182468.png) 28 | 29 | [![Communicating](http://savepic.su/7183492m.png)](http://savepic.su/7183492.png) 30 | -------------------------------------------------------------------------------- /examples/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn main() { 4 | let target = env::var("TARGET").unwrap(); 5 | let triple: Vec<_> = target.split('-').collect(); 6 | let mapped = match triple.get(0) { 7 | Some(&"i686") => "i386", 8 | Some(&"x86_64") => "amd64", 9 | _ => panic!("unknown architecture of {:?}", target), 10 | }; 11 | println!("cargo:rustc-link-search=../../../native/win7/{}", mapped); 12 | } 13 | -------------------------------------------------------------------------------- /examples/screenshots/winxp-2016-04-11-20-30-41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pravic/winapi-kmd-rs/ad962d199189d559dd5f41c574cf26e5f08744ab/examples/screenshots/winxp-2016-04-11-20-30-41.png -------------------------------------------------------------------------------- /examples/screenshots/winxp-2016-04-11-20-32-43.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pravic/winapi-kmd-rs/ad962d199189d559dd5f41c574cf26e5f08744ab/examples/screenshots/winxp-2016-04-11-20-32-43.png -------------------------------------------------------------------------------- /examples/screenshots/winxp-2016-04-11-20-46-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pravic/winapi-kmd-rs/ad962d199189d559dd5f41c574cf26e5f08744ab/examples/screenshots/winxp-2016-04-11-20-46-14.png -------------------------------------------------------------------------------- /src/alloc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alloc_system" 3 | version = "0.1.0" 4 | description = "Windows Kernel Mode support library." 5 | 6 | authors = ["pravic "] 7 | license = "MIT" 8 | 9 | [lib] 10 | name = "alloc_system" 11 | path = "alloc.rs" 12 | test = false 13 | 14 | [dependencies] 15 | core = { path= "../../../libcore" } 16 | alloc = { path = "../../../liballoc" } 17 | -------------------------------------------------------------------------------- /src/alloc/alloc.rs: -------------------------------------------------------------------------------- 1 | //! Kernel Mode Allocator 2 | 3 | #![crate_name = "alloc_system"] 4 | #![crate_type = "rlib"] 5 | 6 | // Allocators are not allowed to depend on the standard library which in turn 7 | // requires an allocator in order to avoid circular dependencies. This crate, 8 | // however, can use all of libcore. 9 | #![no_std] 10 | 11 | // The compiler needs to be instructed that this crate is an allocator in order 12 | // to realize that when this is linked in another allocator like jemalloc should 13 | // not be linked in 14 | #![feature(global_allocator)] 15 | #![feature(default_lib_allocator)] 16 | //#![allocator] 17 | 18 | 19 | 20 | mod pool; 21 | 22 | // Listed below are the five allocation functions currently required by custom 23 | // allocators. Their signatures and symbol names are not currently typechecked 24 | // by the compiler, but this is a future extension and are required to match 25 | // what is found below. 26 | // 27 | // Note that the standard `malloc` and `realloc` functions do not provide a way 28 | // to communicate alignment so this implementation would need to be improved 29 | // with respect to alignment in that aspect. 30 | 31 | const KMRS_TAG: u32 = 0x4B4D5253; // 'KMRS' 32 | use pool::{ExAllocatePoolWithTag, ExFreePoolWithTag, POOL_TYPE}; 33 | 34 | extern "C" 35 | { 36 | // from ntoskrnl 37 | pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; 38 | } 39 | 40 | #[no_mangle] 41 | pub extern "C" fn __rust_allocate(size: usize, _align: usize) -> *mut u8 42 | { 43 | unsafe { ExAllocatePoolWithTag(POOL_TYPE::PagedPool, size, KMRS_TAG) } 44 | } 45 | 46 | #[no_mangle] 47 | pub extern "C" fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) 48 | { 49 | unsafe { ExFreePoolWithTag(ptr, KMRS_TAG) }; 50 | } 51 | 52 | #[no_mangle] 53 | pub extern "C" fn __rust_reallocate(old: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 54 | { 55 | unsafe { 56 | // http://en.cppreference.com/w/c/memory/realloc 57 | let minsize = if size < old_size { size } else { old_size }; 58 | let new = __rust_allocate(size, align); 59 | if new.is_null() { 60 | return new; 61 | } 62 | if !old.is_null() && old_size > 0 { 63 | memcpy(new, old, minsize); 64 | __rust_deallocate(old, old_size, align); 65 | } 66 | return new; 67 | } 68 | } 69 | 70 | #[no_mangle] 71 | pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize, _align: usize) -> usize 72 | { 73 | old_size // this api is not supported 74 | } 75 | 76 | #[no_mangle] 77 | pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize 78 | { 79 | size 80 | } 81 | -------------------------------------------------------------------------------- /src/alloc/pool.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | pub enum POOL_TYPE 3 | { 4 | PagedPool, 5 | } 6 | 7 | pub type PVOID = *mut u8; 8 | 9 | extern "system" 10 | { 11 | pub fn ExAllocatePoolWithTag(PoolType: POOL_TYPE, NumberOfBytes: usize, Tag: u32) -> PVOID; 12 | pub fn ExFreePoolWithTag(P: PVOID, Tag: u32); 13 | } 14 | -------------------------------------------------------------------------------- /src/basedef.rs: -------------------------------------------------------------------------------- 1 | //! Kernel-Mode Types. 2 | 3 | use ::KIRQL; 4 | 5 | 6 | // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable 7 | // more optimization opportunities around it recognizing things like 8 | // malloc/free. 9 | #[repr(u8)] 10 | #[doc(hidden)] 11 | pub enum km_void { 12 | // Two dummy variants so the #[repr] attribute can be used. 13 | #[doc(hidden)] 14 | __variant1, 15 | #[doc(hidden)] 16 | __variant2, 17 | } 18 | 19 | pub type CHAR = i8; 20 | pub type CCHAR = i8; 21 | pub type USHORT = u16; 22 | pub type CSHORT = i16; 23 | pub type ULONG = u32; 24 | 25 | pub type VOID = km_void; 26 | pub type PVOID = *mut VOID; 27 | pub type PCVOID = *const VOID; 28 | 29 | pub type SIZE_T = usize; 30 | 31 | pub type ULONG_PTR = usize; 32 | 33 | pub type PEPROCESS = PVOID; 34 | pub type PETHREAD = PVOID; 35 | pub type PSECURITY_DESCRIPTOR = PVOID; 36 | 37 | pub type PGUID = PVOID; 38 | pub type PCGUID = PCVOID; 39 | 40 | pub type PSTR = *mut u8; 41 | pub type PWSTR = *mut u16; 42 | pub type PCSTR = *const u8; 43 | pub type PCWSTR = *const u16; 44 | 45 | pub type PIO_APC_ROUTINE = Option; 46 | 47 | 48 | extern "system" 49 | { 50 | pub fn KeGetCurrentIrql() -> KIRQL; 51 | pub fn KeRaiseIrqlToDpcLevel() -> KIRQL; 52 | } 53 | 54 | /// Doubly linked list structure. 55 | #[repr(C)] 56 | pub struct LIST_ENTRY 57 | { 58 | pub next: *mut LIST_ENTRY, 59 | pub prev: *mut LIST_ENTRY, 60 | } 61 | 62 | /// Spin Lock. 63 | #[repr(C)] 64 | #[derive(Default)] 65 | pub struct KSPIN_LOCK 66 | { 67 | pub lock: usize, 68 | } 69 | 70 | /// Common dispatcher object header. 71 | #[repr(C)] 72 | pub struct DISPATCHER_HEADER 73 | { 74 | pub Type: u8, 75 | pub Absolute: u8, 76 | pub Size: u8, 77 | pub Inserted: u8, 78 | pub SignalState: i32, 79 | pub WaitListHead: LIST_ENTRY, 80 | } 81 | 82 | /// An I/O status block. 83 | #[repr(C)] 84 | #[derive(Default, Clone, Copy)] 85 | pub struct IO_STATUS_BLOCK 86 | { 87 | /// Completion status. 88 | pub Status: ::NTSTATUS, 89 | /// Request-dependent value. 90 | pub Information: usize, 91 | } 92 | 93 | pub type PIO_STATUS_BLOCK = *mut IO_STATUS_BLOCK; 94 | 95 | impl IO_STATUS_BLOCK { 96 | /// Return integer value for `Information` field. 97 | pub fn as_size(&self) -> usize { 98 | self.Information 99 | } 100 | 101 | /// Return the pointer of specified object type. 102 | pub fn as_ptr(&self) -> *const T { 103 | unsafe { ::core::mem::transmute(self.Information) } 104 | } 105 | } 106 | 107 | 108 | /// Processor modes. 109 | #[repr(u8)] 110 | #[derive(Copy, Clone)] 111 | pub enum KPROCESSOR_MODE 112 | { 113 | KernelMode, 114 | UserMode, 115 | } 116 | 117 | /// I/O Request priority. 118 | pub mod IO_PRIORITY { 119 | /// I/O Request priority type. 120 | pub type KPRIORITY_BOOST = u8; 121 | 122 | pub const IO_NO_INCREMENT: KPRIORITY_BOOST = 0; 123 | pub const IO_DISK_INCREMENT: KPRIORITY_BOOST = 1; 124 | pub const EVENT_INCREMENT: KPRIORITY_BOOST = 1; 125 | } 126 | 127 | pub type KPRIORITY = IO_PRIORITY::KPRIORITY_BOOST; 128 | 129 | /// Memory Descriptor List (MDL) 130 | #[repr(C)] 131 | pub struct MDL 132 | { 133 | Next: *mut MDL, 134 | Size: i16, 135 | MdlFlags: i16, 136 | Process: PEPROCESS, 137 | MappedSystemVa: PVOID, 138 | StartVa: PVOID, 139 | ByteCount: u32, 140 | ByteOffset: u32, 141 | } 142 | 143 | pub type PMDL = *mut MDL; 144 | 145 | #[repr(i16)] 146 | pub enum MDL_FLAGS { 147 | MDL_MAPPED_TO_SYSTEM_VA = 0x0001, 148 | MDL_PAGES_LOCKED = 0x0002, 149 | MDL_SOURCE_IS_NONPAGED_POOL = 0x0004, 150 | MDL_ALLOCATED_FIXED_SIZE = 0x0008, 151 | MDL_PARTIAL = 0x0010, 152 | MDL_PARTIAL_HAS_BEEN_MAPPED = 0x0020, 153 | MDL_IO_PAGE_READ = 0x0040, 154 | MDL_WRITE_OPERATION = 0x0080, 155 | MDL_PARENT_MAPPED_SYSTEM_VA = 0x0100, 156 | MDL_LOCK_HELD = 0x0200, 157 | MDL_SCATTER_GATHER_VA = 0x0400, 158 | MDL_IO_SPACE = 0x0800, 159 | MDL_NETWORK_HEADER = 0x1000, 160 | MDL_MAPPING_CAN_FAIL = 0x2000, 161 | MDL_ALLOCATED_MUST_SUCCEED = 0x4000, 162 | } 163 | -------------------------------------------------------------------------------- /src/crt.rs: -------------------------------------------------------------------------------- 1 | //! C runtime library. 2 | //! 3 | //! Functions imported from `ntoskrnl.exe`. 4 | 5 | extern "C" 6 | { 7 | pub fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; 8 | pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; 9 | 10 | pub fn strlen(s: *const u8) -> usize; 11 | pub fn strcmp(s1: *const u8, s2: *const u8) -> i32; 12 | pub fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8; 13 | pub fn strcat(dest: *mut u8, src: *const u8) -> *mut u8; 14 | pub fn strncpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; 15 | 16 | pub fn wcslen(s: *const u16) -> usize; 17 | pub fn wcscpy(dest: *mut u16, src: *const u16) -> *mut u16; 18 | pub fn wcsncpy(dest: *mut u16, src: *const u16, n: usize) -> *mut u16; 19 | } 20 | 21 | 22 | #[no_mangle] 23 | #[allow(non_upper_case_globals)] 24 | #[cfg(target_arch="x86")] 25 | #[doc(hidden)] 26 | pub static __security_cookie: usize = 0xBB40E64E; 27 | 28 | #[no_mangle] 29 | #[allow(non_upper_case_globals)] 30 | #[cfg(target_arch="x86_64")] 31 | #[doc(hidden)] 32 | pub static __security_cookie: usize = 0x00002B992DDFA232; 33 | 34 | 35 | #[doc(hidden)] 36 | pub mod rust_intrinsics 37 | { 38 | #![allow(unused_variables)] 39 | 40 | // Idk why, but linker cannot find `_memcmp` for llvm intrinsics. So lets make forward one. 41 | #[no_mangle] 42 | pub unsafe fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 { 43 | return ::crt::memcmp(s1, s2, n); 44 | } 45 | 46 | // ported from compiler-rt 47 | // pub fn __muldi3(a: u64, b: u64) -> u64 { 48 | // unimplemented!(); 49 | // } 50 | 51 | #[no_mangle] 52 | pub fn __mulodi4(a: i64, b: i64, overflow: &mut i32) -> i64 { 53 | unimplemented!(); 54 | } 55 | 56 | #[no_mangle] 57 | pub extern "C" fn __multi3(a: i128, b: i128) -> i128 { 58 | unimplemented!(); 59 | } 60 | 61 | #[no_mangle] 62 | pub extern fn __muloti4(a: i128, b: i128, oflow: &mut i32) -> i128 { 63 | unimplemented!(); 64 | } 65 | 66 | #[no_mangle] 67 | pub extern "C" fn __udivti3(n: u128, d: u128) -> u128 { 68 | unimplemented!(); 69 | } 70 | 71 | #[no_mangle] 72 | pub extern "C" fn __umodti3(n: u128, d: u128) -> u128 { 73 | unimplemented!(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/debug.rs: -------------------------------------------------------------------------------- 1 | //! Debugger support. 2 | 3 | use ::status::NTSTATUS; 4 | 5 | extern "C" 6 | { 7 | /// `DbgPrint` routine sends a message to the kernel debugger. 8 | pub fn DbgPrint(Format: *const u8, ...) -> NTSTATUS; 9 | /// The `DbgPrintEx` routine sends a string to the kernel debugger if certain conditions are met. 10 | pub fn DbgPrintEx(ComponentId: u32, Level: u32, Format: *const u8, ...) -> NTSTATUS; 11 | } 12 | 13 | extern "system" 14 | { 15 | /// Breaks into the kernel debugger. 16 | pub fn DbgBreakPoint(); 17 | /// Breaks into the kernel debugger and sends the value of `Status` to the debugger. 18 | pub fn DbgBreakPointWithStatus(Status: NTSTATUS); 19 | } 20 | 21 | /// `DbgPrintEx` Message severity. 22 | #[repr(C)] 23 | pub enum DPFLTR_LEVEL { 24 | ERROR = 0, 25 | WARNING, 26 | TRACE, 27 | INFO, 28 | } 29 | 30 | /// `DbgPrintEx` Component name. 31 | #[repr(C)] 32 | pub enum DPFLTR_ID { 33 | SYSTEM = 0, 34 | SMSS, 35 | SETUP, 36 | NTFS, 37 | // ... 38 | IHVDRIVER = 77, 39 | IHVVIDEO, 40 | IHVAUDIO, 41 | IHVNETWORK, 42 | IHVSTREAMING, 43 | IHVBUS, 44 | 45 | DEFAULT = 99, 46 | } 47 | -------------------------------------------------------------------------------- /src/device_object.rs: -------------------------------------------------------------------------------- 1 | //! Device Object. 2 | 3 | use ::{NTSTATUS, UNICODE_STRING}; 4 | use ::driver_object::DRIVER_OBJECT; 5 | use ::irp::{IRP}; 6 | use ::dpc::KDPC; 7 | use ::event::KEVENT; 8 | use ::object::*; 9 | use ::PVOID; 10 | 11 | extern "system" 12 | { 13 | pub fn IoCreateDevice(DriverObject: &mut DRIVER_OBJECT, DeviceExtensionSize: u32, DeviceName: *const UNICODE_STRING, 14 | DeviceType: u32, DeviceCharacteristics: u32, Exclusive: bool, DeviceObject: *mut*mut DEVICE_OBJECT) -> NTSTATUS; 15 | 16 | pub fn IoDeleteDevice(DeviceObject: &mut DEVICE_OBJECT) -> NTSTATUS; 17 | pub fn IoCreateSymbolicLink(SymbolicLinkName: &UNICODE_STRING, DeviceName: &UNICODE_STRING) -> NTSTATUS; 18 | pub fn IoDeleteSymbolicLink(SymbolicLinkName: &UNICODE_STRING) -> NTSTATUS; 19 | } 20 | 21 | /// Device object flags. 22 | #[repr(C)] 23 | pub enum DEVICE_FLAGS { 24 | NONE = 0, 25 | DO_VERIFY_VOLUME = 0x00000002, 26 | DO_BUFFERED_IO = 0x00000004, 27 | DO_EXCLUSIVE = 0x00000008, 28 | DO_DIRECT_IO = 0x00000010, 29 | DO_MAP_IO_BUFFER = 0x00000020, 30 | DO_DEVICE_HAS_NAME = 0x00000040, 31 | DO_DEVICE_INITIALIZING = 0x00000080, 32 | DO_SYSTEM_BOOT_PARTITION = 0x00000100, 33 | DO_LONG_TERM_REQUESTS = 0x00000200, 34 | DO_NEVER_LAST_DEVICE = 0x00000400, 35 | DO_SHUTDOWN_REGISTERED = 0x00000800, 36 | DO_BUS_ENUMERATED_DEVICE = 0x00001000, 37 | DO_POWER_PAGABLE = 0x00002000, 38 | DO_POWER_INRUSH = 0x00004000, 39 | DO_POWER_NOOP = 0x00008000, 40 | DO_LOW_PRIORITY_FILESYSTEM = 0x00010000, 41 | DO_XIP = 0x00020000 42 | } 43 | 44 | /// `IoCompletion` routine result. 45 | #[repr(u32)] 46 | pub enum IO_COMPLETION_ROUTINE_RESULT { 47 | // STATUS_SUCCESS 48 | ContinueCompletion = 0, 49 | // STATUS_MORE_PROCESSING_REQUIRED 50 | StopCompletion = 0xC0000016, 51 | } 52 | 53 | /// The `DEVICE_OBJECT` structure is used by the operating system to represent a device object. 54 | #[repr(C)] 55 | pub struct DEVICE_OBJECT 56 | { 57 | pub Type: u16, 58 | pub Size: u16, 59 | pub ReferenceCount: i32, 60 | pub DriverObject: *const DRIVER_OBJECT, 61 | pub NextDevice: *mut DEVICE_OBJECT, 62 | pub AttachedDevice: *mut DEVICE_OBJECT, 63 | pub CurrentIrp: *const IRP, 64 | pub Timer: *mut u8, 65 | pub Flags: u32, 66 | pub Characteristics: u32, 67 | pub Vpb: *mut u8, 68 | pub DeviceExtension: *mut u8, 69 | pub DeviceType: u32, 70 | pub StackSize: u8, 71 | pub Queue: *mut WAIT_CONTEXT_BLOCK, 72 | pub AlignmentRequirement: u32, 73 | pub DeviceQueue: KDEVICE_QUEUE, 74 | pub Dpc: KDPC, 75 | pub ActiveThreadCount: u32, 76 | pub SecurityDescriptor: *const u8, 77 | pub DeviceLock: KEVENT, 78 | pub SectorSize: u16, 79 | pub Spare1: u16, 80 | pub DeviceObjectExtension: *mut DEVOBJ_EXTENSION, 81 | pub Reserved: *const u8, 82 | } 83 | 84 | impl DEVICE_OBJECT { 85 | /// Return a reference to driver-defined data structure. 86 | pub fn extension(&mut self) -> &mut T { 87 | unsafe { &mut *(self.DeviceExtension as *mut T) } 88 | } 89 | } 90 | 91 | /// Device object extension structure. 92 | #[repr(C)] 93 | pub struct DEVOBJ_EXTENSION 94 | { 95 | Type: u16, 96 | Size: u16, 97 | DeviceObject: *mut DEVICE_OBJECT, 98 | PowerFlags: u32, 99 | Dope: *mut u8, 100 | ExtensionFlags: u32, 101 | DeviceNode: *mut u8, 102 | AttachedTo: *mut DEVICE_OBJECT, 103 | StartIoCount: i32, 104 | StartIoKey: i32, 105 | StartIoFlags: u32, 106 | Vpb: *mut u8, 107 | } 108 | 109 | pub type PDEVICE_OBJECT = *mut DEVICE_OBJECT; 110 | 111 | pub type PDRIVER_CANCEL = Option; 112 | 113 | pub type PDRIVER_DISPATCH = Option NTSTATUS>; 114 | 115 | pub type PIO_COMPLETION_ROUTINE = Option IO_COMPLETION_ROUTINE_RESULT>; 116 | -------------------------------------------------------------------------------- /src/dpc.rs: -------------------------------------------------------------------------------- 1 | //! Deferred Procedure Calls (DPC). 2 | 3 | use ::basedef::*; 4 | 5 | extern "system" 6 | { 7 | pub fn KeInitializeDpc(Dpc: *mut KDPC, DeferredRoutine: PDEFERRED_ROUTINE, DeferredContext: *mut u8); 8 | pub fn KeInsertQueueDpc(Dpc: *mut KDPC, SystemArgument1: *const u8, SystemArgument2: *const u8) -> bool; 9 | pub fn KeRemoveQueueDpc(Dpc: *mut KDPC) -> bool; 10 | pub fn KeFlushQueuedDpcs(); 11 | pub fn KeGenericCallDpc(DeferredRoutine: PDEFERRED_ROUTINE, DeferredContext: *mut u8); 12 | } 13 | 14 | pub type PDEFERRED_ROUTINE = extern "system" fn (Dpc: *const KDPC, DeferredContext: *mut u8, SystemArgument1: *const u8, SystemArgument2: *const u8); 15 | 16 | /// Deferred Procedure Call object. 17 | #[repr(C)] 18 | pub struct KDPC 19 | { 20 | Type: u8, 21 | Number: u8, 22 | Importance: u8, 23 | 24 | DpcListEntry: LIST_ENTRY, 25 | DeferredRoutine: PDEFERRED_ROUTINE, 26 | DeferredContext: *mut u8, 27 | SystemArgument1: *mut u8, 28 | SystemArgument2: *mut u8, 29 | 30 | DpcData: *mut KDPC_DATA, 31 | } 32 | 33 | /// DPC data structure definition. 34 | #[repr(C)] 35 | pub struct KDPC_DATA 36 | { 37 | DpcListHead: LIST_ENTRY, 38 | DpcLock: KSPIN_LOCK, 39 | DpcQueueDepth: i32, 40 | DpcCount: u32, 41 | } 42 | -------------------------------------------------------------------------------- /src/driver_object.rs: -------------------------------------------------------------------------------- 1 | //! Driver Object. 2 | 3 | use ::{NTSTATUS, UNICODE_STRING}; 4 | use ::device_object::*; 5 | use ::irp::IRP; 6 | 7 | 8 | pub type PDRIVER_INITIALIZE = Option NTSTATUS>; 9 | pub type PDRIVER_STARTIO = Option; 10 | pub type PDRIVER_UNLOAD = Option; 11 | 12 | 13 | /// Represents the image of a loaded kernel-mode driver. 14 | #[repr(C)] 15 | pub struct DRIVER_OBJECT 16 | { 17 | pub Type: u16, 18 | pub Size: u16, 19 | pub DeviceObject: *mut DEVICE_OBJECT, 20 | pub Flags: u32, 21 | pub DriverStart: *const u8, 22 | pub DriverSize: u32, 23 | pub DriverSection: *const u8, 24 | pub DriverExtension: *mut u8, 25 | pub DriverName: UNICODE_STRING, 26 | pub HardwareDatabase: *const UNICODE_STRING, 27 | pub FastIoDispatch: *mut u8, 28 | pub DriverInit: PDRIVER_INITIALIZE, 29 | pub DriverStartIo: PDRIVER_STARTIO, 30 | /// The entry point for the driver's Unload routine, if any. 31 | pub DriverUnload: PDRIVER_UNLOAD, 32 | /// A dispatch table consisting of an array of entry points for the driver's `DispatchXxx` routines. 33 | pub MajorFunction: [PDRIVER_DISPATCH; 28], 34 | } 35 | -------------------------------------------------------------------------------- /src/event.rs: -------------------------------------------------------------------------------- 1 | //! Event Objects. 2 | 3 | use ::basedef::DISPATCHER_HEADER; 4 | 5 | extern "system" 6 | { 7 | pub fn KeInitializeEvent(Event: PKEVENT, Type: EVENT_TYPE, State: bool); 8 | pub fn KeSetEvent(Event: PKEVENT, Increment: i32, Wait: bool) -> i32; 9 | pub fn KeReadStateEvent(Event: PKEVENT) -> i32; 10 | pub fn KeResetEvent(Event: PKEVENT) -> i32; 11 | pub fn KeClearEvent(Event: PKEVENT); 12 | } 13 | 14 | pub type PKEVENT = *mut KEVENT; 15 | 16 | /// Specifies the event type. 17 | #[repr(C)] 18 | pub enum EVENT_TYPE 19 | { 20 | /// Manual-reset event. 21 | NotificationEvent = 0, 22 | /// Auto-clearing event. 23 | SynchronizationEvent, 24 | } 25 | 26 | /// Event object. 27 | #[repr(C)] 28 | pub struct KEVENT 29 | { 30 | Header: DISPATCHER_HEADER, 31 | } 32 | -------------------------------------------------------------------------------- /src/file_object.rs: -------------------------------------------------------------------------------- 1 | //! File Object. 2 | 3 | use ::device_object::PDEVICE_OBJECT; 4 | 5 | pub type PFILE_OBJECT = *mut FILE_OBJECT; 6 | 7 | /// The `FILE_OBJECT` structure is used by the system to represent a file object. 8 | #[repr(C)] 9 | pub struct FILE_OBJECT 10 | { 11 | Type: u16, 12 | Size: u16, 13 | DeviceObject: PDEVICE_OBJECT, 14 | // ... 15 | } 16 | -------------------------------------------------------------------------------- /src/irp.rs: -------------------------------------------------------------------------------- 1 | //! I/O request packets (IRP). 2 | 3 | use ::NTSTATUS; 4 | use ::basedef::*; 5 | use ::event::PKEVENT; 6 | use ::device_object::*; 7 | use ::file_object::*; 8 | use ::basedef::IO_PRIORITY::*; 9 | use ::KIRQL; 10 | 11 | 12 | pub type PIRP = *mut IRP; 13 | pub type PIO_STACK_LOCATION = *mut IO_STACK_LOCATION; 14 | 15 | // NOTE: fastcall is broken: https://github.com/rust-lang/rust/issues/18086 16 | //extern "fastcall" { fn IofCompleteRequest(Irp: PIRP, PriorityBoost: KPRIORITY_BOOST); } 17 | extern "system" 18 | { 19 | fn IoCompleteRequest(Irp: PIRP, PriorityBoost: KPRIORITY_BOOST); 20 | 21 | pub fn IoAllocateIrp(StackSize: CCHAR, ChargeQuota: bool) -> PIRP; 22 | pub fn IoFreeIrp(Irp: PIRP); 23 | pub fn IoReuseIrp(Irp: PIRP, Status: NTSTATUS); 24 | pub fn IoInitializeIrp(Irp: PIRP, PacketSize: USHORT, StackSize: CCHAR); 25 | pub fn IoMakeAssociatedIrp(Irp: PIRP, StackSize: CCHAR) -> PIRP; 26 | 27 | // unfortunately following are macro 28 | // fn IoGetCurrentIrpStackLocation(Irp: PIRP) -> PIO_STACK_LOCATION; 29 | // fn IoGetNextIrpStackLocation(Irp: PIRP) -> PIO_STACK_LOCATION; 30 | // fn IoSetNextIrpStackLocation(Irp: PIRP); 31 | // fn IoSkipCurrentIrpStackLocation(Irp: PIRP); 32 | } 33 | 34 | /// `IRP` Major Function Codes. 35 | /// 36 | /// For information about these requests, see 37 | /// [IRP Major Function Codes](https://msdn.microsoft.com/en-us/library/windows/hardware/ff548603%28v=vs.85%29.aspx). 38 | #[repr(u8)] 39 | pub enum IRP_MJ 40 | { 41 | /// The operating system sends this request to open a handle to a file object or device object. 42 | CREATE, 43 | CREATE_NAMED_PIPE, 44 | /// Indicates that the last handle of the file object that is associated with the target device object 45 | /// has been closed and released. All outstanding I/O requests have been completed or canceled. 46 | /// See also `CLEANUP`. 47 | CLOSE, 48 | /// A user-mode application or Win32 component has requested a data transfer from the device. 49 | /// Or a higher-level driver has created and set up the read IRP. 50 | READ, 51 | /// A user-mode application or Win32 component has requested a data transfer to the device. 52 | /// Or a higher-level driver has created and set up the write IRP. 53 | WRITE, 54 | QUERY_INFORMATION, 55 | SET_INFORMATION, 56 | QUERY_EA, 57 | SET_EA, 58 | /// Indicates that the driver should flush the device's cache or its internal buffer, 59 | /// or, possibly, should discard the data in its internal buffer. 60 | FLUSH_BUFFERS, 61 | QUERY_VOLUME_INFORMATION, 62 | SET_VOLUME_INFORMATION, 63 | DIRECTORY_CONTROL, 64 | FILE_SYSTEM_CONTROL, 65 | /// An user-mode thread has called the Microsoft Win32 `DeviceIoControl` function, or a higher-level kernel-mode driver has set up the request. 66 | DEVICE_CONTROL, 67 | /// Some driver calls either `IoBuildDeviceIoControlRequest` or `IoAllocateIrp` to create a request. 68 | INTERNAL_DEVICE_CONTROL, 69 | /// Indicates that a file system driver is sending notice that the system is being shut down. 70 | SHUTDOWN, 71 | LOCK_CONTROL, 72 | /// Indicates that the last handle for a file object that is associated with the target device object has been closed 73 | /// (but, due to outstanding I/O requests, might not have been released). 74 | /// See also `CLOSE`. 75 | CLEANUP, 76 | CREATE_MAILSLOT, 77 | QUERY_SECURITY, 78 | SET_SECURITY, 79 | POWER, 80 | SYSTEM_CONTROL, 81 | DEVICE_CHANGE, 82 | QUERY_QUOTA, 83 | SET_QUOTA, 84 | PNP, 85 | MAXIMUM_FUNCTION, 86 | } 87 | 88 | /// The `IRP` structure is a partial opaque structure that represents an I/O request packet. 89 | #[repr(C)] 90 | pub struct IRP 91 | { 92 | pub Type: u16, 93 | pub Size: u16, 94 | /// Pointer to an `MDL` describing a user buffer, if the driver is using direct I/O. 95 | pub MdlAddress: PVOID, 96 | /// Flags word - used to remember various flags. 97 | pub Flags: u32, 98 | /// Pointer to a system-space buffer if the driver is using buffered I/O. 99 | pub SystemBuffer: PVOID, 100 | pub ThreadListEntry: LIST_ENTRY, 101 | /// I/O status - final status of operation. 102 | pub IoStatus: IO_STATUS_BLOCK, 103 | /// Indicates the execution mode of the original requester of the operation. 104 | pub RequestorMode: KPROCESSOR_MODE, 105 | /// If set to `TRUE`, a driver has marked the IRP pending. 106 | pub PendingReturned: bool, 107 | /// Stack state information. 108 | pub StackCount: i8, 109 | /// Stack state information. 110 | pub CurrentLocation: i8, 111 | /// If set to `TRUE`, the IRP either is or should be canceled. 112 | pub Cancel: bool, 113 | /// Irql at which the cancel spinlock was acquired. 114 | pub CancelIrql: KIRQL, 115 | pub ApcEnvironment: u8, 116 | /// Allocation control flags. 117 | pub AllocationFlags: u8, 118 | /// User parameters. 119 | pub UserIosb: PIO_STATUS_BLOCK, 120 | pub UserEvent: PKEVENT, 121 | 122 | // union { 123 | pub UserApcRoutine: PIO_APC_ROUTINE, 124 | pub UserApcContext: PVOID, 125 | // } Overlay 126 | 127 | /// Contains the entry point for a driver-supplied `Cancel` routine to be called if the IRP is canceled. 128 | pub CancelRoutine: PDRIVER_CANCEL, 129 | /// Contains the address of an output buffer for `IRP_MJ_DEVICE_CONTROL`. 130 | pub UserBuffer: PVOID, 131 | 132 | /// Kernel structures. 133 | // union { 134 | pub Overlay: _IRP_OVERLAY, 135 | // } Tail 136 | } 137 | 138 | /// Kernel structures for IRP. 139 | #[repr(C)] 140 | pub struct _IRP_OVERLAY 141 | { 142 | pub DriverContext: [PVOID; 4], 143 | pub Thread: PETHREAD, 144 | pub AuxiliaryBuffer: PVOID, 145 | pub ListEntry: LIST_ENTRY, 146 | /// Current stack location. 147 | pub CurrentStackLocation: PIO_STACK_LOCATION, 148 | pub OriginalFileObject: PFILE_OBJECT, 149 | } 150 | 151 | pub const SL_PENDING_RETURNED: u8 = 0x01; 152 | pub const SL_INVOKE_ON_CANCEL: u8 = 0x20; 153 | pub const SL_INVOKE_ON_SUCCESS: u8 = 0x40; 154 | pub const SL_INVOKE_ON_ERROR: u8 = 0x80; 155 | 156 | /// I/O Stack Locations. 157 | #[repr(C)] 158 | pub struct IO_STACK_LOCATION 159 | { 160 | /// The IRP major function code indicating the type of I/O operation to be performed. 161 | pub MajorFunction: u8, 162 | /// A subfunction code for `MajorFunction`. 163 | pub MinorFunction: u8, 164 | /// Request-type-specific values (see [DEVICE_FLAGS](../device_object/enum.DEVICE_FLAGS.html)). 165 | pub Flags: u8, 166 | /// Stack location control flags. 167 | pub Control: u8, 168 | 169 | /// A union that depends on the major and minor IRP function code values 170 | /// contained in `MajorFunction` and `MinorFunction`. 171 | // union Parameters 172 | pub Parameters: [PVOID; 4], 173 | 174 | /// A pointer to the driver-created `DEVICE_OBJECT` structure 175 | /// representing the target physical, logical, or virtual device for which this driver is to handle the IRP. 176 | pub DeviceObject: PDEVICE_OBJECT, 177 | /// A pointer to a `FILE_OBJECT` structure that represents the file object, if any, that is associated with `DeviceObject` pointer. 178 | pub FileObject: PFILE_OBJECT, 179 | /// The following routine is invoked depending on the flags in the above `Flags` field. 180 | pub CompletionRoutine: PIO_COMPLETION_ROUTINE, 181 | /// The following is used to store the address of the context parameter that should be passed to the `CompletionRoutine`. 182 | pub Context: PVOID, 183 | } 184 | 185 | /// Parameters for `IRP_MJ_READ`. 186 | #[repr(C)] 187 | pub struct _IO_STACK_LOCATION_READ 188 | { 189 | pub Length: u32, 190 | pub Key: u32, 191 | pub ByteOffset: i64, 192 | } 193 | 194 | 195 | impl IRP { 196 | pub fn new(StackSize: i8) -> PIRP { 197 | unsafe { IoAllocateIrp(StackSize, false) } 198 | } 199 | 200 | pub fn with_quota(StackSize: i8) -> PIRP { 201 | unsafe { IoAllocateIrp(StackSize, true) } 202 | } 203 | 204 | pub fn free(&mut self) { 205 | unsafe { IoFreeIrp(self) }; 206 | } 207 | 208 | /// Returns a pointer to the caller's stack location in the given `IRP`. 209 | pub fn get_current_stack_location(&mut self) -> &mut IO_STACK_LOCATION { 210 | unsafe { &mut *self.Overlay.CurrentStackLocation } 211 | } 212 | 213 | /// Returns a pointer to the next-lower-level driver's I/O stack location. 214 | pub fn get_next_stack_location(&mut self) -> &mut IO_STACK_LOCATION { 215 | unsafe { &mut *self.Overlay.CurrentStackLocation.offset(-1) } 216 | } 217 | 218 | /// Indicates that the caller has completed all processing for a given I/O request 219 | /// and is returning the given IRP to the I/O manager. 220 | pub fn complete_request(&mut self, Status: NTSTATUS) -> NTSTATUS { 221 | self.IoStatus.Status = Status; 222 | unsafe { IoCompleteRequest(self, IO_NO_INCREMENT) }; 223 | return Status; 224 | } 225 | 226 | /// Registers an `IoCompletion` routine, which will be called when the next-lower-level driver 227 | /// has completed the requested operation for the given IRP. 228 | pub fn set_completion(&mut self, CompletionRoutine: PIO_COMPLETION_ROUTINE, Context: PVOID, 229 | InvokeOnSuccess: bool, InvokeOnError: bool, InvokeOnCancel: bool) 230 | { 231 | let mut lower = self.get_next_stack_location(); 232 | lower.CompletionRoutine = CompletionRoutine; 233 | lower.Context = Context; 234 | lower.Control = 0; 235 | if InvokeOnSuccess { 236 | lower.Control |= SL_INVOKE_ON_SUCCESS; 237 | } 238 | if InvokeOnError { 239 | lower.Control |= SL_INVOKE_ON_ERROR; 240 | } 241 | if InvokeOnCancel { 242 | lower.Control |= SL_INVOKE_ON_CANCEL; 243 | } 244 | } 245 | 246 | pub fn set_unconditional_completion(&mut self, CompletionRoutine: PIO_COMPLETION_ROUTINE, Context: PVOID) { 247 | self.set_completion(CompletionRoutine, Context, true, true, true) 248 | } 249 | } 250 | 251 | impl IO_STACK_LOCATION { 252 | /// Access parameters for `IRP_MJ_READ`. 253 | pub fn ParametersRead(&mut self) -> &mut _IO_STACK_LOCATION_READ { 254 | unsafe { ::core::mem::transmute(&mut self.Parameters) } 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/irql.rs: -------------------------------------------------------------------------------- 1 | //! Interrupt Request Level (IRQL). 2 | 3 | /// IRQL type. 4 | pub type KIRQL = u8; 5 | 6 | /// Passive release level, no interrupt vectors are masked. 7 | pub const PASSIVE_LEVEL: KIRQL = 0; 8 | /// The lowest IRQL level, no interrupt vectors are masked. 9 | pub const LOW_LEVEL: KIRQL = 0; 10 | /// APC interrupt level. 11 | pub const APC_LEVEL: KIRQL = 1; 12 | /// Dispatcher level 13 | pub const DISPATCH_LEVEL: KIRQL = 2; 14 | 15 | /// Timer used for profiling. 16 | #[cfg(target_arch = "x86")] 17 | pub const PROFILE_LEVEL: KIRQL = 27; 18 | 19 | /// Interval clock level. 20 | #[cfg(target_arch = "x86")] 21 | pub const CLOCK_LEVEL: KIRQL = 28; 22 | 23 | /// Interprocessor interrupt level. 24 | #[cfg(target_arch = "x86")] 25 | pub const IPI_LEVEL: KIRQL = 29; 26 | 27 | /// Power failure level. 28 | #[cfg(target_arch = "x86")] 29 | pub const POWER_LEVEL: KIRQL = 30; 30 | 31 | /// Highest interrupt level. 32 | #[cfg(target_arch = "x86")] 33 | pub const HIGH_LEVEL: KIRQL = 31; 34 | 35 | /// Synchronization level. 36 | #[cfg(target_arch = "x86")] 37 | pub const SYNCH_LEVEL: KIRQL = 29 - 2; 38 | 39 | /// Interval clock level. 40 | #[cfg(target_arch = "x86_64")] 41 | pub const CLOCK_LEVEL: KIRQL = 13; 42 | 43 | /// Interprocessor interrupt level. 44 | #[cfg(target_arch = "x86_64")] 45 | pub const IPI_LEVEL: KIRQL = 14; 46 | 47 | /// Power failure level. 48 | #[cfg(target_arch = "x86_64")] 49 | pub const POWER_LEVEL: KIRQL = 15; 50 | 51 | /// Timer used for profiling. 52 | #[cfg(target_arch = "x86_64")] 53 | pub const PROFILE_LEVEL: KIRQL = 16; 54 | 55 | /// Highest interrupt level. 56 | #[cfg(target_arch = "x86_64")] 57 | pub const HIGH_LEVEL: KIRQL = 17; 58 | 59 | /// Synchronization level. 60 | #[cfg(target_arch = "x86_64")] 61 | pub const SYNCH_LEVEL: KIRQL = 14- 2; 62 | -------------------------------------------------------------------------------- /src/lang.rs: -------------------------------------------------------------------------------- 1 | #[lang = "eh_personality"] extern fn eh_personality() {} 2 | #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} 3 | 4 | #[lang = "panic_fmt"] extern fn panic_fmt() -> ! { 5 | KdPrint!("panic_fmt() -> !"); 6 | loop{} 7 | } 8 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Windows Kernel Mode library. 2 | 3 | #![feature(lang_items)] 4 | #![feature(on_unimplemented, fundamental)] 5 | #![feature(no_core)] 6 | #![feature(i128_type)] 7 | 8 | #![no_std] 9 | #![allow(bad_style)] 10 | 11 | 12 | #[macro_use] pub mod macros; 13 | 14 | mod lang; 15 | 16 | pub mod status; 17 | 18 | pub mod basedef; 19 | pub mod crt; 20 | pub mod debug; 21 | pub mod device_object; 22 | pub mod dpc; 23 | pub mod driver_object; 24 | pub mod event; 25 | pub mod file_object; 26 | pub mod irp; 27 | pub mod irql; 28 | pub mod object; 29 | pub mod pool; 30 | pub mod rtl; 31 | pub mod shared; 32 | pub mod string; 33 | pub mod time; 34 | 35 | #[doc(hidden)] 36 | pub use irql::KIRQL; 37 | 38 | #[doc(hidden)] 39 | pub use status::*; 40 | 41 | #[doc(hidden)] 42 | pub use debug::DbgPrint; 43 | 44 | #[doc(hidden)] 45 | pub use string::*; 46 | 47 | #[doc(hidden)] 48 | pub use driver_object::*; 49 | 50 | #[doc(hidden)] 51 | pub use device_object::*; 52 | 53 | #[doc(hidden)] 54 | pub use irp::IRP; 55 | 56 | #[doc(hidden)] 57 | pub use basedef::{PVOID}; 58 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | //! Macros for Kernel-Mode drivers. 2 | 3 | /// Macro to send a message to the kernel debugger. 4 | /// 5 | /// # Example 6 | /// 7 | /// ```no_run 8 | /// KdPrint!("NTSTATUS is 0x%X\n", status); 9 | /// ``` 10 | #[macro_export] 11 | macro_rules! KdPrint { 12 | ($msg:expr $(, $arg:expr)*) => { unsafe { $crate::debug::DbgPrint( concat!($msg, "\0").as_ptr() $(, $arg )* )} }; 13 | } 14 | 15 | /// Macro to send a message to the kernel debugger for unsafe blocks. 16 | /// 17 | /// Used in `unsafe {}` blocks. 18 | #[macro_export] 19 | macro_rules! KdPrint_u { 20 | ($msg:expr $(, $arg:expr)*) => { $crate::debug::DbgPrint( concat!($msg, "\0").as_ptr() $(, $arg )* ) }; 21 | } 22 | 23 | #[macro_export] 24 | macro_rules! check_unsafe { 25 | ($expr:expr) => {{ 26 | let st: $crate::status::Status = unsafe { $expr }; 27 | if st.is_err() { 28 | KdPrint!("[km] error: status 0x%X\n", st); 29 | return st; 30 | } else { 31 | st 32 | } 33 | }} 34 | } 35 | -------------------------------------------------------------------------------- /src/object.rs: -------------------------------------------------------------------------------- 1 | //! Kernel Objects. 2 | 3 | use ::basedef::*; 4 | use ::device_object::PDEVICE_OBJECT; 5 | use ::irp::IRP; 6 | use ::status::NTSTATUS; 7 | 8 | extern "system" 9 | { 10 | pub fn KeWaitForSingleObject(Object: PVOID, WaitReason: u32, WaitMode: KPROCESSOR_MODE, Alertable: bool, Timeout: Option<&i64>) -> NTSTATUS; 11 | } 12 | 13 | #[repr(C)] 14 | pub struct WAIT_CONTEXT_BLOCK 15 | { 16 | WaitQueueEntry: *mut KDEVICE_QUEUE_ENTRY, 17 | DeviceRoutine: extern "system" fn (_obj: PDEVICE_OBJECT, _irp: *mut IRP, *mut u8, *mut u8) -> IO_ALLOCATION_ACTION, 18 | DeviceContext: *mut u8, 19 | NumberOfMapRegisters: u32, 20 | DeviceObject: *mut u8, 21 | CurrentIrp: *mut u8, 22 | BufferChainingDpc: * mut u8, 23 | } 24 | 25 | #[repr(C)] 26 | pub enum IO_ALLOCATION_ACTION 27 | { 28 | KeepObject = 0x01, 29 | DeallocateObject = 0x02, 30 | DeallocateObjectKeepRegisters = 0x03, 31 | } 32 | 33 | #[repr(C)] 34 | pub struct KDEVICE_QUEUE_ENTRY 35 | { 36 | DeviceListEntry: LIST_ENTRY, 37 | SortKey: u32, 38 | Inserted: bool, 39 | } 40 | 41 | #[repr(C)] 42 | pub struct KDEVICE_QUEUE 43 | { 44 | Type: u16, 45 | Size: u16, 46 | DeviceListHead: LIST_ENTRY, 47 | Lock: KSPIN_LOCK, 48 | Busy: bool, 49 | } 50 | -------------------------------------------------------------------------------- /src/pool.rs: -------------------------------------------------------------------------------- 1 | //! Kernel Mode pools. 2 | 3 | use ::PVOID; 4 | 5 | extern "system" 6 | { 7 | /// Allocates pool memory of the specified type and tag. 8 | pub fn ExAllocatePoolWithTag(PoolType: POOL_TYPE, NumberOfBytes: usize, Tag: u32) -> PVOID; 9 | /// Deallocates a block of pool memory allocated with the specified tag. 10 | pub fn ExFreePoolWithTag(P: PVOID, Tag: u32); 11 | 12 | /// Allocates pool memory of the specified type. 13 | pub fn ExAllocatePool(PoolType: POOL_TYPE, NumberOfBytes: usize) -> PVOID; 14 | /// Deallocates a block of pool memory. 15 | pub fn ExFreePool(P: PVOID); 16 | } 17 | 18 | 19 | /// Specifies the type of system memory to allocate. 20 | #[repr(C)] 21 | pub enum POOL_TYPE 22 | { 23 | /// Nonpageable system memory, can be accessed from any IRQL. 24 | NonPagedPool = 0, 25 | /// Pageable system memory, can only be allocated and accessed at IRQL < DISPATCH_LEVEL. 26 | PagedPool, 27 | NonPagedPoolMustSucceed, 28 | DontUseThisType, 29 | /// Nonpaged pool, aligned on processor cache boundaries. 30 | NonPagedPoolCacheAligned, 31 | /// Paged pool, aligned on processor cache boundaries. 32 | PagedPoolCacheAligned, 33 | NonPagedPoolCacheAlignedMustS, 34 | MaxPoolType, 35 | NonPagedPoolSession = 32, 36 | PagedPoolSession, 37 | NonPagedPoolMustSucceedSession, 38 | DontUseThisTypeSession, 39 | NonPagedPoolCacheAlignedSession, 40 | PagedPoolCacheAlignedSession, 41 | NonPagedPoolCacheAlignedMustSSession, 42 | } 43 | -------------------------------------------------------------------------------- /src/rtl.rs: -------------------------------------------------------------------------------- 1 | //! NT runtime routines. 2 | 3 | extern "system" 4 | { 5 | /// Returns a random number that was generated from a given `seed` value in the range `[0..MAXLONG-1]`. 6 | pub fn RtlRandom(Seed: *mut u32) -> u32; 7 | /// Returns a random number that was generated from a given `seed` value in the range `[0..MAXLONG-1]`. 8 | pub fn RtlRandomEx(Seed: *mut u32) -> u32; 9 | /// A simple uniform random number generator, based on D.H. Lehmer's 1948 alrogithm. 10 | pub fn RtlUniform(Seed: *mut u32) -> u32; 11 | } 12 | -------------------------------------------------------------------------------- /src/shared.rs: -------------------------------------------------------------------------------- 1 | //! Data shared between kernel and user mode. 2 | 3 | 4 | /// System time is a count of 100-nanosecond intervals since January 1, 1601. 5 | pub type SYSTEMTIME = i64; 6 | 7 | 8 | /// Dystem time structure 9 | #[repr(C)] 10 | #[derive(Copy, Clone)] 11 | pub struct KSYSTEM_TIME 12 | { 13 | LowPart: u32, 14 | High1Time: i32, 15 | High2Time: i32, 16 | } 17 | 18 | #[repr(C)] 19 | pub enum NT_PRODUCT_TYPE 20 | { 21 | NtProductWinNt = 1, 22 | NtProductLanManNt, 23 | NtProductServer 24 | } 25 | 26 | #[repr(C)] 27 | pub enum ALTERNATIVE_ARCHITECTURE_TYPE 28 | { 29 | StandardDesign, 30 | NEC98x86, 31 | EndAlternatives, 32 | } 33 | 34 | /// The data shared between kernel and user mode. 35 | #[repr(C)] 36 | pub struct KUSER_SHARED_DATA 37 | { 38 | pub TickCountLowDeprecated: u32, 39 | pub TickCountMultiplier: u32, 40 | 41 | /// Current 64-bit interrupt time in 100ns units. 42 | pub InterruptTime: KSYSTEM_TIME, 43 | /// Current 64-bit system time in 100ns units. 44 | pub SystemTime: KSYSTEM_TIME, 45 | /// Current 64-bit time zone bias. 46 | pub TimeZoneBias: KSYSTEM_TIME, 47 | 48 | pub ImageNumberLow: u16, 49 | pub ImageNumberHigh: u16, 50 | 51 | pub NtSystemRoot: [u16; 260], 52 | 53 | pub MaxStackTraceDepth: u32, 54 | pub CryptoExponent: u32, 55 | pub TimeZoneId: u32, 56 | pub LargePageMinimum: u32, 57 | pub Reserved2: [u32; 7], 58 | 59 | pub NtProductType: NT_PRODUCT_TYPE, 60 | pub ProductTypeIsValid: bool, 61 | pub NtMajorVersion: u32, 62 | pub NtMinorVersion: u32, 63 | 64 | pub ProcessorFeatures: [bool; 64], 65 | pub Reserved1: u32, 66 | pub Reserved3: u32, 67 | pub TimeSlip: u32, 68 | 69 | pub AlternativeArchitecture: ALTERNATIVE_ARCHITECTURE_TYPE, 70 | pub SystemExpirationDate: u64, 71 | pub SuiteMask: u32, 72 | 73 | /// True if a kernel debugger is connected/enabled. 74 | pub KdDebuggerEnabled: bool, 75 | pub NXSupportPolicy: u8, 76 | pub ActiveConsoleId: u32, 77 | pub DismountCount: u32, 78 | pub ComPlusPackage: u32, 79 | pub LastSystemRITEventTickCount: u32, 80 | pub NumberOfPhysicalPages: u32, 81 | 82 | /// True if the system was booted in safe boot mode. 83 | pub SafeBootMode: bool, 84 | pub TraceLogging: u32, 85 | 86 | pub TestRetInstruction: u64, 87 | pub SystemCall: u32, 88 | pub SystemCallReturn: u32, 89 | pub SystemCallPad: [u64; 3], 90 | 91 | /// The 64-bit tick count. 92 | pub TickCount: KSYSTEM_TIME, 93 | 94 | /// Cookie for encoding pointers system wide. 95 | pub Cookie: u32, 96 | 97 | // NT 6.0+: 98 | 99 | #[cfg(target_arch = "x86_64")] 100 | pub Wow64SharedInformation: [u32; 16], 101 | #[cfg(target_arch = "x86_64")] 102 | pub UserModeGlobalLogger: [u16; 8], 103 | #[cfg(target_arch = "x86_64")] 104 | pub HeapTracingPid: [u32; 2], 105 | #[cfg(target_arch = "x86_64")] 106 | pub CritSecTracingPid: [u32; 2], 107 | #[cfg(target_arch = "x86_64")] 108 | pub ImageFileExecutionOptions: u32, 109 | #[cfg(target_arch = "x86_64")] 110 | pub ActiveProcessorAffinity: u64, 111 | #[cfg(target_arch = "x86_64")] 112 | pub InterruptTimeBias: u64, 113 | } 114 | 115 | #[cfg(target_arch = "x86")] 116 | const KI_USER_SHARED_DATA: *const KUSER_SHARED_DATA = 0xffdf_0000 as *const KUSER_SHARED_DATA; 117 | 118 | #[cfg(target_arch = "x86_64")] 119 | const KI_USER_SHARED_DATA: *const KUSER_SHARED_DATA = 0xFFFF_F780_0000_0000 as *const KUSER_SHARED_DATA; 120 | 121 | impl KUSER_SHARED_DATA { 122 | 123 | /// Get reference to the mapped shared data. 124 | pub fn get() -> &'static KUSER_SHARED_DATA { 125 | unsafe { &*KI_USER_SHARED_DATA } 126 | } 127 | } 128 | 129 | /// Convert `KSYSTEM_TIME` to `i64` 130 | #[cfg(target_arch = "x86_64")] 131 | impl ::core::convert::From for SYSTEMTIME { 132 | fn from(time: KSYSTEM_TIME) -> Self { 133 | unsafe { *(&time as *const KSYSTEM_TIME as *const SYSTEMTIME) } 134 | } 135 | } 136 | 137 | /// Convert `KSYSTEM_TIME` to `i64` 138 | #[cfg(target_arch = "x86")] 139 | impl ::core::convert::From for SYSTEMTIME { 140 | fn from(time: KSYSTEM_TIME) -> Self { 141 | // FIXME: is any `volatile` or memory fenses need here? 142 | let mut lo; 143 | let mut hi; 144 | loop { 145 | hi = time.High1Time; 146 | lo = time.LowPart; 147 | if hi == time.High2Time { 148 | break; 149 | } 150 | } 151 | return (hi as i64) << 32 | lo as i64 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/status.rs: -------------------------------------------------------------------------------- 1 | //! NT Status codes. 2 | #![allow(non_camel_case_types)] 3 | #![allow(overflowing_literals)] 4 | 5 | /// NT Status type. 6 | pub type NTSTATUS = Status; 7 | 8 | /// A specialized `Result` type for NT operations. 9 | pub type Result = ::core::result::Result; 10 | 11 | 12 | /// NT Status code. 13 | #[repr(C)] 14 | #[derive(Clone, Copy)] 15 | pub enum Status { 16 | success = 0, 17 | unsuccessful = 0xC0000001, 18 | } 19 | 20 | impl ::core::default::Default for Status { 21 | #[inline] 22 | fn default() -> Status { 23 | Status::success 24 | } 25 | } 26 | 27 | impl Status { 28 | /// Evaluates to `true` if the `Status` is a success type (`0..0x3FFFFFFF`) 29 | /// or an informational type (`0x40000000..0x7FFFFFFF`). 30 | pub fn is_ok(&self) -> bool { 31 | (*self as i32) >= 0 32 | } 33 | /// Status is a warning or error type. 34 | pub fn is_err(&self) -> bool { 35 | (*self as i32) < 0 36 | } 37 | /// Status is a success type. 38 | pub fn is_success(&self) -> bool { 39 | let c = *self as u32; 40 | c > 0 && c < 0x3FFF_FFFF 41 | } 42 | /// Status is a information type. 43 | pub fn is_information(&self) -> bool { 44 | let c = *self as u32; 45 | c > 0x4000_0000 && c < 0x7FFF_FFFF 46 | } 47 | /// Status is a warning type. 48 | pub fn is_warning(&self) -> bool { 49 | let c = *self as u32; 50 | c > 0x8000_0000 && c < 0xBFFF_FFFF 51 | } 52 | /// Status is a error type. 53 | pub fn is_error(&self) -> bool { 54 | let c = *self as u32; 55 | c > 0xC000_0000 && c < 0xFFFF_FFFF 56 | } 57 | } 58 | 59 | /// Convert `Status` to `Result<()>`. 60 | pub fn check(st: Status) -> Result<()> { 61 | if st.is_err() { 62 | Err(st) 63 | } else { 64 | Ok(()) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/string.rs: -------------------------------------------------------------------------------- 1 | //! Kernel mode string types. 2 | 3 | use ::NTSTATUS; 4 | 5 | /// NT native string types. 6 | pub trait NativeString { 7 | /// Size of string in bytes. 8 | fn size(&self) -> u16; 9 | /// Size of buffer in bytes. 10 | fn max_size(&self) -> u16; 11 | 12 | /// Check is the string is empty. 13 | fn is_empty(&self) -> bool { 14 | self.size() == 0u16 15 | } 16 | } 17 | 18 | /// A counted Unicode string. 19 | #[repr(C)] 20 | pub struct UNICODE_STRING 21 | { 22 | /// The length in **bytes** of the string stored in `Buffer`. 23 | pub Length: u16, 24 | /// The length in **bytes** of `Buffer`. 25 | pub MaximumLength: u16, 26 | /// Pointer to a buffer used to contain a string of wide characters. 27 | pub Buffer: *const u16, 28 | } 29 | 30 | /// A counted string used for ANSI strings. 31 | #[repr(C)] 32 | pub struct ANSI_STRING 33 | { 34 | /// The length in *bytes* of the string stored in `Buffer`. 35 | pub Length: u16, 36 | /// The length in bytes of `Buffer`. 37 | pub MaximumLength: u16, 38 | /// Pointer to a buffer used to contain a string of characters. 39 | pub Buffer: *const u8, 40 | } 41 | 42 | impl NativeString for UNICODE_STRING 43 | { 44 | fn size(&self) -> u16 { self.Length } 45 | fn max_size(&self) -> u16 { self.MaximumLength } 46 | } 47 | 48 | impl UNICODE_STRING 49 | { 50 | } 51 | 52 | /// Initializes a counted Unicode string. 53 | impl Default for UNICODE_STRING { 54 | fn default() -> Self { 55 | UNICODE_STRING { Length: 0, MaximumLength: 0, Buffer: ::core::ptr::null() } 56 | } 57 | } 58 | 59 | impl<'a> From<&'a [u8]> for ANSI_STRING { 60 | fn from(s: &'a [u8]) -> Self { 61 | let len = s.len(); 62 | let n = if len > 0 && s[len-1] == 0 { len - 1 } else { len }; 63 | ANSI_STRING { Length: n as u16, MaximumLength: len as u16, Buffer: s.as_ptr() } 64 | } 65 | } 66 | 67 | 68 | pub type AnsiString = ANSI_STRING; 69 | pub type UnicodeString = UNICODE_STRING; 70 | pub type CONST_UNICODE_STRING = UNICODE_STRING; 71 | pub type CONST_ANSI_STRING = ANSI_STRING; 72 | 73 | pub type PUNICODE_STRING = *mut UNICODE_STRING; 74 | pub type PCUNICODE_STRING = *const UNICODE_STRING; 75 | 76 | extern "system" 77 | { 78 | pub fn RtlIntegerToUnicodeString(Value: u32, Base: u32, String: &mut UNICODE_STRING) -> NTSTATUS; 79 | pub fn RtlInt64ToUnicodeString(Value: u64, Base: u32, String: &mut UNICODE_STRING) -> NTSTATUS; 80 | pub fn RtlUnicodeStringToInteger(String: &CONST_UNICODE_STRING, Base: u32, Value: &mut u32) -> NTSTATUS; 81 | 82 | pub fn RtlUnicodeStringToAnsiString(DestinationString: &mut ANSI_STRING, SourceString: &CONST_UNICODE_STRING, AllocateDestination: bool) -> NTSTATUS; 83 | pub fn RtlUnicodeStringToAnsiSize(SourceString: &CONST_UNICODE_STRING) -> u32; 84 | 85 | pub fn RtlAnsiStringToUnicodeString(DestinationString: &mut UNICODE_STRING, SourceString: &CONST_ANSI_STRING, AllocateDestination: bool) -> NTSTATUS; 86 | pub fn RtlAnsiStringToUnicodeSize(SourceString: &CONST_ANSI_STRING) -> u32; 87 | 88 | pub fn RtlCompareUnicodeString (String1: &CONST_UNICODE_STRING, String2: &CONST_UNICODE_STRING, CaseInSensitive: bool) -> i32; 89 | pub fn RtlCompareString (String1: &CONST_ANSI_STRING, String2: &CONST_ANSI_STRING, CaseInSensitive: bool) -> i32; 90 | 91 | pub fn RtlEqualUnicodeString(String1: &CONST_UNICODE_STRING, String2: &CONST_UNICODE_STRING) -> bool; 92 | pub fn RtlEqualString(String1: &CONST_ANSI_STRING, String2: &CONST_ANSI_STRING) -> bool; 93 | 94 | pub fn RtlFreeAnsiString(UnicodeString: &mut ANSI_STRING); 95 | pub fn RtlFreeUnicodeString(UnicodeString: &mut UNICODE_STRING); 96 | } 97 | -------------------------------------------------------------------------------- /src/thread.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pravic/winapi-kmd-rs/ad962d199189d559dd5f41c574cf26e5f08744ab/src/thread.rs -------------------------------------------------------------------------------- /src/time.rs: -------------------------------------------------------------------------------- 1 | //! NT Time routines. 2 | 3 | use ::shared::{SYSTEMTIME}; 4 | 5 | #[cfg(target_arch = "x86_64")] 6 | use ::shared::{KUSER_SHARED_DATA}; 7 | 8 | 9 | extern "system" 10 | { 11 | // The following exports exists only on x86 kernels. 12 | // x64 drivers must use KUSER_SHARED_DATA to obtain these values. 13 | 14 | #[cfg(target_arch = "x86")] 15 | fn KeQuerySystemTime(CurrentTime: *mut SYSTEMTIME); 16 | #[cfg(target_arch = "x86")] 17 | fn KeQueryTickCount(TickCount: *mut i64); 18 | 19 | /// Converts a GMT system time value to the local system time for the current time zone. 20 | pub fn ExSystemTimeToLocalTime(SystemTime: *const SYSTEMTIME, LocalTime: *mut SYSTEMTIME); 21 | } 22 | 23 | 24 | /// Obtains the current system time. 25 | #[cfg(target_arch = "x86")] 26 | pub fn QuerySystemTime() -> SYSTEMTIME { 27 | let mut t = 0i64; 28 | unsafe { KeQuerySystemTime(&mut t) }; 29 | return t; 30 | } 31 | 32 | /// Obtains the current system time. 33 | #[cfg(target_arch = "x86_64")] 34 | pub fn QuerySystemTime() -> SYSTEMTIME { 35 | let shared = KUSER_SHARED_DATA::get(); 36 | SYSTEMTIME::from(shared.SystemTime) 37 | } 38 | 39 | 40 | /// A count of the interval timer interrupts that have occurred since the system was booted. 41 | #[cfg(target_arch = "x86")] 42 | pub fn QueryTickCount() -> i64 { 43 | let mut t = 0i64; 44 | unsafe { KeQueryTickCount(&mut t) }; 45 | return t; 46 | } 47 | 48 | 49 | /// A count of the interval timer interrupts that have occurred since the system was booted. 50 | #[cfg(target_arch = "x86_64")] 51 | pub fn QueryTickCount() -> i64 { 52 | let shared = KUSER_SHARED_DATA::get(); 53 | SYSTEMTIME::from(shared.TickCount) 54 | } 55 | --------------------------------------------------------------------------------