Skip to content

Commit 7619ef0

Browse files
[poc] mbe-1256 ifeo windows launcher + tests ヾ( ˃ᴗ˂ )◞ • *✰ (#3436)
* initial commit. * oops. forgot -r * o_vec() for RegistryValue * format * start_ifeo * oops * simplify tests * cute little create_process * sync for the day * un-pub ifeo functions * simplify code * set up entrypoint for mirrord-layer * forgot git add * layer. * layer. * first simple version... * docs touchup * more logic touchups * oops * let hell loose * ughhh * FINALLY AHHH!! * here!!! * oops!! * finished!
1 parent 228f3e2 commit 7619ef0

File tree

26 files changed

+2060
-35
lines changed

26 files changed

+2060
-35
lines changed

Cargo.lock

Lines changed: 437 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22

33
members = [
4+
"mirrord-win-poc/ifeo/*",
45
"mirrord-win-poc/manual-exec/*"
56
]
67
resolver = "2"

changelog.d/+mirror-e2e.internal.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added more traffic mirroring tests.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "mirrord-launcher"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
winapi = { version = "0.3.9", features = ["winreg", "winerror", "errhandlingapi", "handleapi", "processthreadsapi", "winbase"] }
8+
dll-syringe = "0.17.0"
9+
mirrord-win-str = { path = "../mirrord-win-str" }
10+
11+
[dev-dependencies]
12+
rand = "0.9.1"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use winapi::um::{
2+
handleapi::{CloseHandle, INVALID_HANDLE_VALUE},
3+
winnt::HANDLE,
4+
};
5+
6+
/// Safe [`HANDLE`] abstraction.
7+
///
8+
/// Acquires raw [`HANDLE`] handle, does [`CloseHandle`] on [`std::ops::Drop`].
9+
#[derive(Debug)]
10+
pub struct SafeHandle {
11+
handle: HANDLE,
12+
}
13+
14+
impl SafeHandle {
15+
/// Constructs [`SafeHandle`] from [`HANDLE`].
16+
///
17+
/// # Arguments
18+
///
19+
/// * `handle`: Windows raw [`HANDLE`] handle.
20+
pub fn from(handle: HANDLE) -> Self {
21+
Self { handle }
22+
}
23+
24+
/// Get underlying raw [`HANDLE`] for Windows API operations.
25+
pub fn get(&self) -> HANDLE {
26+
self.handle
27+
}
28+
29+
/// Close underlying raw [`HANDLE`] handle.
30+
pub fn close(&mut self) {
31+
if !self.handle.is_null() && self.handle != INVALID_HANDLE_VALUE {
32+
unsafe { CloseHandle(self.get()) };
33+
}
34+
35+
self.handle = std::ptr::null_mut();
36+
}
37+
}
38+
39+
impl std::ops::Drop for SafeHandle {
40+
fn drop(&mut self) {
41+
self.close()
42+
}
43+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use winapi::{shared::minwindef::HKEY, um::winreg::RegCloseKey};
2+
3+
/// Safe [`HKEY`] abstraction.
4+
///
5+
/// Acquires raw [`HKEY`] handle, does [`RegCloseKey`] on [`std::ops::Drop`].
6+
#[derive(Debug)]
7+
pub struct SafeHKey {
8+
handle: HKEY,
9+
}
10+
11+
impl SafeHKey {
12+
/// Constructs [`SafeHKey`] from [`HKEY`].
13+
///
14+
/// # Arguments
15+
///
16+
/// * `handle`: Windows raw [`HKEY`] handle.
17+
pub fn from(handle: HKEY) -> Self {
18+
Self { handle }
19+
}
20+
21+
/// Get underlying raw [`HKEY`] for Windows API operations.
22+
pub fn get(&self) -> HKEY {
23+
self.handle
24+
}
25+
26+
/// Close underlying raw [`HKEY`] handle.
27+
pub fn close(&mut self) {
28+
if !self.handle.is_null() {
29+
unsafe { RegCloseKey(self.get()) };
30+
self.handle = std::ptr::null_mut();
31+
}
32+
}
33+
}
34+
35+
impl std::ops::Drop for SafeHKey {
36+
fn drop(&mut self) {
37+
self.close()
38+
}
39+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod handle;
2+
pub mod hkey;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//! IFEO module for `launcher`.
2+
//!
3+
//! Responsible for doing operations on the "Image File Execution Options" system
4+
//! in Windows, which is managed through the registry.
5+
//!
6+
//! Among others, this system allows to override process creation through
7+
//! the registry value `Debugger`, which is checked against in `CreateProcessInternalW`.
8+
//!
9+
//! Registering this should allow us to create a global override for our target process,
10+
//! and we have to mitigate the effect of that, to avoid capturing stray processes.
11+
12+
use std::path::Path;
13+
14+
use crate::{
15+
process::{absolute_path, process_name_from_path},
16+
registry::Registry,
17+
};
18+
19+
const IMAGE_FILE_EXECUTION_OPTIONS: &str =
20+
r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options"#;
21+
const DEBUGGER_VALUE: &str = "Debugger";
22+
23+
fn get_ifeo<T: AsRef<str>>(program: T) -> Option<Registry> {
24+
let hklm = Registry::hklm();
25+
hklm.get_key(IMAGE_FILE_EXECUTION_OPTIONS)?
26+
.get_or_insert_key(program)
27+
}
28+
29+
/// Sets IFEO entry for `program`, redirecting it's execution towards `debug`.
30+
///
31+
/// # Arguments
32+
///
33+
/// * `program` - Path, relative/absolute, towards program to be overriden.
34+
/// * `debug` - Path, relative/absolute, towards program to override.
35+
pub fn set_ifeo<T: AsRef<Path>, U: AsRef<Path>>(program: T, debug: U) -> bool {
36+
// Truncate any potential path to it's potential file name.
37+
let program = process_name_from_path(program);
38+
if program.is_none() {
39+
return false;
40+
}
41+
42+
let program = program.unwrap();
43+
44+
// Turn path into absolute path to have non-ambiguous override.
45+
let debug = absolute_path(debug);
46+
if debug.is_none() {
47+
return false;
48+
}
49+
50+
let debug = debug.unwrap();
51+
52+
// Remove IFEO before installing.
53+
remove_ifeo(&program);
54+
55+
// Install IFEO.
56+
if let Some(mut ifeo) = get_ifeo(program) {
57+
let inserted = ifeo.insert_value_string(DEBUGGER_VALUE, debug);
58+
ifeo.flush();
59+
return inserted;
60+
}
61+
62+
false
63+
}
64+
65+
/// Removes IFEO entry for `program`, re-establishing normal execution.
66+
///
67+
/// # Arguments
68+
///
69+
/// * `program` - Path, absolute/relative, towards program to remove IFEO for.
70+
pub fn remove_ifeo<T: AsRef<Path>>(program: T) -> bool {
71+
// Truncate any potential path to it's potential file name.
72+
let program = process_name_from_path(program);
73+
if program.is_none() {
74+
return false;
75+
}
76+
77+
let program = program.unwrap();
78+
79+
if let Some(mut ifeo) = get_ifeo(program) {
80+
let deleted = ifeo.delete_value(DEBUGGER_VALUE);
81+
ifeo.flush();
82+
return deleted;
83+
}
84+
85+
false
86+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod ifeo;

0 commit comments

Comments
 (0)