aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpravic <[email protected]>2016-04-12 16:39:37 +0300
committerpravic <[email protected]>2016-04-12 16:39:37 +0300
commit28ff216899e95a6a9756bcbe580f28ed8ce61228 (patch)
treebbf00e3c5f3b440db5ddb3f86b6d3a893349cee0
parentgit ignore (diff)
downloadwinapi-kmd-rs-28ff216899e95a6a9756bcbe580f28ed8ce61228.tar.xz
winapi-kmd-rs-28ff216899e95a6a9756bcbe580f28ed8ce61228.zip
Windows Kernel-Mode library
-rw-r--r--Cargo.toml27
-rw-r--r--README.md2
-rw-r--r--src/alloc/Cargo.toml15
-rw-r--r--src/alloc/alloc.rs77
-rw-r--r--src/alloc/pool.rs13
-rw-r--r--src/basedef.rs91
-rw-r--r--src/crt.rs86
-rw-r--r--src/debug.rs46
-rw-r--r--src/device_object.rs99
-rw-r--r--src/dpc.rs41
-rw-r--r--src/driver_object.rs34
-rw-r--r--src/event.rs31
-rw-r--r--src/file_object.rs15
-rw-r--r--src/irp.rs184
-rw-r--r--src/irql.rs61
-rw-r--r--src/lang.rs7
-rw-r--r--src/lib.rs55
-rw-r--r--src/macros.rs34
-rw-r--r--src/object.rs44
-rw-r--r--src/pool.rs42
-rw-r--r--src/rtl.rs11
-rw-r--r--src/status.rs59
-rw-r--r--src/string.rs95
-rw-r--r--src/thread.rs0
-rw-r--r--src/time.rs26
-rw-r--r--src/types.rs1
26 files changed, 1196 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..65634df
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "winapi-km"
+version = "0.1.0"
+description = "Windows Kernel Mode support library."
+
+authors = ["pravic <[email protected]>"]
+readme = "README.md"
+license = "MIT"
+
+# libc = { version = "*", default_features = false }
+
+[lib]
+name = "km"
+crate-type = ["rlib"]
+
+[dependencies]
+core = { path= "../libcore", version="*" }
+alloc_system = { path="src/alloc" }
+collections = { path = "../libcollections" }
+
+[profile.release]
+opt-level = 3
+debug = true
+rpath = false
+lto = true
+debug-assertions = false
+codegen-units = 4
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d8361cf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# Windows Kernel-Mode Drivers written in Rust
+
diff --git a/src/alloc/Cargo.toml b/src/alloc/Cargo.toml
new file mode 100644
index 0000000..2c7f4b8
--- /dev/null
+++ b/src/alloc/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "alloc_system"
+version = "0.1.0"
+description = "Windows Kernel Mode support library."
+
+authors = ["pravic <[email protected]>"]
+license = "MIT"
+
+[lib]
+name = "alloc_system"
+path = "alloc.rs"
+test = false
+
+[dependencies]
+core = { path= "../../../libcore" }
diff --git a/src/alloc/alloc.rs b/src/alloc/alloc.rs
new file mode 100644
index 0000000..963c3e3
--- /dev/null
+++ b/src/alloc/alloc.rs
@@ -0,0 +1,77 @@
+//! Kernel Mode Allocator
+
+// The compiler needs to be instructed that this crate is an allocator in order
+// to realize that when this is linked in another allocator like jemalloc should
+// not be linked in
+#![feature(allocator)]
+#![allocator]
+
+// Allocators are not allowed to depend on the standard library which in turn
+// requires an allocator in order to avoid circular dependencies. This crate,
+// however, can use all of libcore.
+#![no_std]
+
+#![crate_name = "alloc_system"]
+#![crate_type = "rlib"]
+
+mod pool;
+
+// Listed below are the five allocation functions currently required by custom
+// allocators. Their signatures and symbol names are not currently typechecked
+// by the compiler, but this is a future extension and are required to match
+// what is found below.
+//
+// Note that the standard `malloc` and `realloc` functions do not provide a way
+// to communicate alignment so this implementation would need to be improved
+// with respect to alignment in that aspect.
+
+const KMRS_TAG: u32 = 0x4B4D5253; // 'KMRS'
+use pool::{ExAllocatePoolWithTag, ExFreePoolWithTag, POOL_TYPE};
+
+extern "C"
+{
+ // from ntoskrnl
+ pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
+}
+
+#[no_mangle]
+pub extern "C" fn __rust_allocate(size: usize, _align: usize) -> *mut u8
+{
+ unsafe { ExAllocatePoolWithTag(POOL_TYPE::PagedPool, size, KMRS_TAG) }
+}
+
+#[no_mangle]
+pub extern "C" fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize)
+{
+ unsafe { ExFreePoolWithTag(ptr, KMRS_TAG) };
+}
+
+#[no_mangle]
+pub extern "C" fn __rust_reallocate(old: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8
+{
+ unsafe {
+ // http://en.cppreference.com/w/c/memory/realloc
+ let minsize = if size < old_size { size } else { old_size };
+ let new = __rust_allocate(size, align);
+ if new.is_null() {
+ return new;
+ }
+ if !old.is_null() && old_size > 0 {
+ memcpy(new, old, minsize);
+ __rust_deallocate(old, old_size, align);
+ }
+ return new;
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize, _align: usize) -> usize
+{
+ old_size // this api is not supported
+}
+
+#[no_mangle]
+pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize
+{
+ size
+}
diff --git a/src/alloc/pool.rs b/src/alloc/pool.rs
new file mode 100644
index 0000000..5b120ac
--- /dev/null
+++ b/src/alloc/pool.rs
@@ -0,0 +1,13 @@
+#[repr(C)]
+pub enum POOL_TYPE
+{
+ PagedPool,
+}
+
+pub type PVOID = *mut u8;
+
+extern "system"
+{
+ pub fn ExAllocatePoolWithTag(PoolType: POOL_TYPE, NumberOfBytes: usize, Tag: u32) -> PVOID;
+ pub fn ExFreePoolWithTag(P: PVOID, Tag: u32);
+}
diff --git a/src/basedef.rs b/src/basedef.rs
new file mode 100644
index 0000000..8638b85
--- /dev/null
+++ b/src/basedef.rs
@@ -0,0 +1,91 @@
+//! Kernel-Mode Types.
+
+use ::KIRQL;
+
+
+// Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable
+// more optimization opportunities around it recognizing things like
+// malloc/free.
+#[repr(u8)]
+#[doc(hidden)]
+pub enum km_void {
+ // Two dummy variants so the #[repr] attribute can be used.
+ #[doc(hidden)]
+ __variant1,
+ #[doc(hidden)]
+ __variant2,
+}
+
+pub type VOID = km_void;
+pub type PVOID = *mut VOID;
+pub type PCVOID = *const VOID;
+
+
+pub type PETHREAD = PVOID;
+pub type PIO_APC_ROUTINE = Option<extern "system" fn (ApcContext: PCVOID, IoStatusBlock: *const IO_STATUS_BLOCK, Reserved: u32)>;
+
+
+extern "system"
+{
+ pub fn KeGetCurrentIrql() -> KIRQL;
+ pub fn KeRaiseIrqlToDpcLevel() -> KIRQL;
+ pub fn KfLowerIrql(NewIrql: KIRQL) -> KIRQL;
+ pub fn KfRaiseIrql(NewIrql: KIRQL) -> KIRQL;
+}
+
+
+/// Doubly linked list structure.
+#[repr(C)]
+pub struct LIST_ENTRY
+{
+ pub next: *mut LIST_ENTRY,
+ pub prev: *mut LIST_ENTRY,
+}
+
+/// Spin Lock.
+#[repr(C)]
+pub struct KSPIN_LOCK
+{
+ pub lock: usize,
+}
+
+/// Common dispatcher object header.
+#[repr(C)]
+pub struct DISPATCHER_HEADER
+{
+ pub Type: u8,
+ pub Absolute: u8,
+ pub Size: u8,
+ pub Inserted: u8,
+ pub SignalState: i32,
+ pub WaitListHead: LIST_ENTRY,
+}
+
+/// An I/O status block.
+#[repr(C)]
+pub struct IO_STATUS_BLOCK
+{
+ pub Status: ::NTSTATUS,
+ pub Information: usize,
+}
+
+pub type PIO_STATUS_BLOCK = *mut IO_STATUS_BLOCK;
+
+
+/// Processor modes.
+#[repr(C)]
+pub enum KPROCESSOR_MODE
+{
+ KernelMode,
+ UserMode,
+}
+
+/// I/O Request priority.
+pub mod IO_PRIORITY {
+ /// I/O Request priority type.
+ pub type KPRIORITY_BOOST = u8;
+
+ pub const IO_NO_INCREMENT: KPRIORITY_BOOST = 0;
+ pub const IO_DISK_INCREMENT: KPRIORITY_BOOST = 1;
+ pub const EVENT_INCREMENT: KPRIORITY_BOOST = 1;
+}
diff --git a/src/crt.rs b/src/crt.rs
new file mode 100644
index 0000000..ad316e2
--- /dev/null
+++ b/src/crt.rs
@@ -0,0 +1,86 @@
+//! C runtime library.
+//!
+//! Functions imported from `ntoskrnl.exe`.
+
+extern "C"
+{
+ pub fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
+ pub fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
+
+ pub fn strlen(s: *const u8) -> usize;
+ pub fn strcmp(s1: *const u8, s2: *const u8) -> i32;
+ pub fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8;
+ pub fn strcat(dest: *mut u8, src: *const u8) -> *mut u8;
+ pub fn strncpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
+
+ pub fn wcslen(s: *const u16) -> usize;
+ pub fn wcscpy(dest: *mut u16, src: *const u16) -> *mut u16;
+ pub fn wcsncpy(dest: *mut u16, src: *const u16, n: usize) -> *mut u16;
+}
+
+
+#[no_mangle]
+#[allow(non_upper_case_globals)]
+#[cfg(target_arch="x86")]
+#[doc(hidden)]
+pub static __security_cookie: usize = 0xBB40E64E;
+
+#[no_mangle]
+#[allow(non_upper_case_globals)]
+#[cfg(target_arch="x86_64")]
+#[doc(hidden)]
+pub static __security_cookie: usize = 0x00002B992DDFA232;
+
+
+#[doc(hidden)]
+pub mod rust_intrinsics
+{
+ // Idk why, but linker cannot find `_memcmp` for llvm intrinsics. So lets make forward one.
+ #[no_mangle]
+ pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
+ return ::crt::memcmp(s1, s2, n);
+ }
+
+ // ported from compiler-rt
+ #[no_mangle]
+ pub unsafe extern fn __mulodi4(a: i64, b: i64, overflow: &mut i32) -> i64 {
+ const N: i32 = 64;
+ const MIN: i64 = 1 << (N-1);
+ const MAX: i64 = !MIN;
+ *overflow = 0;
+
+ let result = a * b;
+ if a == MIN {
+ if b != 0 && b != 1 {
+ *overflow = 1;
+ }
+ return result;
+ }
+
+ if b == MIN {
+ if a != 0 && a != 1 {
+ *overflow = 1;
+ }
+ return result;
+ }
+
+ let sa = a >> (N-1);
+ let sb = b >> (N-1);
+ let abs_a = (a ^ sa) - sa;
+ let abs_b = (b ^ sb) - sb;
+
+ if abs_a < 2 || abs_b < 2 {
+ return result;
+ }
+ if sa == sb {
+ if abs_a > MAX / abs_b {
+ *overflow = 1;
+ }
+ } else {
+ if abs_a > MIN / -abs_b {
+ *overflow = 1;
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/debug.rs b/src/debug.rs
new file mode 100644
index 0000000..66e46ab
--- /dev/null
+++ b/src/debug.rs
@@ -0,0 +1,46 @@
+//! Debugger support.
+
+use ::status::NTSTATUS;
+
+extern "C"
+{
+ /// `DbgPrint` routine sends a message to the kernel debugger.
+ pub fn DbgPrint(Format: *const u8, ...) -> NTSTATUS;
+ /// The `DbgPrintEx` routine sends a string to the kernel debugger if certain conditions are met.
+ pub fn DbgPrintEx(ComponentId: u32, Level: u32, Format: *const u8, ...) -> NTSTATUS;
+}
+
+extern "system"
+{
+ /// Breaks into the kernel debugger.
+ pub fn DbgBreakPoint();
+ /// Breaks into the kernel debugger and sends the value of `Status` to the debugger.
+ pub fn DbgBreakPointWithStatus(Status: NTSTATUS);
+}
+
+/// `DbgPrintEx` Message severity.
+#[repr(C)]
+pub enum DPFLTR_LEVEL {
+ ERROR = 0,
+ WARNING,
+ TRACE,
+ INFO,
+}
+
+/// `DbgPrintEx` Component name.
+#[repr(C)]
+pub enum DPFLTR_ID {
+ SYSTEM = 0,
+ SMSS,
+ SETUP,
+ NTFS,
+ // ...
+ IHVDRIVER = 77,
+ IHVVIDEO,
+ IHVAUDIO,
+ IHVNETWORK,
+ IHVSTREAMING,
+ IHVBUS,
+
+ DEFAULT = 99,
+}
diff --git a/src/device_object.rs b/src/device_object.rs
new file mode 100644
index 0000000..f4cbf39
--- /dev/null
+++ b/src/device_object.rs
@@ -0,0 +1,99 @@
+//! Device Object.
+
+use ::{NTSTATUS, UNICODE_STRING};
+use ::driver_object::DRIVER_OBJECT;
+use ::irp::{IRP, PIRP};
+use ::dpc::KDPC;
+use ::event::KEVENT;
+use ::object::*;
+use ::PVOID;
+
+extern "system"
+{
+ pub fn IoCreateDevice(DriverObject: &mut DRIVER_OBJECT, DeviceExtensionSize: u32, DeviceName: *const UNICODE_STRING,
+ DeviceType: u32, DeviceCharacteristics: u32, Exclusive: bool, DeviceObject: *mut*mut DEVICE_OBJECT) -> NTSTATUS;
+
+ pub fn IoDeleteDevice(DeviceObject: &mut DEVICE_OBJECT) -> NTSTATUS;
+ pub fn IoCreateSymbolicLink(SymbolicLinkName: &UNICODE_STRING, DeviceName: &UNICODE_STRING) -> NTSTATUS;
+ pub fn IoDeleteSymbolicLink(SymbolicLinkName: &UNICODE_STRING) -> NTSTATUS;
+}
+
+/// Device object flags.
+#[repr(C)]
+pub enum DEVICE_FLAGS {
+ NONE = 0,
+ DO_VERIFY_VOLUME = 0x00000002,
+ DO_BUFFERED_IO = 0x00000004,
+ DO_EXCLUSIVE = 0x00000008,
+ DO_DIRECT_IO = 0x00000010,
+ DO_MAP_IO_BUFFER = 0x00000020,
+ DO_DEVICE_HAS_NAME = 0x00000040,
+ DO_DEVICE_INITIALIZING = 0x00000080,
+ DO_SYSTEM_BOOT_PARTITION = 0x00000100,
+ DO_LONG_TERM_REQUESTS = 0x00000200,
+ DO_NEVER_LAST_DEVICE = 0x00000400,
+ DO_SHUTDOWN_REGISTERED = 0x00000800,
+ DO_BUS_ENUMERATED_DEVICE = 0x00001000,
+ DO_POWER_PAGABLE = 0x00002000,
+ DO_POWER_INRUSH = 0x00004000,
+ DO_POWER_NOOP = 0x00008000,
+ DO_LOW_PRIORITY_FILESYSTEM = 0x00010000,
+ DO_XIP = 0x00020000
+}
+
+/// The `DEVICE_OBJECT` structure is used by the operating system to represent a device object.
+#[repr(C)]
+pub struct DEVICE_OBJECT
+{
+ pub Type: u16,
+ pub Size: u16,
+ pub ReferenceCount: i32,
+ pub DriverObject: *const DRIVER_OBJECT,
+ pub NextDevice: *mut DEVICE_OBJECT,
+ pub AttachedDevice: *mut DEVICE_OBJECT,
+ pub CurrentIrp: *const IRP,
+ pub Timer: *mut u8,
+ pub Flags: u32,
+ pub Characteristics: u32,
+ pub Vpb: *mut u8,
+ pub DeviceExtension: *mut u8,
+ pub DeviceType: u32,
+ pub StackSize: u8,
+ pub Queue: *mut WAIT_CONTEXT_BLOCK,
+ pub AlignmentRequirement: u32,
+ pub DeviceQueue: KDEVICE_QUEUE,
+ pub Dpc: KDPC,
+ pub ActiveThreadCount: u32,
+ pub SecurityDescriptor: *const u8,
+ pub DeviceLock: KEVENT,
+ pub SectorSize: u16,
+ pub Spare1: u16,
+ pub DeviceObjectExtension: *mut DEVOBJ_EXTENSION,
+ pub Reserved: *const u8,
+}
+
+/// Device object extension structure.
+#[repr(C)]
+pub struct DEVOBJ_EXTENSION
+{
+ Type: u16,
+ Size: u16,
+ DeviceObject: *mut DEVICE_OBJECT,
+ PowerFlags: u32,
+ Dope: *mut u8,
+ ExtensionFlags: u32,
+ DeviceNode: *mut u8,
+ AttachedTo: *mut DEVICE_OBJECT,
+ StartIoCount: i32,
+ StartIoKey: i32,
+ StartIoFlags: u32,
+ Vpb: *mut u8,
+}
+
+pub type PDEVICE_OBJECT = *mut DEVICE_OBJECT;
+
+pub type PDRIVER_CANCEL = Option<extern "system" fn (DeviceObject: PDEVICE_OBJECT, Irp: PIRP)>;
+
+pub type PDRIVER_DISPATCH = Option<extern "system" fn (DeviceObject: &mut DEVICE_OBJECT, Irp: &mut IRP) -> NTSTATUS>;
+
+pub type PIO_COMPLETION_ROUTINE = Option<extern "system" fn (DeviceObject: PDEVICE_OBJECT, Irp: PIRP, Context: PVOID) -> NTSTATUS>;
diff --git a/src/dpc.rs b/src/dpc.rs
new file mode 100644
index 0000000..de37e1a
--- /dev/null
+++ b/src/dpc.rs
@@ -0,0 +1,41 @@
+//! Deferred Procedure Calls (DPC).
+
+use ::basedef::*;
+
+extern "system"
+{
+ pub fn KeInitializeDpc(Dpc: *mut KDPC, DeferredRoutine: PDEFERRED_ROUTINE, DeferredContext: *mut u8);
+ pub fn KeInsertQueueDpc(Dpc: *mut KDPC, SystemArgument1: *const u8, SystemArgument2: *const u8) -> bool;
+ pub fn KeRemoveQueueDpc(Dpc: *mut KDPC) -> bool;
+ pub fn KeFlushQueuedDpcs();
+ pub fn KeGenericCallDpc(DeferredRoutine: PDEFERRED_ROUTINE, DeferredContext: *mut u8);
+}
+
+pub type PDEFERRED_ROUTINE = extern "system" fn (Dpc: *const KDPC, DeferredContext: *mut u8, SystemArgument1: *const u8, SystemArgument2: *const u8);
+
+/// Deferred Procedure Call object.
+#[repr(C)]
+pub struct KDPC
+{
+ Type: u8,
+ Number: u8,
+ Importance: u8,
+
+ DpcListEntry: LIST_ENTRY,
+ DeferredRoutine: PDEFERRED_ROUTINE,
+ DeferredContext: *mut u8,
+ SystemArgument1: *mut u8,
+ SystemArgument2: *mut u8,
+
+ DpcData: *mut KDPC_DATA,
+}
+
+/// DPC data structure definition.
+#[repr(C)]
+pub struct KDPC_DATA
+{
+ DpcListHead: LIST_ENTRY,
+ DpcLock: KSPIN_LOCK,
+ DpcQueueDepth: i32,
+ DpcCount: u32,
+}
diff --git a/src/driver_object.rs b/src/driver_object.rs
new file mode 100644
index 0000000..82a87e7
--- /dev/null
+++ b/src/driver_object.rs
@@ -0,0 +1,34 @@
+//! Driver Object.
+
+use ::{NTSTATUS, UNICODE_STRING};
+use ::device_object::*;
+use ::irp::IRP;
+
+
+pub type PDRIVER_INITIALIZE = Option<extern "system" fn (_self: &mut DRIVER_OBJECT, &UNICODE_STRING) -> NTSTATUS>;
+pub type PDRIVER_STARTIO = Option<extern "system" fn (_self: &mut DRIVER_OBJECT, &IRP)>;
+pub type PDRIVER_UNLOAD = Option<extern "system" fn (_self: &mut DRIVER_OBJECT)>;
+
+
+/// Represents the image of a loaded kernel-mode driver.
+#[repr(C)]
+pub struct DRIVER_OBJECT
+{
+ pub Type: u16,
+ pub Size: u16,
+ pub DeviceObject: *mut DEVICE_OBJECT,
+ pub Flags: u32,
+ pub DriverStart: *const u8,
+ pub DriverSize: u32,
+ pub DriverSection: *const u8,
+ pub DriverExtension: *mut u8,
+ pub DriverName: UNICODE_STRING,
+ pub HardwareDatabase: *const UNICODE_STRING,
+ pub FastIoDispatch: *mut u8,
+ pub DriverInit: PDRIVER_INITIALIZE,
+ pub DriverStartIo: PDRIVER_STARTIO,
+ /// The entry point for the driver's Unload routine, if any.
+ pub DriverUnload: PDRIVER_UNLOAD,
+ /// A dispatch table consisting of an array of entry points for the driver's `DispatchXxx` routines.
+ pub MajorFunction: [PDRIVER_DISPATCH; 28],
+}
diff --git a/src/event.rs b/src/event.rs
new file mode 100644
index 0000000..2f00bb1
--- /dev/null
+++ b/src/event.rs
@@ -0,0 +1,31 @@
+//! Event Objects.
+
+use ::basedef::DISPATCHER_HEADER;
+
+extern "system"
+{
+ pub fn KeInitializeEvent(Event: PKEVENT, Type: EVENT_TYPE, State: bool);
+ pub fn KeSetEvent(Event: PKEVENT, Increment: i32, Wait: bool) -> i32;
+ pub fn KeReadStateEvent(Event: PKEVENT) -> i32;
+ pub fn KeResetEvent(Event: PKEVENT) -> i32;
+ pub fn KeClearEvent(Event: PKEVENT);
+}
+
+pub type PKEVENT = *mut KEVENT;
+
+/// Specifies the event type.
+#[repr(C)]
+pub enum EVENT_TYPE
+{
+ /// Manual-reset event.
+ NotificationEvent = 0,
+ /// Auto-clearing event.
+ SynchronizationEvent,
+}
+
+/// Event object.
+#[repr(C)]
+pub struct KEVENT
+{
+ Header: DISPATCHER_HEADER,
+}
diff --git a/src/file_object.rs b/src/file_object.rs
new file mode 100644
index 0000000..b0d24a2
--- /dev/null
+++ b/src/file_object.rs
@@ -0,0 +1,15 @@
+//! File Object.
+
+use ::device_object::PDEVICE_OBJECT;
+
+pub type PFILE_OBJECT = *mut FILE_OBJECT;
+
+/// The `FILE_OBJECT` structure is used by the system to represent a file object.
+#[repr(C)]
+pub struct FILE_OBJECT
+{
+ Type: u16,
+ Size: u16,
+ DeviceObject: PDEVICE_OBJECT,
+ // ...
+}
diff --git a/src/irp.rs b/src/irp.rs
new file mode 100644
index 0000000..8d1b390
--- /dev/null
+++ b/src/irp.rs
@@ -0,0 +1,184 @@
+//! I/O request packets (IRP).
+
+use ::NTSTATUS;
+use ::basedef::*;
+use ::event::PKEVENT;
+use ::device_object::*;
+use ::file_object::*;
+use ::basedef::IO_PRIORITY::*;
+use ::KIRQL;
+
+
+pub type PIRP = *mut IRP;
+pub type PIO_STACK_LOCATION = *mut IO_STACK_LOCATION;
+
+// NOTE: fastcall is broken: https://github.com/rust-lang/rust/issues/18086
+//extern "fastcall" { fn IofCompleteRequest(Irp: PIRP, PriorityBoost: KPRIORITY_BOOST); }
+extern "system"
+{
+ fn IoCompleteRequest(Irp: PIRP, PriorityBoost: KPRIORITY_BOOST);
+
+ // unfortunately following are macro
+ // fn IoGetCurrentIrpStackLocation(Irp: PIRP) -> PIO_STACK_LOCATION;
+ // fn IoGetNextIrpStackLocation(Irp: PIRP) -> PIO_STACK_LOCATION;
+ // fn IoSetNextIrpStackLocation(Irp: PIRP);
+ // fn IoSkipCurrentIrpStackLocation(Irp: PIRP);
+}
+
+/// `IRP` Major Function Codes.
+#[repr(u8)]
+pub enum IRP_MJ
+{
+ CREATE,
+ CREATE_NAMED_PIPE,
+ CLOSE,
+ READ,
+ WRITE,
+ QUERY_INFORMATION,
+ SET_INFORMATION,
+ QUERY_EA,
+ SET_EA,
+ FLUSH_BUFFERS,
+ QUERY_VOLUME_INFORMATION,
+ SET_VOLUME_INFORMATION,
+ DIRECTORY_CONTROL,
+ FILE_SYSTEM_CONTROL,
+ DEVICE_CONTROL,
+ INTERNAL_DEVICE_CONTROL,
+ SHUTDOWN,
+ LOCK_CONTROL,
+ CLEANUP,
+ CREATE_MAILSLOT,
+ QUERY_SECURITY,
+ SET_SECURITY,
+ POWER,
+ SYSTEM_CONTROL,
+ DEVICE_CHANGE,
+ QUERY_QUOTA,
+ SET_QUOTA,
+ PNP,
+ MAXIMUM_FUNCTION,
+}
+
+/// The `IRP` structure is a partial opaque structure that represents an I/O request packet.
+#[repr(C)]
+pub struct IRP
+{
+ pub Type: u16,
+ pub Size: u16,
+ /// Pointer to an `MDL` describing a user buffer, if the driver is using direct I/O.
+ pub MdlAddress: PVOID,
+ /// Flags word - used to remember various flags.
+ pub Flags: u32,
+ /// Pointer to a system-space buffer if the driver is using buffered I/O.
+ pub SystemBuffer: PVOID,
+ pub ThreadListEntry: LIST_ENTRY,
+ /// I/O status - final status of operation.
+ pub IoStatus: IO_STATUS_BLOCK,
+ /// Indicates the execution mode of the original requester of the operation.
+ pub RequestorMode: KPROCESSOR_MODE,
+ /// If set to `TRUE`, a driver has marked the IRP pending.
+ pub PendingReturned: bool,
+ /// Stack state information.
+ pub StackCount: i8,
+ /// Stack state information.
+ pub CurrentLocation: i8,
+ /// If set to `TRUE`, the IRP either is or should be canceled.
+ pub Cancel: bool,
+ /// Irql at which the cancel spinlock was acquired.
+ pub CancelIrql: KIRQL,
+ pub ApcEnvironment: u8,
+ /// Allocation control flags.
+ pub AllocationFlags: u8,
+ /// User parameters.
+ pub UserIosb: PIO_STATUS_BLOCK,
+ pub UserEvent: PKEVENT,
+
+ // union {
+ pub UserApcRoutine: PIO_APC_ROUTINE,
+ pub UserApcContext: PVOID,
+ // } Overlay
+
+ /// Contains the entry point for a driver-supplied `Cancel` routine to be called if the IRP is canceled.
+ pub CancelRoutine: PDRIVER_CANCEL,
+ /// Contains the address of an output buffer for `IRP_MJ_DEVICE_CONTROL`.
+ pub UserBuffer: PVOID,
+
+ /// Kernel structures.
+ // union {
+ pub Overlay: _IRP_OVERLAY,
+ // } Tail
+}
+
+/// Kernel structures for IRP.
+#[repr(C)]
+pub struct _IRP_OVERLAY
+{
+ pub DriverContext: [PVOID; 4],
+ pub Thread: PETHREAD,
+ pub AuxiliaryBuffer: PVOID,
+ pub ListEntry: LIST_ENTRY,
+ /// Current stack location.
+ pub CurrentStackLocation: PIO_STACK_LOCATION,
+ pub OriginalFileObject: PFILE_OBJECT,
+}
+
+/// I/O Stack Locations.
+#[repr(C)]
+pub struct IO_STACK_LOCATION
+{
+ /// The IRP major function code indicating the type of I/O operation to be performed.
+ pub MajorFunction: u8,
+ /// A subfunction code for `MajorFunction`.
+ pub MinorFunction: u8,
+ /// Request-type-specific values (see [DEVICE_FLAGS](../device_object/enum.DEVICE_FLAGS.html)).
+ pub Flags: u8,
+ pub Control: u8,
+
+ /// A union that depends on the major and minor IRP function code values
+ /// contained in `MajorFunction` and `MinorFunction`.
+ // union Parameters
+ pub Parameters: [PVOID; 4],
+
+ /// A pointer to the driver-created `DEVICE_OBJECT` structure
+ /// representing the target physical, logical, or virtual device for which this driver is to handle the IRP.
+ pub DeviceObject: PDEVICE_OBJECT,
+ /// A pointer to a `FILE_OBJECT` structure that represents the file object, if any, that is associated with `DeviceObject` pointer.
+ pub FileObject: PFILE_OBJECT,
+ /// The following routine is invoked depending on the flags in the above `Flags` field.
+ pub CompletionRoutine: PIO_COMPLETION_ROUTINE,
+ /// The following is used to store the address of the context parameter that should be passed to the `CompletionRoutine`.
+ pub Context: PVOID,
+}
+
+/// Parameters for `IRP_MJ_READ`.
+#[repr(C)]
+pub struct _IO_STACK_LOCATION_READ
+{
+ pub Length: u32,
+ pub Key: u32,
+ pub ByteOffset: i64,
+}
+
+
+impl IRP {
+ /// Returns a pointer to the caller's stack location in the given `IRP`.
+ pub fn get_current_stack_location(&mut self) -> &mut IO_STACK_LOCATION {
+ unsafe { &mut *self.Overlay.CurrentStackLocation }
+ }
+
+ /// Indicates that the caller has completed all processing for a given I/O request
+ /// and is returning the given IRP to the I/O manager.
+ pub fn complete_request(&mut self, Status: NTSTATUS) -> NTSTATUS {
+ self.IoStatus.Status = Status;
+ unsafe { IoCompleteRequest(self, IO_NO_INCREMENT) };
+ return Status;
+ }
+}
+
+impl IO_STACK_LOCATION {
+ /// Access parameters for `IRP_MJ_READ`.
+ pub fn ParametersRead(&mut self) -> &mut _IO_STACK_LOCATION_READ {
+ unsafe { ::core::mem::transmute(&mut self.Parameters) }
+ }
+}
diff --git a/src/irql.rs b/src/irql.rs
new file mode 100644
index 0000000..e6e60bb
--- /dev/null
+++ b/src/irql.rs
@@ -0,0 +1,61 @@
+//! Interrupt Request Level (IRQL).
+
+/// IRQL type.
+pub type KIRQL = u8;
+
+/// Passive release level, no interrupt vectors are masked.
+pub const PASSIVE_LEVEL: KIRQL = 0;
+/// The lowest IRQL level, no interrupt vectors are masked.
+pub const LOW_LEVEL: KIRQL = 0;
+/// APC interrupt level.
+pub const APC_LEVEL: KIRQL = 1;
+/// Dispatcher level
+pub const DISPATCH_LEVEL: KIRQL = 2;
+
+/// Timer used for profiling.
+#[cfg(target_arch = "x86")]
+pub const PROFILE_LEVEL: KIRQL = 27;
+
+/// Interval clock level.
+#[cfg(target_arch = "x86")]
+pub const CLOCK_LEVEL: KIRQL = 28;
+
+/// Interprocessor interrupt level.
+#[cfg(target_arch = "x86")]
+pub const IPI_LEVEL: KIRQL = 29;
+
+/// Power failure level.
+#[cfg(target_arch = "x86")]
+pub const POWER_LEVEL: KIRQL = 30;
+
+/// Highest interrupt level.
+#[cfg(target_arch = "x86")]
+pub const HIGH_LEVEL: KIRQL = 31;
+
+/// Synchronization level.
+#[cfg(target_arch = "x86")]
+pub const SYNCH_LEVEL: KIRQL = 29 - 2;
+
+/// Interval clock level.
+#[cfg(target_arch = "x86_64")]
+pub const CLOCK_LEVEL: KIRQL = 13;
+
+/// Interprocessor interrupt level.
+#[cfg(target_arch = "x86_64")]
+pub const IPI_LEVEL: KIRQL = 14;
+
+/// Power failure level.
+#[cfg(target_arch = "x86_64")]
+pub const POWER_LEVEL: KIRQL = 15;
+
+/// Timer used for profiling.
+#[cfg(target_arch = "x86_64")]
+pub const PROFILE_LEVEL: KIRQL = 16;
+
+/// Highest interrupt level.
+#[cfg(target_arch = "x86_64")]
+pub const HIGH_LEVEL: KIRQL = 17;
+
+/// Synchronization level.
+#[cfg(target_arch = "x86_64")]
+pub const SYNCH_LEVEL: KIRQL = 14- 2;
diff --git a/src/lang.rs b/src/lang.rs
new file mode 100644
index 0000000..5d6bd2b
--- /dev/null
+++ b/src/lang.rs
@@ -0,0 +1,7 @@
+#[lang = "eh_personality"] extern fn eh_personality() {}
+#[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
+
+#[lang = "panic_fmt"] extern fn panic_fmt() -> ! {
+ KdPrint!("panic_fmt() -> !");
+ loop{}
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..aaad51d
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,55 @@
+//! Windows Kernel Mode library.
+
+#![feature(lang_items)]
+#![feature(on_unimplemented, fundamental)]
+#![feature(no_core)]
+
+#![no_std]
+#![allow(bad_style)]
+
+
+#[macro_use] pub mod macros;
+
+mod lang;
+
+pub mod status;
+
+pub mod basedef;
+pub mod crt;
+pub mod debug;
+pub mod device_object;
+pub mod dpc;
+pub mod driver_object;
+pub mod event;
+pub mod file_object;
+pub mod irp;
+pub mod irql;
+pub mod object;
+pub mod pool;
+pub mod rtl;
+pub mod string;
+pub mod time;
+
+#[doc(hidden)]
+pub use irql::KIRQL;
+
+#[doc(hidden)]
+pub use status::*;
+
+#[doc(hidden)]
+pub use debug::DbgPrint;
+
+#[doc(hidden)]
+pub use string::*;
+
+#[doc(hidden)]
+pub use driver_object::*;
+
+#[doc(hidden)]
+pub use device_object::*;
+
+#[doc(hidden)]
+pub use irp::IRP;
+
+#[doc(hidden)]
+pub use basedef::{PVOID};
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..ba3b24d
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,34 @@
+//! Macros for Kernel-Mode drivers.
+
+/// Macro to send a message to the kernel debugger.
+///
+/// # Example
+///
+/// ```no_run
+/// KdPrint!("NTSTATUS is 0x%X\n", status);
+/// ```
+#[macro_export]
+macro_rules! KdPrint {
+ ($msg:expr $(, $arg:expr)*) => { unsafe { $crate::debug::DbgPrint( concat!($msg, "\0").as_ptr() $(, $arg )* )} };
+}
+
+/// Macro to send a message to the kernel debugger for unsafe blocks.
+///
+/// Used in `unsafe {}` blocks.
+#[macro_export]
+macro_rules! KdPrint_u {
+ ($msg:expr $(, $arg:expr)*) => { $crate::debug::DbgPrint( concat!($msg, "\0").as_ptr() $(, $arg )* ) };
+}
+
+#[macro_export]
+macro_rules! check_unsafe {
+ ($expr:expr) => {{
+ let st: $crate::status::Status = unsafe { $expr };
+ if st.is_err() {
+ KdPrint!("[km] error: status 0x%X\n", st);
+ return st;
+ } else {
+ st
+ }
+ }}
+}
diff --git a/src/object.rs b/src/object.rs
new file mode 100644
index 0000000..ab34aeb
--- /dev/null
+++ b/src/object.rs
@@ -0,0 +1,44 @@
+//! Kernel Objects.
+
+use ::basedef::*;
+use ::device_object::PDEVICE_OBJECT;
+use ::irp::IRP;
+
+
+#[repr(C)]
+pub struct WAIT_CONTEXT_BLOCK
+{
+ WaitQueueEntry: *mut KDEVICE_QUEUE_ENTRY,
+ DeviceRoutine: extern "system" fn (_obj: PDEVICE_OBJECT, _irp: *mut IRP, *mut u8, *mut u8) -> IO_ALLOCATION_ACTION,
+ DeviceContext: *mut u8,
+ NumberOfMapRegisters: u32,
+ DeviceObject: *mut u8,
+ CurrentIrp: *mut u8,
+ BufferChainingDpc: * mut u8,
+}
+
+#[repr(C)]
+pub enum IO_ALLOCATION_ACTION
+{
+ KeepObject = 0x01,
+ DeallocateObject = 0x02,
+ DeallocateObjectKeepRegisters = 0x03,
+}
+
+#[repr(C)]
+pub struct KDEVICE_QUEUE_ENTRY
+{
+ DeviceListEntry: LIST_ENTRY,
+ SortKey: u32,
+ Inserted: bool,
+}
+
+#[repr(C)]
+pub struct KDEVICE_QUEUE
+{
+ Type: u16,
+ Size: u16,
+ DeviceListHead: LIST_ENTRY,
+ Lock: KSPIN_LOCK,
+ Busy: bool,
+}
diff --git a/src/pool.rs b/src/pool.rs
new file mode 100644
index 0000000..31598d5
--- /dev/null
+++ b/src/pool.rs
@@ -0,0 +1,42 @@
+//! Kernel Mode pools.
+
+use ::PVOID;
+
+extern "system"
+{
+ /// Allocates pool memory of the specified type and tag.
+ pub fn ExAllocatePoolWithTag(PoolType: POOL_TYPE, NumberOfBytes: usize, Tag: u32) -> PVOID;
+ /// Deallocates a block of pool memory allocated with the specified tag.
+ pub fn ExFreePoolWithTag(P: PVOID, Tag: u32);
+
+ /// Allocates pool memory of the specified type.
+ pub fn ExAllocatePool(PoolType: POOL_TYPE, NumberOfBytes: usize) -> PVOID;
+ /// Deallocates a block of pool memory.
+ pub fn ExFreePool(P: PVOID);
+}
+
+
+/// Specifies the type of system memory to allocate.
+#[repr(C)]
+pub enum POOL_TYPE
+{
+ /// Nonpageable system memory, can be accessed from any IRQL.
+ NonPagedPool = 0,
+ /// Pageable system memory, can only be allocated and accessed at IRQL < DISPATCH_LEVEL.
+ PagedPool,
+ NonPagedPoolMustSucceed,
+ DontUseThisType,
+ /// Nonpaged pool, aligned on processor cache boundaries.
+ NonPagedPoolCacheAligned,
+ /// Paged pool, aligned on processor cache boundaries.
+ PagedPoolCacheAligned,
+ NonPagedPoolCacheAlignedMustS,
+ MaxPoolType,
+ NonPagedPoolSession = 32,
+ PagedPoolSession,
+ NonPagedPoolMustSucceedSession,
+ DontUseThisTypeSession,
+ NonPagedPoolCacheAlignedSession,
+ PagedPoolCacheAlignedSession,
+ NonPagedPoolCacheAlignedMustSSession,
+}
diff --git a/src/rtl.rs b/src/rtl.rs
new file mode 100644
index 0000000..eedcbe5
--- /dev/null
+++ b/src/rtl.rs
@@ -0,0 +1,11 @@
+//! NT runtime routines.
+
+extern "system"
+{
+ /// Returns a random number that was generated from a given `seed` value in the range `[0..MAXLONG-1]`.
+ pub fn RtlRandom(Seed: *mut u32) -> u32;
+ /// Returns a random number that was generated from a given `seed` value in the range `[0..MAXLONG-1]`.
+ pub fn RtlRandomEx(Seed: *mut u32) -> u32;
+ /// A simple uniform random number generator, based on D.H. Lehmer's 1948 alrogithm.
+ pub fn RtlUniform(Seed: *mut u32) -> u32;
+}
diff --git a/src/status.rs b/src/status.rs
new file mode 100644
index 0000000..aae9ec5
--- /dev/null
+++ b/src/status.rs
@@ -0,0 +1,59 @@
+//! NT Status codes.
+#![allow(non_camel_case_types)]
+#![allow(overflowing_literals)]
+
+/// NT Status type.
+pub type NTSTATUS = Status;
+
+/// A specialized `Result` type for NT operations.
+pub type Result<T> = ::core::result::Result<T, Status>;
+
+
+/// NT Status code.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub enum Status {
+ success = 0,
+ unsuccessful = 0xC0000001,
+}
+
+impl Status {
+ /// Evaluates to `true` if the `Status` is a success type (`0..0x3FFFFFFF`)
+ /// or an informational type (`0x40000000..0x7FFFFFFF`).
+ pub fn is_ok(&self) -> bool {
+ (*self as i32) >= 0
+ }
+ /// Status is a warning or error type.
+ pub fn is_err(&self) -> bool {
+ (*self as i32) < 0
+ }
+ /// Status is a success type.
+ pub fn is_success(&self) -> bool {
+ let c = *self as u32;
+ c > 0 && c < 0x3FFF_FFFF
+ }
+ /// Status is a information type.
+ pub fn is_information(&self) -> bool {
+ let c = *self as u32;
+ c > 0x4000_0000 && c < 0x7FFF_FFFF
+ }
+ /// Status is a warning type.
+ pub fn is_warning(&self) -> bool {
+ let c = *self as u32;
+ c > 0x8000_0000 && c < 0xBFFF_FFFF
+ }
+ /// Status is a error type.
+ pub fn is_error(&self) -> bool {
+ let c = *self as u32;
+ c > 0xC000_0000 && c < 0xFFFF_FFFF
+ }
+}
+
+/// Convert `Status` to `Result<()>`.
+pub fn check(st: Status) -> Result<()> {
+ if st.is_err() {
+ Err(st)
+ } else {
+ Ok(())
+ }
+}
diff --git a/src/string.rs b/src/string.rs
new file mode 100644
index 0000000..252dbe6
--- /dev/null
+++ b/src/string.rs
@@ -0,0 +1,95 @@
+//! Kernel mode string types.
+
+use ::NTSTATUS;
+
+/// NT native string types.
+pub trait NativeString {
+ /// Size of string in bytes.
+ fn size(&self) -> u16;
+ /// Size of buffer in bytes.
+ fn max_size(&self) -> u16;
+
+ /// Check is the string is empty.
+ fn is_empty(&self) -> bool {
+ self.size() == 0u16
+ }
+}
+
+/// A counted Unicode string.
+#[repr(C)]
+pub struct UNICODE_STRING
+{
+ /// The length in **bytes** of the string stored in `Buffer`.
+ pub Length: u16,
+ /// The length in **bytes** of `Buffer`.
+ pub MaximumLength: u16,
+ /// Pointer to a buffer used to contain a string of wide characters.
+ pub Buffer: *const u16,
+}
+
+/// A counted string used for ANSI strings.
+#[repr(C)]
+pub struct ANSI_STRING
+{
+ /// The length in *bytes* of the string stored in `Buffer`.
+ pub Length: u16,
+ /// The length in bytes of `Buffer`.
+ pub MaximumLength: u16,
+ /// Pointer to a buffer used to contain a string of characters.
+ pub Buffer: *const u8,
+}
+
+impl NativeString for UNICODE_STRING
+{
+ fn size(&self) -> u16 { self.Length }
+ fn max_size(&self) -> u16 { self.MaximumLength }
+}
+
+impl UNICODE_STRING
+{
+}
+
+/// Initializes a counted Unicode string.
+impl Default for UNICODE_STRING {
+ fn default() -> Self {
+ UNICODE_STRING { Length: 0, MaximumLength: 0, Buffer: ::core::ptr::null() }
+ }
+}
+
+impl<'a> From<&'a [u8]> for ANSI_STRING {
+ fn from(s: &'a [u8]) -> Self {
+ let len = s.len();
+ let n = if len > 0 && s[len-1] == 0 { len - 1 } else { len };
+ ANSI_STRING { Length: n as u16, MaximumLength: len as u16, Buffer: s.as_ptr() }
+ }
+}
+
+
+pub type AnsiString = ANSI_STRING;
+pub type UnicodeString = UNICODE_STRING;
+pub type CONST_UNICODE_STRING = UNICODE_STRING;
+pub type CONST_ANSI_STRING = ANSI_STRING;
+
+
+
+extern "system"
+{
+ pub fn RtlIntegerToUnicodeString(Value: u32, Base: u32, String: &mut UNICODE_STRING) -> NTSTATUS;
+ pub fn RtlInt64ToUnicodeString(Value: u64, Base: u32, String: &mut UNICODE_STRING) -> NTSTATUS;
+ pub fn RtlUnicodeStringToInteger(String: &CONST_UNICODE_STRING, Base: u32, Value: &mut u32) -> NTSTATUS;
+
+ pub fn RtlUnicodeStringToAnsiString(DestinationString: &mut ANSI_STRING, SourceString: &CONST_UNICODE_STRING, AllocateDestination: bool) -> NTSTATUS;
+ pub fn RtlUnicodeStringToAnsiSize(SourceString: &CONST_UNICODE_STRING) -> u32;
+
+ pub fn RtlAnsiStringToUnicodeString(DestinationString: &mut UNICODE_STRING, SourceString: &CONST_ANSI_STRING, AllocateDestination: bool) -> NTSTATUS;
+ pub fn RtlAnsiStringToUnicodeSize(SourceString: &CONST_ANSI_STRING) -> u32;
+
+ pub fn RtlCompareUnicodeString (String1: &CONST_UNICODE_STRING, String2: &CONST_UNICODE_STRING, CaseInSensitive: bool) -> i32;
+ pub fn RtlCompareString (String1: &CONST_ANSI_STRING, String2: &CONST_ANSI_STRING, CaseInSensitive: bool) -> i32;
+
+ pub fn RtlEqualUnicodeString(String1: &CONST_UNICODE_STRING, String2: &CONST_UNICODE_STRING) -> bool;
+ pub fn RtlEqualString(String1: &CONST_ANSI_STRING, String2: &CONST_ANSI_STRING) -> bool;
+
+ pub fn RtlFreeAnsiString(UnicodeString: &mut ANSI_STRING);
+ pub fn RtlFreeUnicodeString(UnicodeString: &mut UNICODE_STRING);
+}
diff --git a/src/thread.rs b/src/thread.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/thread.rs
diff --git a/src/time.rs b/src/time.rs
new file mode 100644
index 0000000..b4d0e99
--- /dev/null
+++ b/src/time.rs
@@ -0,0 +1,26 @@
+//! NT Time routines.
+
+/// System time is a count of 100-nanosecond intervals since January 1, 1601.
+pub type SYSTEMTIME = i64;
+
+extern "system"
+{
+ fn KeQuerySystemTime(CurrentTime: *mut SYSTEMTIME);
+ fn KeQueryTickCount(TickCount: *mut i64);
+ /// Converts a GMT system time value to the local system time for the current time zone.
+ pub fn ExSystemTimeToLocalTime(SystemTime: *const SYSTEMTIME, LocalTime: *mut SYSTEMTIME);
+}
+
+/// Obtains the current system time.
+pub fn QuerySystemTime() -> SYSTEMTIME {
+ let mut t = 0i64;
+ unsafe { KeQuerySystemTime(&mut t) };
+ return t;
+}
+
+/// A count of the interval timer interrupts that have occurred since the system was booted.
+pub fn QueryTickCount() -> i64 {
+ let mut t = 0i64;
+ unsafe { KeQueryTickCount(&mut t) };
+ return t;
+}
diff --git a/src/types.rs b/src/types.rs
new file mode 100644
index 0000000..f7e3838
--- /dev/null
+++ b/src/types.rs
@@ -0,0 +1 @@
+//! Kernel types.