Files
mxaccess/docs/Transport-Correlation.md
Joseph Doherty fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
Initial project state: .NET reference, design, Rust port (M0+M1), evidence
Layout:
- src/                    .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
                          MxAsbClient, probes, tests, harnesses. Executable spec.
- design/                 Architectural plan for the Rust port (M0–M6), error
                          model, protocol invariants, risks (R1–R16), adversarial
                          review log (review.md).
- rust/                   Rust workspace. M0 skeleton + M1 codec parity.
                          mxaccess-codec: 215 unit tests + 2 cross-implementation
                          parity tests (byte-identical against .NET reference).
                          Other crates are M0 stubs awaiting M2+.
- captures/               Frida + netsh + pcap evidence per CLAUDE.md
                          ("captures are evidence, not throwaway logs").
- analysis/               Decompiled C# (frida/proxy/decompiled-*),
                          Ghidra exports for native DLLs (`exports/` only —
                          working state at `projects/` and AVEVA's input
                          binaries at `input/` are gitignored).
- docs/                   Reverse-engineering reference docs.
- tools/                  Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
                          Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/      Rust CI: fmt + build + test + clippy on Windows.
- LICENSE                 MIT (Joseph Doherty, 2026).

Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly

Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 06:21:00 -04:00

2.5 KiB

Transport correlation

This note records the current boundary between the native adapter body format and localhost transport.

Combined captures

The combined runner starts Npcap loopback capture, then launches the harness under Frida:

analysis\scripts\run_frida_loopback_capture.ps1

Helper scripts:

analysis\scripts\map_frida_to_tcp.py
analysis\scripts\parse_dcerpc_streams.py
analysis\scripts\decode_mixed_local_stream.py

Capture 043

captures\043-frida-loopback-write-test-int-115

This writes TestChildObject.TestInt = 115. It proved exact Frida adapter bodies are not copied verbatim to TCP, but the scalar value 115 was ambiguous because it also matched DCE/RPC call IDs in the same window.

Capture 044

captures\044-frida-loopback-write-test-int-123456789

This writes a distinctive value:

TestChildObject.TestInt = 123456789

Results:

Needle Result
raw little-endian 123456789 not found anywhere in the full pcap payload scan
exact 40-byte Frida PutRequest body not found in reassembled TCP streams
exact 86-byte Frida TransferData body not found in reassembled TCP streams
exact 88-byte Frida callback body not found in reassembled TCP streams
mixed 127.0.0.1:57415 <-> 57433 stream parsed, raw value not found
DCE/RPC ::1:49704 streams parsed 452 PDUs, raw value not found in request/response stubs

Generated files:

captures\044-frida-loopback-write-test-int-123456789\frida-to-tcp-map.tsv
captures\044-frida-loopback-write-test-int-123456789\dcerpc-stream-pdus.tsv
captures\044-frida-loopback-write-test-int-123456789\mixed-stream-57415-to-57433.tsv
captures\044-frida-loopback-write-test-int-123456789\mixed-stream-57433-to-57415.tsv

Implication

The CNmxAdapter::PutRequest and CNmxAdapter::TransferData buffers are an internal adapter representation, not the TCP wire format. The wire transport does not expose the write value as plain little-endian scalar bytes for this distinctive-value capture.

The next reverse-engineering step is to decode the structural bridge between adapter bodies and transport messages:

  1. Correlate Frida call timestamps to DCE/RPC call IDs and mixed-stream record windows.
  2. Decode DCE/RPC NDR stubs for the observed context/opnum pairs.
  3. Hook deeper in NmxSvc.exe around CNmxControler::TransferData and CNmxService::TransferData so both sides of the adapter-to-service boundary can be compared before TCP serialization.