diff --git a/csharp/README.md b/csharp/README.md index 67e9e3d..6cace64 100644 --- a/csharp/README.md +++ b/csharp/README.md @@ -7,7 +7,7 @@ A Windows application that injects fake time into running processes by hooking W ``` TimeMocker.sln ├── TimeMocker.UI — WinForms controller app (run as Admin) -│ ├── Forms/MainForm — UI: process chooser, time picker, pattern manager +│ ├── Forms/MainForm — UI: process list with inject toggle, time picker, pattern manager │ ├── Core/InjectionManager — EasyHook-based injector per process │ ├── Core/ProcessWatcher — background scanner for auto-inject patterns │ └── Core/SharedMemoryManager — named MMF shared with the hook DLL @@ -53,47 +53,62 @@ dotnet build -c Release -p:Platform=x64 ### Manual Injection 1. Launch `TimeMocker.exe` (UAC will prompt for elevation) -2. **Processes tab** → search for your target process → select it -3. Set the desired date/time in the **Mock Time Settings** bar at the top -4. Tick **Enable Mock** → click **Inject →** -5. The target process now sees your fake time immediately +2. Set the desired date/time in the **Mock Time Settings** bar at the top +3. Click **Set** to apply the time to all injected processes +4. Go to the **Processes** tab +5. Find your target process in the list (use Search if needed) +6. Check the **Injected** checkbox next to the process +7. The target process now sees your fake time immediately +8. To stop mocking for a process, simply uncheck the **Injected** checkbox ### Auto-Inject Rules +The auto-inject watcher starts automatically when TimeMocker launches. Any process matching a rule will be injected automatically. + 1. Go to the **Auto-Inject Rules** tab 2. Enter a pattern matching the process path or name, e.g.: - Glob: `C:\Games\MyGame\*` - Glob by name: `*chrome*` - Regex: `^.*\\MyApp\.exe$` -3. Click **+ Add Rule** -4. Tick **Enable Auto-Inject Watcher** -5. Any process that starts (or is already running) matching the rule gets injected automatically +3. Select **Glob** or **Regex** pattern type +4. Click **+ Add Rule** +5. Any process that starts (or is already running) matching the rule gets injected automatically with the current mock time -### Auto-Advance Time +### Time Flow -Tick **Auto-advance time** in the time bar — the fake time ticks forward in sync with real time from the moment you set it. +TimeMocker uses a **delta-based** approach. When you set a fake time, it calculates the offset between your desired time and the current real time. This offset is stored and applied continuously, so the fake time flows forward naturally at the same rate as real time. + +- Click **Now** to reset the date/time pickers to current time +- Click **Set** to apply the selected time to all injected processes +- The offset is recalculated each time you click **Set** + +### Process List + +- Only user processes are shown (system processes are filtered out) +- Click **⟳ Refresh** to reload the process list +- Dead processes are automatically removed from the injected processes list ## IPC Design -The fake time is stored in a **named Memory-Mapped File** (one per injected process): +The time offset is stored in a **named Memory-Mapped File** (one per injected process): ``` Name: TimeMocker_ -Size: 12 bytes - [0..7] FakeUtcTicks (Int64 — DateTime.Ticks) - [8..11] Enabled (Int32 — 0=passthrough, 1=mock) +Size: 8 bytes + [0..7] DeltaTicks (Int64 — offset from DateTime.UtcNow.Ticks) ``` -The hook reads this on every time API call (~50 ns read, no syscall). The UI writes it whenever you click **Apply** or toggle the checkbox. +The hook reads this on every time API call and returns `DateTime.UtcNow + DeltaTicks`. This design allows the fake time to flow naturally without requiring timer-based updates from the UI. ## Notes & Limitations - **64-bit only** — 32-bit processes require a separate 32-bit hook DLL build -- Processes using `QueryPerformanceCounter` for *monotonic* timing are not affected +- Processes using `QueryPerformanceCounter` for *monotonic* timing are not affected (QPC is a hardware register; patching it is unsupported by EasyHook) - Anti-cheat or heavily protected processes (Epic, BattlEye, etc.) will block injection - Some .NET apps read time through the CLR, which internally calls the hooked APIs — these *will* be affected -- EasyHook does not fully support hot-eject; to restore real time, disable the mock via the checkbox rather than ejecting +- EasyHook does not fully support hot-eject; to restore real time, uncheck the **Injected** checkbox +- Mocked time is always enabled — there is no passthrough mode ## License