finish device io call to scan
This commit is contained in:
parent
0ca87a871c
commit
d08852af55
@ -10,5 +10,5 @@ edition = "2018"
|
||||
hex = "0.4.2"
|
||||
pdb = "0.5.0"
|
||||
widestring = "0.4.0"
|
||||
winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset"] }
|
||||
winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset", "winioctl", "errhandlingapi"] }
|
||||
reqwest = { version = "0.10.1", features = ["blocking"] }
|
||||
|
246
src/driver_state.rs
Normal file
246
src/driver_state.rs
Normal file
@ -0,0 +1,246 @@
|
||||
use std::ffi::c_void;
|
||||
use std::mem::{size_of_val};
|
||||
|
||||
use winapi::shared::ntdef::{NTSTATUS};
|
||||
use winapi::shared::minwindef::{DWORD};
|
||||
use winapi::um::winioctl::{
|
||||
CTL_CODE, FILE_ANY_ACCESS,
|
||||
METHOD_IN_DIRECT, METHOD_OUT_DIRECT, METHOD_BUFFERED, METHOD_NEITHER
|
||||
};
|
||||
|
||||
use crate::pdb_store::{PdbStore};
|
||||
use crate::windows::{WindowsFFI, WindowsVersion};
|
||||
use crate::ioctl_protocol::{
|
||||
InputData, OffsetData, DerefAddr, ScanRange,
|
||||
OutputData, Nothing
|
||||
};
|
||||
|
||||
const SIOCTL_TYPE: DWORD = 40000;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum DriverAction {
|
||||
SetupOffset,
|
||||
GetKernelBase,
|
||||
ScanPsActiveHead,
|
||||
ScanPool,
|
||||
ScanPoolRemote,
|
||||
DereferenceAddress
|
||||
}
|
||||
|
||||
impl DriverAction {
|
||||
pub fn get_code(&self) -> DWORD {
|
||||
match self {
|
||||
DriverAction::SetupOffset => CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::GetKernelBase => CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::ScanPsActiveHead => CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS),
|
||||
DriverAction::ScanPool => CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::ScanPoolRemote => CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::DereferenceAddress => CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct DriverState {
|
||||
pdb_store: PdbStore,
|
||||
windows_ffi: WindowsFFI,
|
||||
ntosbase: u64,
|
||||
nonpaged_range: [u64; 2],
|
||||
}
|
||||
|
||||
impl DriverState {
|
||||
pub fn new(pdb_store: PdbStore, windows_ffi: WindowsFFI) -> Self {
|
||||
pdb_store.print_default_information();
|
||||
windows_ffi.print_version();
|
||||
Self {
|
||||
pdb_store,
|
||||
windows_ffi,
|
||||
ntosbase: 0u64,
|
||||
nonpaged_range: [0, 0]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn startup(&mut self) -> NTSTATUS {
|
||||
self.windows_ffi.load_driver()
|
||||
}
|
||||
|
||||
pub fn shutdown(&self) -> NTSTATUS {
|
||||
self.windows_ffi.unload_driver()
|
||||
}
|
||||
|
||||
// TODO: Function output and input data????
|
||||
pub fn interact(&mut self, action: DriverAction) {
|
||||
let code = action.get_code();
|
||||
println!("Driver action: {:?}", action);
|
||||
match action {
|
||||
DriverAction::SetupOffset => {
|
||||
let mut input = InputData {
|
||||
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version)
|
||||
};
|
||||
self.windows_ffi.device_io(code, &mut input, &mut Nothing);
|
||||
},
|
||||
DriverAction::GetKernelBase => {
|
||||
self.windows_ffi.device_io(code, &mut Nothing, &mut self.ntosbase);
|
||||
println!("ntosbase: 0x{:x}", self.ntosbase);
|
||||
},
|
||||
DriverAction::ScanPsActiveHead => {
|
||||
self.interact(DriverAction::GetKernelBase);
|
||||
let ps_active_head = self.ntosbase + self.pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64);
|
||||
let flink_offset = self.pdb_store.get_offset("_LIST_ENTRY.Flink").unwrap_or(0u64);
|
||||
let eprocess_link_offset = self.pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64);
|
||||
let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64);
|
||||
|
||||
let mut ptr = ps_active_head;
|
||||
self.deref_addr(ptr + flink_offset, &mut ptr);
|
||||
|
||||
println!("========================");
|
||||
println!("Scan PsActiveProcessHead");
|
||||
while ptr != ps_active_head {
|
||||
let mut image_name = [0u8; 15];
|
||||
let eprocess = ptr - eprocess_link_offset;
|
||||
self.deref_addr(eprocess + eprocess_name_offset, &mut image_name);
|
||||
match std::str::from_utf8(&image_name) {
|
||||
Ok(n) => {
|
||||
// TODO: save to somewhere
|
||||
println!("_EPROCESS at 0x{:x} of {}", eprocess, n);
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
self.deref_addr(ptr + flink_offset, &mut ptr);
|
||||
}
|
||||
println!("========================");
|
||||
|
||||
// test call to check result
|
||||
self.windows_ffi.device_io(code, &mut Nothing, &mut Nothing);
|
||||
},
|
||||
DriverAction::ScanPool => {
|
||||
self.get_nonpaged_range();
|
||||
let mut input = InputData {
|
||||
scan_range: ScanRange::new(&self.nonpaged_range)
|
||||
};
|
||||
self.windows_ffi.device_io(code, &mut input, &mut Nothing);
|
||||
},
|
||||
DriverAction::ScanPoolRemote => {
|
||||
self.get_nonpaged_range();
|
||||
let start_address = self.nonpaged_range[0];
|
||||
let end_address = self.nonpaged_range[1];
|
||||
|
||||
let pool_header_size = self.pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64);
|
||||
let eprocess_name_offset = self.pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64);
|
||||
|
||||
let mut ptr = start_address;
|
||||
while ptr < end_address {
|
||||
let mut input = InputData {
|
||||
scan_range: ScanRange::new(&[ptr, end_address])
|
||||
};
|
||||
self.windows_ffi.device_io(code, &mut input, &mut ptr);
|
||||
if ptr >= end_address {
|
||||
break;
|
||||
}
|
||||
let pool_addr = ptr;
|
||||
ptr += pool_header_size;
|
||||
|
||||
let mut pool = vec![0u8; pool_header_size as usize];
|
||||
self.deref_addr_ptr(pool_addr, pool.as_mut_ptr(), pool_header_size);
|
||||
// TODO: Use pdb to parse, bit mangling and stuff
|
||||
println!("=========================");
|
||||
println!("Pool at 0x{:x}", pool_addr);
|
||||
println!("Previos Size: 0x{:x}", pool[0]);
|
||||
println!("Pool index : {:x}", pool[1]);
|
||||
println!("Block size : 0x{:x}", (pool[2] as u64) * 16u64); // CHUNK_SIZE = 16
|
||||
println!("Pool type : {}", pool[3]);
|
||||
println!("Pool tag : {}", std::str::from_utf8(&pool[4..8]).unwrap());
|
||||
|
||||
let pool_size = (pool[2] as u64) * 16u64;
|
||||
// dump pool here
|
||||
let eprocess_offset: Vec<u64> = match pool_size {
|
||||
0xf00 => vec![0x40],
|
||||
0xd80 => vec![0x40, 0x70, 0x80],
|
||||
0xe00 => vec![0x60, 0x70, 0x80, 0x90],
|
||||
_ => vec![]
|
||||
};
|
||||
// let eprocess_offset: Vec<u64> = vec![0x40, 0x70, 0x80];
|
||||
let mut found_valid = false;
|
||||
for &offset in &eprocess_offset {
|
||||
let eprocess = pool_addr + offset;
|
||||
let mut image_name = [0u8; 15];
|
||||
self.deref_addr(eprocess + eprocess_name_offset, &mut image_name);
|
||||
match std::str::from_utf8(&image_name) {
|
||||
Ok(n) => {
|
||||
// TODO: save to somewhere
|
||||
// TODO: check if a name is not valid, values outside ascii,
|
||||
// remember that if a string is vaid, the rest of the name is 0
|
||||
found_valid = true;
|
||||
println!("_EPROCESS at 0x{:x} of {}", eprocess, n);
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
if !found_valid {
|
||||
println!("Not an eprocess maybe");
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
|
||||
let code = DriverAction::DereferenceAddress.get_code();
|
||||
let size: usize = size_of_val(outbuf);
|
||||
let mut input = InputData {
|
||||
deref_addr: DerefAddr {
|
||||
addr,
|
||||
size: size as u64
|
||||
}
|
||||
};
|
||||
// unsafe { println!("Dereference {} bytes at 0x{:x}", input.deref_addr.size, input.deref_addr.addr) };
|
||||
self.windows_ffi.device_io(code, &mut input, outbuf);
|
||||
}
|
||||
|
||||
fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len: u64) {
|
||||
let code = DriverAction::DereferenceAddress.get_code();
|
||||
let mut input = InputData {
|
||||
deref_addr: DerefAddr {
|
||||
addr,
|
||||
size: output_len
|
||||
}
|
||||
};
|
||||
self.windows_ffi.device_io_raw(code,
|
||||
&mut input as *mut _ as *mut c_void, size_of_val(&input) as DWORD,
|
||||
outptr as *mut c_void, output_len as DWORD);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn get_nonpaged_range(&mut self) {
|
||||
// TODO: Add support for other Windows version here
|
||||
match self.windows_ffi.short_version {
|
||||
WindowsVersion::Windows10FastRing => {
|
||||
let mistate = self.ntosbase + self.pdb_store.get_offset("MiState").unwrap_or(0u64);
|
||||
let system_node_ptr = self.pdb_store.addr_decompose(
|
||||
mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool")
|
||||
.unwrap_or(0u64);
|
||||
let mut system_node_addr = 0u64;
|
||||
self.deref_addr(system_node_ptr, &mut system_node_addr);
|
||||
|
||||
let mut first_va = 0u64;
|
||||
let mut last_va = 0u64;
|
||||
self.deref_addr(
|
||||
system_node_addr + self.pdb_store.get_offset(
|
||||
"_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64),
|
||||
&mut first_va);
|
||||
|
||||
self.deref_addr(
|
||||
system_node_addr + self.pdb_store.get_offset(
|
||||
"_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64),
|
||||
&mut last_va);
|
||||
|
||||
self.nonpaged_range[0] = first_va;
|
||||
self.nonpaged_range[1] = last_va;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
println!("Nonpaged pool range: 0x{:x} - 0x{:x}", self.nonpaged_range[0], self.nonpaged_range[1]);
|
||||
}
|
||||
}
|
95
src/ioctl_protocol.rs
Normal file
95
src/ioctl_protocol.rs
Normal file
@ -0,0 +1,95 @@
|
||||
use crate::pdb_store::PdbStore;
|
||||
use crate::windows::WindowsVersion;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct OffsetData {
|
||||
eprocess_name_offset: u64,
|
||||
eprocess_link_offset: u64,
|
||||
list_blink_offset: u64,
|
||||
process_head_offset: u64,
|
||||
mistate_offset: u64,
|
||||
hardware_offset: u64,
|
||||
system_node_offset: u64,
|
||||
first_va_offset: u64,
|
||||
last_va_offset: u64,
|
||||
large_page_table_offset: u64,
|
||||
large_page_size_offset: u64,
|
||||
pool_chunk_size: u64,
|
||||
}
|
||||
|
||||
// TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version
|
||||
impl OffsetData {
|
||||
pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self {
|
||||
match windows_version {
|
||||
WindowsVersion::Windows10FastRing => Self {
|
||||
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64),
|
||||
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64),
|
||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64),
|
||||
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool").unwrap_or(0u64),
|
||||
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64),
|
||||
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64),
|
||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64),
|
||||
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64),
|
||||
},
|
||||
// TODO: Add other version of Windows here
|
||||
_ => Self {
|
||||
eprocess_name_offset: 0u64,
|
||||
eprocess_link_offset: 0u64,
|
||||
list_blink_offset: 0u64,
|
||||
process_head_offset: 0u64,
|
||||
mistate_offset: 0u64,
|
||||
hardware_offset: 0u64,
|
||||
system_node_offset: 0u64,
|
||||
first_va_offset: 0u64,
|
||||
last_va_offset: 0u64,
|
||||
large_page_table_offset: 0u64,
|
||||
large_page_size_offset: 0u64,
|
||||
pool_chunk_size: 0u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct DerefAddr {
|
||||
pub addr: u64,
|
||||
pub size: u64
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ScanRange {
|
||||
pub start: u64,
|
||||
pub end: u64
|
||||
}
|
||||
|
||||
impl ScanRange {
|
||||
pub fn new(arr: &[u64; 2]) -> Self {
|
||||
Self {
|
||||
start: arr[0],
|
||||
end: arr[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union InputData {
|
||||
pub offset_value: OffsetData,
|
||||
pub deref_addr: DerefAddr,
|
||||
pub scan_range: ScanRange,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Nothing; // for empty data
|
||||
|
||||
#[repr(C)]
|
||||
pub union OutputData {
|
||||
pub nothing: Nothing,
|
||||
}
|
23
src/main.rs
23
src/main.rs
@ -1,18 +1,25 @@
|
||||
mod pdb_store;
|
||||
mod windows;
|
||||
mod ioctl_protocol;
|
||||
mod driver_state;
|
||||
|
||||
use pdb_store::parse_pdb;
|
||||
use windows::WindowsFFI;
|
||||
use driver_state::{DriverState, DriverAction};
|
||||
|
||||
fn main() {
|
||||
let store = pdb_store::parse_pdb();
|
||||
store.print_default_information();
|
||||
|
||||
// for windows admin require
|
||||
// https://github.com/nabijaczleweli/rust-embed-resource
|
||||
let mut windows_ffi = windows::WindowsFFI::new();
|
||||
windows_ffi.print_version();
|
||||
|
||||
println!("NtLoadDriver() -> 0x{:x}", windows_ffi.load_driver());
|
||||
let mut driver = DriverState::new(parse_pdb(), WindowsFFI::new());
|
||||
|
||||
windows_ffi.device_io(0x900);
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", windows_ffi.unload_driver());
|
||||
driver.interact(DriverAction::SetupOffset);
|
||||
driver.interact(DriverAction::GetKernelBase);
|
||||
// driver.interact(DriverAction::ScanPsActiveHead);
|
||||
// driver.interact(DriverAction::ScanPool);
|
||||
driver.interact(DriverAction::ScanPoolRemote);
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::ffi::CString;
|
||||
use std::mem::transmute;
|
||||
use std::ffi::{c_void, CString};
|
||||
use std::mem::{transmute, size_of_val};
|
||||
use std::ptr::null_mut;
|
||||
use widestring::U16CString;
|
||||
|
||||
@ -12,7 +12,8 @@ use winapi::um::winnt::{
|
||||
FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE
|
||||
};
|
||||
|
||||
use winapi::um::ioapiset::DeviceIoControl;
|
||||
use winapi::um::ioapiset::{DeviceIoControl};
|
||||
use winapi::um::errhandlingapi::{GetLastError};
|
||||
use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS};
|
||||
use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle};
|
||||
use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress};
|
||||
@ -24,7 +25,7 @@ use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCA
|
||||
const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\nganhkhoa";
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum WindowsVersion {
|
||||
Windows10_2015,
|
||||
Windows10_2016,
|
||||
@ -37,6 +38,7 @@ pub enum WindowsVersion {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct WindowsFFI {
|
||||
pub version_info: OSVERSIONINFOW,
|
||||
pub short_version: WindowsVersion,
|
||||
@ -148,7 +150,7 @@ impl WindowsFFI {
|
||||
Self {
|
||||
version_info,
|
||||
short_version,
|
||||
driver_handle: null_mut(),
|
||||
driver_handle: INVALID_HANDLE_VALUE,
|
||||
ntdll,
|
||||
nt_load_driver,
|
||||
nt_unload_driver,
|
||||
@ -157,7 +159,13 @@ impl WindowsFFI {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn driver_loaded(self) -> bool {
|
||||
self.driver_handle != INVALID_HANDLE_VALUE
|
||||
}
|
||||
|
||||
pub fn load_driver(&mut self) -> NTSTATUS {
|
||||
// TODO: Move this to new()
|
||||
// If we move this function to new(), self.driver_handle will be init, and thus no mut here
|
||||
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
|
||||
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
||||
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16);
|
||||
@ -180,7 +188,7 @@ impl WindowsFFI {
|
||||
status
|
||||
}
|
||||
|
||||
pub fn unload_driver(&mut self) -> NTSTATUS {
|
||||
pub fn unload_driver(&self) -> NTSTATUS {
|
||||
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
|
||||
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
||||
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr());
|
||||
@ -202,10 +210,37 @@ impl WindowsFFI {
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn device_io(&self, _code: DWORD) {
|
||||
pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD {
|
||||
// input_ptr: *mut c_void, input_len: DWORD, output_ptr: *mut c_void, output_len: DWORD) {
|
||||
// println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code);
|
||||
// TODO: call device_io_raw
|
||||
let mut bytes_returned: DWORD = 0;
|
||||
unsafe {
|
||||
DeviceIoControl(self.driver_handle, 0x900, null_mut(), 0, null_mut(), 0, null_mut(), null_mut());
|
||||
}
|
||||
let status = DeviceIoControl(self.driver_handle, code,
|
||||
inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD,
|
||||
outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD,
|
||||
&mut bytes_returned, null_mut());
|
||||
if status == 0 {
|
||||
println!("device io failed: last error {}", GetLastError());
|
||||
}
|
||||
};
|
||||
bytes_returned
|
||||
}
|
||||
|
||||
pub fn device_io_raw(&self, code: DWORD,
|
||||
input_ptr: *mut c_void, input_len: DWORD,
|
||||
output_ptr: *mut c_void, output_len: DWORD) -> DWORD {
|
||||
// println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code);
|
||||
let mut bytes_returned: DWORD = 0;
|
||||
unsafe {
|
||||
let status = DeviceIoControl(self.driver_handle, code,
|
||||
input_ptr, input_len,
|
||||
output_ptr, output_len,
|
||||
&mut bytes_returned, null_mut());
|
||||
if status == 0 {
|
||||
println!("device io failed: last error {}", GetLastError());
|
||||
}
|
||||
};
|
||||
bytes_returned
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user