[F46] analysis/frida: Suspend/Activate hooks + R5 next-step

Closes the wire-side gap left by capture 077 in F44's R5 walk. The Frida
script now hooks the production LmxProxy.dll dispatchers so a future live
re-run on the AVEVA host can answer "does CLMXProxyServer issue a separate
ORPC method for Suspend/Activate, or are they synthesised client-side?"

Hooks added in `analysis/frida/mx-nmx-trace.js`:
- `LmxProxy.dll!CLMXProxyServer.Suspend`  @ RVA 0x13d9c (FUN_10013d9c)
- `LmxProxy.dll!CLMXProxyServer.Activate` @ RVA 0x14028 (FUN_10014028)

Both RVAs were extracted from
`analysis/ghidra/exports/LmxProxy.dll.string-refs.tsv` rows 119/122 (the
`CLMXProxyServer::Suspend - Server Handle` / `Activate - Server Handle`
log strings each xref one function — same pattern as the existing
AdviseSupervisory hook at 0x142b4). The hooks emit `mx.suspend.begin/end`
and `mx.activate.begin/end` events with serverHandle, itemHandle, and the
`MxStatus*` out parameter decoded as 4 x int16 (Success / Category /
DetectedBy / Detail per `src/MxNativeCodec/MxStatus.cs`). Naming matches
the F46 spec's `mx.<verb>.begin / end` grep convention rather than the
generic `call.enter / leave` shape because we want to filter these out
of large traces without false positives from other LmxProxy entrypoints.

No `Resume` / `Reactivate` exports exist in `LmxProxy.dll` — verified
against `analysis/ghidra/exports/LmxProxy.dll.ghidra.md` (no such string
xrefs) and the decompiled `ILMXProxyServer5` / `ILMXProxyServer4`
interfaces under `analysis/decompiled-mxaccess/ArchestrA/MxAccess/`
(only Suspend and Activate are declared on the dispatch interface).

The script's top-of-file comment now carries the live re-run procedure
(rebuild MxTraceHarness x86, attach Frida with `--scenario=suspend-advised`
then `--scenario=activate-advised`, save under
`captures/NNN-frida-suspend-activate-instrumented/`, grep the new TSV for
`mx.suspend.*` / `mx.activate.*` and correlate with `nmx.enter` events
in the same time window). Live capture is intentionally deferred to the
maintainer per the F46 spec — this dev box has no AVEVA install.

`design/70-risks-and-open-questions.md` R5 status updated:
- Title flag `(filed as F45)` -> `(filed as F46, hook landed pending live re-run)`
  (the docs/M6-buffered-evidence.md footnote referenced F45 from before
  F45 / F46 were de-conflicted by commit 2120dfa).
- New "Next step - F46" paragraph documents the two hooked RVAs, the
  out-param decode shape, and the verified absence of Resume / Reactivate
  symbols.
- "Current best answer" paragraph re-points the residual ORPC question
  at F46.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-06 05:42:24 -04:00
parent c7e71e4424
commit 808fea18a0
2 changed files with 148 additions and 6 deletions
+19 -6
View File
@@ -60,12 +60,13 @@ The `OnBufferedDataChange` **public event shape** the wwtools api-notes describe
**Settles when:** indefinitely deferred — see Open evidence gaps table. Settle criteria depends on the same Ghidra mapping table as R3, which does not exist in `analysis/ghidra/` and has no owner. Reopen if a future capture or decompiled output produces evidence.
### R5 — Activate / Suspend behaviour **(partially observed — F44 documented client-side trigger; wire-side residual gap filed as F45)**
### R5 — Activate / Suspend behaviour **(partially observed — F44 documented client-side trigger; wire-side residual gap filed as F46, hook landed pending live re-run)**
**Severity: P2** (downgraded from P1 — client-side acceptance criteria are
now documented; LMX-proxy wire emission remains unconfirmed)
**Status (2026-05-06): PARTIALLY OBSERVED.** F44's evidence walk on
**Status (2026-05-06): PARTIALLY OBSERVED — Frida hooks ready, live capture pending.**
F44's evidence walk on
`captures/077-frida-suspend-advised-scanstate/` (per `docs/M6-buffered-evidence.md`)
documents:
@@ -83,15 +84,27 @@ What capture 077 could **not** answer: whether the production
(e.g. an `ILMXProxyServer5` opnum) or also handles them client-side. Capture
077's Frida script did not hook
`LmxProxy.dll!CLMXProxyServer.Suspend`/`.Activate`, so the wire-side
behaviour is invisible. Filed as **F45** in `design/followups.md` to
re-instrument and capture.
behaviour is invisible.
**Next step — F46.** `analysis/frida/mx-nmx-trace.js` now carries
`Interceptor.attach` blocks for `LmxProxy.dll!CLMXProxyServer.Suspend`
(RVA `0x13d9c`, `FUN_10013d9c`) and `.Activate` (RVA `0x14028`,
`FUN_10014028`), emitting `mx.suspend.begin/end` and
`mx.activate.begin/end` events with the `MxStatus*` out-parameter
decoded as 4 × int16. No `Resume` / `Reactivate` symbols exist in
`LmxProxy.dll` — verified against
`analysis/ghidra/exports/LmxProxy.dll.ghidra.md` and the decompiled
`ILMXProxyServer5` / `ILMXProxyServer4` interfaces. R5 stays open
until a live re-run on the AVEVA host produces
`captures/NNN-frida-suspend-activate-instrumented/` per the procedure
documented at the top of `analysis/frida/mx-nmx-trace.js`.
**Current best answer:** expose `Session::suspend(item)` and
`Session::activate(item)` returning `Result<MxStatus, Error>`. The success
criteria match the .NET reference's client-side gating: the item must have
an active subscription. If F45's wire capture later proves the LMX proxy
an active subscription. If F46's wire capture later proves the LMX proxy
issues a separate ORPC method, add the wire emission here in M6 follow-up.
Do not build callback-driven state transitions on top until F45 settles.
Do not build callback-driven state transitions on top until F46 settles.
**Settles when:** F45 produces a Frida capture instrumenting
`LmxProxy.dll!CLMXProxyServer.Suspend` / `.Activate` and either confirms a