R1.8/R1.9: empirical summary-query probe + enum-dump RE command

Pushed on recovering the summary query params. Findings:

- Added `enum-dump` to the RE CLI (dumps a managed enum's literal members).
  Confirmed INSQL_QUERYTYPE / HISTORIAN_SUMMARYTYPE are value__-only in the
  managed metadata — their named members are native-side constants, so they
  can't be recovered statically. Same for CColumnNameMap.LoadColumnNameMap
  (column->bit built from native string/const data, not IL ldstr/ldc).

- Live-probed StartQuery2 against SysTimeSec sweeping QueryType/SummaryType/
  ColumnSelectorFlags. The server ACCEPTS SummaryType 1/2/4/5 (returns a valid
  version-9 buffer) but yields 0 rows; column flags don't change that;
  QueryType 15/16 don't exist. So a summary query is NOT Full+SummaryType+
  flags — the config lives in the AutoSummaryParameters trailer (currently
  zeroed) and/or a native summary QueryType.

Conclusion recorded in the plan: the request shape needs a NATIVE capture
(instrument-wcf-writemessage on a real summary query), not managed-metadata
recovery or blind probing. Decode targets remain located. No guessed code in
src/; probe scaffolding removed. 208 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-06-20 16:11:35 -04:00
parent 085f01123c
commit 34e352ba28
2 changed files with 74 additions and 0 deletions
@@ -35,6 +35,7 @@ try
"dnlib-method" => InspectDnlibMethod(args),
"method-refs" => PrintMethodReferences(args),
"field-constant" => PrintFieldConstantReferences(args),
"enum-dump" => DumpEnumMembers(args),
"instrument-startdataquery" => InstrumentStartDataQuery(args),
"instrument-getnextrow" => InstrumentGetNextRow(args),
"instrument-wcf-readquery" => InstrumentWcfReadQuery(args),
@@ -80,6 +81,53 @@ catch (Exception ex)
return 1;
}
static int DumpEnumMembers(string[] args)
{
string path = args.Length > 1 ? args[1] : Path.Combine("current", "aahClientManaged.dll");
string filter = args.Length > 2 ? args[2] : throw new ArgumentException("Usage: enum-dump [dll-path] [type-name-substring]");
dnlib.DotNet.ModuleDefMD module = dnlib.DotNet.ModuleDefMD.Load(path);
int matchedTypes = 0;
foreach (dnlib.DotNet.TypeDef type in module.GetTypes())
{
if (type.Name.String.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0)
{
continue;
}
matchedTypes++;
Console.WriteLine($"Type: {type.FullName} (enum={type.IsEnum}, fields={type.Fields.Count})");
foreach (dnlib.DotNet.FieldDef field in type.Fields)
{
object? value = field.Constant?.Value;
if (value is null)
{
Console.WriteLine($" {field.Name,-40} [literal={field.IsLiteral} static={field.IsStatic} sig={field.FieldType?.TypeName}] (no const)");
continue;
}
string hex = value switch
{
int i => $"0x{i:X}",
uint u => $"0x{u:X}",
short s => $"0x{s:X}",
ushort us => $"0x{us:X}",
long l => $"0x{l:X}",
byte b => $"0x{b:X}",
sbyte sb => $"0x{sb:X}",
_ => "?"
};
Console.WriteLine($" {field.Name,-40} = {value} ({hex})");
}
}
if (matchedTypes == 0)
{
Console.WriteLine($"No type matched '{filter}'.");
}
return 0;
}
static int PrintExports(string[] args)
{
string path = args.Length > 1 ? args[1] : Path.Combine("current", "aahClient.dll");