windows_recipe_messagebox/windows-recipe-messagebox.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
//! # [`recipe!`] example
//!
//! This example demonstrates how to write a simple recipe.
//!
//! The recipe is injected into the `explorer.exe` process and shows
//! a message box.
//!
//! # Possible log output
//!
//! ```text
//! DEBUG domain_id=XenDomainId(102)
//! DEBUG found MZ base_address=0xfffff80002861000
//! INFO profile already exists profile_path="cache/windows/ntkrnlmp.pdb/3844dbb920174967be7aa4a2c20430fa2/profile.json"
//! INFO Creating VMI session
//! INFO found explorer.exe pid=1248 object=0xfffffa80030e9060
//! DEBUG injector{vcpu=2 rip=0x0000000077c618ca}:memory_access: thread hijacked current_tid=1488
//! DEBUG injector{vcpu=2 rip=0x0000000077c618ca}:memory_access: recipe step index=0
//! DEBUG injector{vcpu=1 rip=0x0000000077c618ca}:memory_access: recipe finished result=0x0000000000000001
//! ```
mod _common;
use vmi::{
arch::amd64::Amd64,
os::windows::WindowsOs,
utils::injector::{recipe, InjectorHandler, Recipe},
VcpuId, VmiDriver,
};
struct MessageBox {
caption: String,
text: String,
}
impl MessageBox {
pub fn new(caption: impl AsRef<str>, text: impl AsRef<str>) -> Self {
Self {
caption: caption.as_ref().to_string(),
text: text.as_ref().to_string(),
}
}
}
#[rustfmt::skip]
fn recipe_factory<Driver>(data: MessageBox) -> Recipe<Driver, WindowsOs<Driver>, MessageBox>
where
Driver: VmiDriver<Architecture = Amd64>,
{
recipe![
Recipe::<_, WindowsOs<Driver>, _>::new(data),
{
inj! {
user32!MessageBoxA(
0, // hWnd
data![text], // lpText
data![caption], // lpCaption
0 // uType
)
}
}
]
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (vmi, profile) = _common::create_vmi_session()?;
let processes = {
let _pause_guard = vmi.pause_guard()?;
let registers = vmi.registers(VcpuId(0))?;
vmi.os().processes(®isters)?
};
let explorer = processes
.iter()
.find(|process| process.name.to_lowercase() == "explorer.exe")
.expect("explorer.exe");
tracing::info!(
pid = %explorer.id,
object = %explorer.object,
"found explorer.exe"
);
vmi.handle(|vmi| {
InjectorHandler::new(
vmi,
&profile,
explorer.id,
recipe_factory(MessageBox::new(
"Hello, World!",
"This is a message box from the VMI!",
)),
)
})?;
Ok(())
}