Files
time-mocker/crates/time-mocker-core/src/lib.rs
T
tiennm99 f4bd35ae5b fix(hook): harden detour install, unload, and delta reconnection
Initialize every detour before enabling any, so a hook body that calls
another detour's trampoline can never hit an uninitialized detour and abort
the process. Pin the module on load so unloading can no longer leave
kernel32/ntdll patched to jump into freed memory. On a failed FILETIME
conversion, fall through to the real time instead of returning an
uninitialized SYSTEMTIME. Reconnect the shared delta mapping lazily so
setting a delta after injection takes effect instead of being disabled
forever. Add host-agnostic tick-conversion tests.
2026-09-21 16:13:17 +07:00

49 lines
1.9 KiB
Rust

//! Shared types and named MMF helper for time-mocker.
//!
//! IPC contract: an 8-byte memory-mapped file named `Global\TimeMocker_<pid>`
//! (or `Local\TimeMocker_<pid>` as a session-scoped fallback) holds an i64
//! `DeltaTicks` — the offset (in 100-ns FILETIME units) added to the real
//! system FILETIME by the injected hook.
//!
//! The `Global\` namespace lets the admin controller in session 1 reach
//! processes in session 0 (services) and other sessions, but creating an
//! object there requires `SeCreateGlobalPrivilege` — granted only to elevated
//! tokens. Debug / non-elevated controllers fall back to `Local\` so dev
//! workflows can still hook same-session targets.
//!
//! Both endpoints (writer = UI, reader = hook DLL) try `Global\` first and
//! then `Local\`, so a controller's elevation state determines the namespace
//! used and the hook just probes both.
// `mmf` wraps Win32-only APIs (named file mappings), so it is gated on
// `windows` at the module level. `ticks` and `types` hold pure arithmetic —
// no Win32 dependency at all beyond the FILETIME/SYSTEMTIME conversions
// inside `ticks`, which are individually `#[cfg(windows)]` — so both stay
// buildable and testable on any host (e.g. `cargo test -p time-mocker-core`
// on Linux CI/dev boxes actually exercises the tick-arithmetic tests instead
// of compiling an empty crate).
#[cfg(windows)]
pub mod mmf;
pub mod ticks;
pub mod types;
#[cfg(windows)]
pub use mmf::{CreateOutcome, SharedDeltaReader, SharedDeltaWriter};
pub use types::MockTimeInfo;
pub const MMF_PREFIX_GLOBAL: &str = "Global\\TimeMocker_";
pub const MMF_PREFIX_LOCAL: &str = "Local\\TimeMocker_";
/// Back-compat alias: the primary (elevated) namespace.
pub const MMF_PREFIX: &str = MMF_PREFIX_GLOBAL;
#[inline]
pub fn mmf_name_for_pid(pid: u32) -> String {
format!("{MMF_PREFIX_GLOBAL}{pid}")
}
#[inline]
pub fn local_mmf_name_for_pid(pid: u32) -> String {
format!("{MMF_PREFIX_LOCAL}{pid}")
}