Initial project state: .NET reference, design, Rust port (M0+M1), evidence
rust / build / test / clippy / fmt (push) Has been cancelled

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>
This commit is contained in:
Joseph Doherty
2026-05-05 06:21:00 -04:00
parent 43733699b0
commit fe2a6db786
3849 changed files with 352975 additions and 0 deletions
@@ -0,0 +1,52 @@
using System;
using System.IO.Pipes;
using System.Text;
namespace ArchestrAServices.Common.Resolution;
public class PipeClient : IDisposable
{
private string _pipeName;
private NamedPipeClientStream _pipeClient;
private bool disposed;
public PipeClient(string PipeName)
{
_pipeName = PipeName;
_pipeClient = new NamedPipeClientStream(".", _pipeName, PipeDirection.Out);
}
public bool SendString(string Data)
{
_pipeClient.Connect(5000);
byte[] bytes = Encoding.UTF8.GetBytes(Data);
_pipeClient.Write(bytes, 0, bytes.Length);
_pipeClient.WaitForPipeDrain();
return true;
}
public void Dispose()
{
Dispose(freeManagedObjectsAlso: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool freeManagedObjectsAlso)
{
if (!disposed)
{
if (freeManagedObjectsAlso)
{
_pipeClient.Dispose();
}
disposed = true;
}
}
~PipeClient()
{
Dispose(freeManagedObjectsAlso: false);
}
}
@@ -0,0 +1,64 @@
using System;
using System.IO.Pipes;
using System.Text;
using System.Threading;
namespace ArchestrAServices.Common.Resolution;
public class PipeServer : IDisposable
{
private string _pipeName;
private NamedPipeServerStream _pipeServer;
private bool disposed;
public PipeServer(string PipeName)
{
_pipeName = PipeName;
_pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In, 1, PipeTransmissionMode.Message);
}
public string ReadString()
{
_pipeServer.WaitForConnection();
string result = string.Empty;
if (_pipeServer.IsConnected)
{
while (!_pipeServer.IsMessageComplete)
{
Thread.Sleep(50);
}
byte[] array = new byte[100];
int num = _pipeServer.Read(array, 0, 100);
if (num > 0)
{
result = Encoding.UTF8.GetString(array, 0, num);
}
}
return result;
}
public void Dispose()
{
Dispose(freeManagedObjectsAlso: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool freeManagedObjectsAlso)
{
if (!disposed)
{
if (freeManagedObjectsAlso)
{
_pipeServer.Dispose();
}
disposed = true;
}
}
~PipeServer()
{
Dispose(freeManagedObjectsAlso: false);
}
}
@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.ServiceModel.Discovery;
namespace ArchestrAServices.Common.Resolution;
public class Resolution
{
private static string MostRecentIPAddressFromExe;
[Obsolete("Use ArchestrAServices.Common.HostedService.Resolution.GetDiscoveryEndpointMetadata() instead.")]
public static EndpointDiscoveryMetadata GetDiscoveryEndpointMetada(EndpointDiscoveryMetadata metaData)
{
string errorMessage;
return GetDiscoveryEndpointMetada(metaData, out errorMessage);
}
[Obsolete("Use ArchestrAServices.Common.HostedService.Resolution.GetDiscoveryEndpointMetadata() instead.")]
public static EndpointDiscoveryMetadata GetDiscoveryEndpointMetada(EndpointDiscoveryMetadata metaData, out string errorMessage)
{
errorMessage = string.Empty;
try
{
if (metaData != null)
{
string[] array = null;
NetworkInterface[] array2 = null;
try
{
array2 = NetworkInterface.GetAllNetworkInterfaces();
}
catch (NetworkInformationException)
{
array2 = null;
}
if (array2 != null)
{
List<string> list = new List<string>();
NetworkInterface[] array3 = array2;
foreach (NetworkInterface networkInterface in array3)
{
if (networkInterface.NetworkInterfaceType != NetworkInterfaceType.Ethernet)
{
continue;
}
foreach (UnicastIPAddressInformation unicastAddress in networkInterface.GetIPProperties().UnicastAddresses)
{
if (unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork && unicastAddress.SuffixOrigin != SuffixOrigin.LinkLayerAddress)
{
if (unicastAddress.SuffixOrigin == SuffixOrigin.Manual || unicastAddress.SuffixOrigin == SuffixOrigin.OriginDhcp)
{
list.Insert(0, unicastAddress.Address.ToString());
}
else
{
list.Add(unicastAddress.Address.ToString());
}
}
}
}
list.Add(Environment.MachineName);
array = list.ToArray();
}
UriBuilder uriBuilder = new UriBuilder(metaData.Address.Uri);
if (uriBuilder != null && !string.IsNullOrEmpty(uriBuilder.Host))
{
metaData.ListenUris.Clear();
string[] array4 = array;
foreach (string host in array4)
{
uriBuilder.Host = host;
Uri uri = uriBuilder.Uri;
metaData.ListenUris.Add(uri);
}
}
}
}
catch (Exception ex2)
{
errorMessage = "GetDiscoveryEndpointMetada: Exception " + ex2.Message;
}
return metaData;
}
[Obsolete("Legacy method. No longer supported due to deprecated Win32 methods being used.")]
public static string ResolveIPAddress(string HostOrIP, out string errorMessage)
{
string empty = string.Empty;
errorMessage = string.Empty;
if (!Environment.Is64BitProcess)
{
try
{
empty = ResolveLocalIPAddr(HostOrIP, out errorMessage);
}
catch (Exception ex)
{
empty = string.Empty;
errorMessage = "ResolveIPAddress caught exception: " + ex.Message;
}
}
else
{
if (string.IsNullOrEmpty(MostRecentIPAddressFromExe))
{
string text = Guid.NewGuid().ToString() + "_Resolution";
using PipeServer pipeServer = new PipeServer(text);
if (File.Exists("aaASBResolveIP.exe"))
{
try
{
Process.Start("aaASBResolveIP.exe", text + " " + HostOrIP);
MostRecentIPAddressFromExe = pipeServer.ReadString();
}
catch (Exception ex2)
{
errorMessage = $"ResolveIPAddress called in 64-bit process - exception starting or reading from helper process aaASBResolveIP.exe: {ex2.Message}";
}
}
else
{
errorMessage = "ResolveIPAddress called in 64-bit process - could not find helper process aaASBResolveIP.exe, no resolution";
}
}
empty = MostRecentIPAddressFromExe;
}
return empty;
}
private unsafe static string ResolveLocalIPAddr(string HostOrIP, out string errorMessage)
{
WinSock.WSAData lpWSAData;
int num = WinSock.WSAStartup(514, out lpWSAData);
string result = string.Empty;
errorMessage = "Unknown failure in ResolveLocalIPAddr";
if (num == 0)
{
int addr = WinSock.inet_addr(HostOrIP);
WinSock.hostent* ptr = null;
if (addr != -1)
{
int len = 4;
ptr = WinSock.gethostbyaddr(ref addr, len, ProtocolFamily.InterNetwork);
if (ptr == null)
{
result = string.Empty;
errorMessage = "ResolveLocalIPAddr: call to gethostbyaddr for IP address " + HostOrIP + " failed to resolve a hostent struct";
}
}
else
{
ptr = WinSock.gethostbyname(HostOrIP);
if (ptr == null)
{
result = string.Empty;
errorMessage = "ResolveLocalIPAddr: call to gethostbyname for host name " + HostOrIP + " failed to resolve a hostent struct";
}
}
if (ptr != null)
{
byte* h_addr_list = *ptr->h_addr_list;
int num2 = *h_addr_list;
int num3 = h_addr_list[1];
int num4 = h_addr_list[2];
int num5 = h_addr_list[3];
result = $"{num2}.{num3}.{num4}.{num5}";
errorMessage = string.Empty;
}
WinSock.WSACleanup();
}
else
{
result = string.Empty;
errorMessage = "ResolveLocalIPAddr: unable to initialize WinSock, WSAStartup returned error";
}
return result;
}
}
@@ -0,0 +1,6 @@
namespace ArchestrAServices.Common.Resolution;
internal static class Validation
{
internal static string IPAddressRegex = "^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$";
}
@@ -0,0 +1,68 @@
using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security;
namespace ArchestrAServices.Common.Resolution;
[SuppressUnmanagedCodeSecurity]
internal class WinSock
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct WSAData
{
[MarshalAs(UnmanagedType.U2)]
public ushort wVersion;
[MarshalAs(UnmanagedType.U2)]
public ushort wHighVersion;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 257)]
private byte[] szDescription;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 129)]
private byte[] szSystemStatus;
[MarshalAs(UnmanagedType.U2)]
public ushort iMaxSockets;
[MarshalAs(UnmanagedType.U2)]
public ushort iMaxUdpDg;
[MarshalAs(UnmanagedType.LPStr)]
public string lpVendorInfo;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct hostent
{
public IntPtr h_name;
public IntPtr h_aliases;
[MarshalAs(UnmanagedType.I2)]
public short h_addrtype;
[MarshalAs(UnmanagedType.I2)]
public short h_length;
public unsafe byte** h_addr_list;
}
internal const uint INADDR_NONE = uint.MaxValue;
[DllImport("ws2_32", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int WSAStartup([In][MarshalAs(UnmanagedType.U2)] ushort wVersionRequested, [MarshalAs(UnmanagedType.Struct)] out WSAData lpWSAData);
[DllImport("ws2_32", CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int WSACleanup();
[DllImport("ws2_32", CharSet = CharSet.Ansi, SetLastError = true)]
internal unsafe static extern hostent* gethostbyaddr([In][MarshalAs(UnmanagedType.I4)] ref int addr, [In][MarshalAs(UnmanagedType.I4)] int len, [In] ProtocolFamily type);
[DllImport("ws2_32", BestFitMapping = false, CharSet = CharSet.Ansi, SetLastError = true)]
internal unsafe static extern hostent* gethostbyname([In] string host);
[DllImport("ws2_32", BestFitMapping = false, CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int inet_addr([In] string cp);
}
@@ -0,0 +1,20 @@
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyCompany("AVEVA Software, LLC")]
[assembly: AssemblyCopyright("Copyright © 2020 AVEVA Group plc and its subsidiaries. All rights reserved.")]
[assembly: AssemblyProduct("ArchestrA Data Store")]
[assembly: AssemblyFileVersion("2019.4.20078.1")]
[assembly: AssemblyInformationalVersion("4.4.6")]
[assembly: AssemblyTitle("ArchestrAServices.Common.Resolution")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: ComVisible(false)]
[assembly: Guid("8a59d007-5515-4d89-b34c-aecf3d1fb35e")]
[assembly: AssemblyTrademark("Refer to: https://sw.aveva.com/legal/trademarks")]
[assembly: AssemblyVersion("1.0.0.0")]
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>aaServicesCommonResolution</AssemblyName>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<TargetFramework>net40</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<LangVersion>14.0</LangVersion>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup />
<ItemGroup />
<ItemGroup>
<Reference Include="System.ServiceModel.Discovery" />
<Reference Include="System.Core" />
<Reference Include="System.ServiceModel" />
</ItemGroup>
</Project>