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(&registers)?
    };

    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(())
}