[GH-ISSUE #743] [Feature] Recover .NET NativeAOT metadata in Ghidra workflows #330

Closed
opened 2026-10-15 18:23:56 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @morluto on GitHub (Oct 6, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/743

Originally assigned to: @N0zoM1z0 on GitHub.

Current limitation

REA classifies managed artifacts and exposes native analysis through the selected Ghidra or Hopper provider, but NativeAOT method-table metadata is not currently recovered as part of REA's Ghidra workflow. For a NativeAOT artifact, an agent can inspect native functions, pseudocode, strings, calls, and references, but the recovered .NET type hierarchy, virtual method slots, and frozen objects are unavailable unless the user separately runs a Ghidra extension.

NativeAOT compiles IL to native code and normally emits a self-contained native executable. It can also produce native shared libraries that expose selected methods. The outer format depends on target OS: PE/COFF on Windows, ELF on Linux, and Mach-O on macOS. The extension this issue references currently gates analysis to x86-64, so adopting its code or ideas without expanding and verifying format/architecture coverage would miss common targets.

NativeAOT must remain distinct from ReadyToRun (which can retain CIL alongside native code), ordinary managed single-file deployments, and Unity IL2CPP. NativeAOT does not retain ordinary CIL method bodies for source decompilation. ReadyToRun metadata may still retain type and object information that can aid native analysis.

Proposed outcome

Add NativeAOT evidence recovery to REA's Ghidra workflow for the supported native file formats and architectures admitted by REA. Recover metadata into the temporary Ghidra analysis database and expose observations through existing native inspection contracts where they fit, including inspect_native_data_type, strings, names, and function dossiers. Keep provider-specific parsing in the Ghidra adapter. Do not add a NativeAOT-only MCP tool unless existing primitives prove insufficient.

Handle these artifact shapes by their bytes and loader identity, not filename suffix:

  • Native executables: PE/COFF, ELF, and Mach-O, including universal Mach-O slice identity.
  • Native shared libraries: PE DLL, ELF .so, and Mach-O .dylib where the selected REA provider admits that target. NativeAOT libraries expose only explicitly exported entry points; they are not equivalent to a full managed assembly API.
  • Packaged applications: use REA's existing artifact inventory/extraction path to identify the contained native image, then carry its component path and digest into analysis.
  • Matching debug sidecars (PDB, ELF .dbg/DWARF, and dSYM) are useful supplementary evidence when the provider supports them. Treat them as separate artifacts with verified identity; their absence must not block NativeAOT metadata recovery.

The upstream Ghidra NativeAOT analyzer and metadata recovery write-up are concrete references. The extension describes ReadyToRun directory discovery, rehydration of DEHYDRATED_DATA, method-table/type hierarchy recovery, vtable annotation, and frozen object/string annotation. Its current analyzer source gates support to x86-64, is disabled by default, and has distinct .NET 7 and .NET 8 metadata paths; its UI metadata browser is not itself an MCP interface. REA needs an explicit headless invocation and useful structured output, not a dependency on a user manually installing/enabling a GUI extension. Microsoft's NativeAOT platform matrix includes Windows, Linux, and macOS across common x64/Arm64 targets, plus some x86/ARM and mobile targets depending on runtime version. Its native library guide documents shared-library builds. REA should state its own exact verified coverage rather than inherit either project's broader platform matrix. The .NET runtime documents NativeAOT's use of COFF/CodeView, ELF/DWARF, and Mach-O/DWARF native object formats in its NativeAOT architecture notes.

Acceptance criteria

  • Detect or explicitly select NativeAOT from bounded binary evidence; distinguish it from ordinary CIL, ReadyToRun, IL2CPP, and other native PE/ELF/Mach-O files.
  • Locate and validate ReadyToRun directory/sections with exact failure details when symbols are absent, signatures are ambiguous, or structures are unsupported. Handle PE RVAs/file offsets and ELF/Mach-O address/relocation semantics explicitly; do not assume all formats use PE mapping rules.
  • Invoke the recovery in REA's headless Ghidra lifecycle and return structured results through MCP/CLI without requiring GUI interaction or a separately installed extension. Keep recovery idempotent in the temporary Ghidra database and do not change executable bytes.
  • Recover supported method tables, type relationships, virtual slots, and frozen objects/strings in the temporary Ghidra database.
  • Make recovered types and annotations available through existing Ghidra-backed MCP/CLI operations and retain exact component identity/digest, provider/version provenance, addresses, and facet-level coverage limitations.
  • Preserve an executable's relationship to an app bundle and any accepted matching debug sidecars. Report symbol identity mismatches rather than silently applying unrelated symbols.
  • Keep unknown or inferred names distinct from byte-observed structures. Do not claim source-level C# reconstruction or map methods to functions without provider evidence.
  • Define tested target architecture and runtime-format versions. Unsupported versions and architectures return typed, actionable unavailability rather than partial success presented as complete. Mobile targets and native object files can remain out of initial scope unless fixtures and a REA provider lane can verify them.
  • Add source-built NativeAOT fixtures and end-to-end Ghidra verification for every initially claimed executable/shared-library format. Keep .NET NativeAOT SDK prerequisites in a separate optional real-toolchain lane.
  • #492 Inspect recovered native data types and layouts
  • ADR-0003: Managed-code evidence and provider boundary
Originally created by @morluto on GitHub (Oct 6, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/743 Originally assigned to: @N0zoM1z0 on GitHub. ## Current limitation REA classifies managed artifacts and exposes native analysis through the selected Ghidra or Hopper provider, but NativeAOT method-table metadata is not currently recovered as part of REA's Ghidra workflow. For a NativeAOT artifact, an agent can inspect native functions, pseudocode, strings, calls, and references, but the recovered .NET type hierarchy, virtual method slots, and frozen objects are unavailable unless the user separately runs a Ghidra extension. NativeAOT compiles IL to native code and normally emits a self-contained native executable. It can also produce native shared libraries that expose selected methods. The outer format depends on target OS: PE/COFF on Windows, ELF on Linux, and Mach-O on macOS. The extension this issue references currently gates analysis to x86-64, so adopting its code or ideas without expanding and verifying format/architecture coverage would miss common targets. NativeAOT must remain distinct from ReadyToRun (which can retain CIL alongside native code), ordinary managed single-file deployments, and Unity IL2CPP. NativeAOT does not retain ordinary CIL method bodies for source decompilation. ReadyToRun metadata may still retain type and object information that can aid native analysis. ## Proposed outcome Add NativeAOT evidence recovery to REA's Ghidra workflow for the supported native file formats and architectures admitted by REA. Recover metadata into the temporary Ghidra analysis database and expose observations through existing native inspection contracts where they fit, including `inspect_native_data_type`, strings, names, and function dossiers. Keep provider-specific parsing in the Ghidra adapter. Do not add a NativeAOT-only MCP tool unless existing primitives prove insufficient. Handle these artifact shapes by their bytes and loader identity, not filename suffix: - Native executables: PE/COFF, ELF, and Mach-O, including universal Mach-O slice identity. - Native shared libraries: PE DLL, ELF `.so`, and Mach-O `.dylib` where the selected REA provider admits that target. NativeAOT libraries expose only explicitly exported entry points; they are not equivalent to a full managed assembly API. - Packaged applications: use REA's existing artifact inventory/extraction path to identify the contained native image, then carry its component path and digest into analysis. - Matching debug sidecars (PDB, ELF `.dbg`/DWARF, and dSYM) are useful supplementary evidence when the provider supports them. Treat them as separate artifacts with verified identity; their absence must not block NativeAOT metadata recovery. The upstream [Ghidra NativeAOT analyzer](https://github.com/Washi1337/ghidra-nativeaot) and [metadata recovery write-up](https://blog.washi.dev/posts/recovering-nativeaot-metadata/) are concrete references. The extension describes ReadyToRun directory discovery, rehydration of `DEHYDRATED_DATA`, method-table/type hierarchy recovery, vtable annotation, and frozen object/string annotation. Its current analyzer source gates support to x86-64, is disabled by default, and has distinct .NET 7 and .NET 8 metadata paths; its UI metadata browser is not itself an MCP interface. REA needs an explicit headless invocation and useful structured output, not a dependency on a user manually installing/enabling a GUI extension. Microsoft's [NativeAOT platform matrix](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/) includes Windows, Linux, and macOS across common x64/Arm64 targets, plus some x86/ARM and mobile targets depending on runtime version. Its [native library guide](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/libraries) documents shared-library builds. REA should state its own exact verified coverage rather than inherit either project's broader platform matrix. The .NET runtime documents NativeAOT's use of COFF/CodeView, ELF/DWARF, and Mach-O/DWARF native object formats in its [NativeAOT architecture notes](https://github.com/dotnet/runtime/blob/main/docs/workflow/building/coreclr/nativeaot.md). ## Acceptance criteria - Detect or explicitly select NativeAOT from bounded binary evidence; distinguish it from ordinary CIL, ReadyToRun, IL2CPP, and other native PE/ELF/Mach-O files. - Locate and validate ReadyToRun directory/sections with exact failure details when symbols are absent, signatures are ambiguous, or structures are unsupported. Handle PE RVAs/file offsets and ELF/Mach-O address/relocation semantics explicitly; do not assume all formats use PE mapping rules. - Invoke the recovery in REA's headless Ghidra lifecycle and return structured results through MCP/CLI without requiring GUI interaction or a separately installed extension. Keep recovery idempotent in the temporary Ghidra database and do not change executable bytes. - Recover supported method tables, type relationships, virtual slots, and frozen objects/strings in the temporary Ghidra database. - Make recovered types and annotations available through existing Ghidra-backed MCP/CLI operations and retain exact component identity/digest, provider/version provenance, addresses, and facet-level coverage limitations. - Preserve an executable's relationship to an app bundle and any accepted matching debug sidecars. Report symbol identity mismatches rather than silently applying unrelated symbols. - Keep unknown or inferred names distinct from byte-observed structures. Do not claim source-level C# reconstruction or map methods to functions without provider evidence. - Define tested target architecture and runtime-format versions. Unsupported versions and architectures return typed, actionable unavailability rather than partial success presented as complete. Mobile targets and native object files can remain out of initial scope unless fixtures and a REA provider lane can verify them. - Add source-built NativeAOT fixtures and end-to-end Ghidra verification for every initially claimed executable/shared-library format. Keep .NET NativeAOT SDK prerequisites in a separate optional real-toolchain lane. ## Related - #492 Inspect recovered native data types and layouts - ADR-0003: Managed-code evidence and provider boundary
bsakaguchi 2026-10-15 18:23:56 +00:00
Author
Owner

@N0zoM1z0 commented on GitHub (Oct 6, 2026):

Implemented the initial verified integration in #748: optional pinned upstream adapter, inline method-table/hierarchy/interface/virtual-slot evidence, frozen strings, native pseudocode, exact artifact/derived-memory identity, and transactional ephemeral recovery through existing CLI/MCP tools.

Verified .NET 8.0.22 / RTR 9.1 x64 ELF (symbols and stripped) and source-built Windows x64 PE targets on Linux, including installed-package CLI/MCP, independent compiler/linker oracles, negative cases, unchanged input bytes and cleanup. The PR documents the exact coverage and limitations.

Keeping this issue open for broader host/format/runtime coverage, shared-library proofs and debug-sidecar/component identity workflows; those are not established by the current fixtures.

<!-- gh-comment-id:6021233788 --> @N0zoM1z0 commented on GitHub (Oct 6, 2026): Implemented the initial verified integration in #748: optional pinned upstream adapter, inline method-table/hierarchy/interface/virtual-slot evidence, frozen strings, native pseudocode, exact artifact/derived-memory identity, and transactional ephemeral recovery through existing CLI/MCP tools. Verified .NET 8.0.22 / RTR 9.1 x64 ELF (symbols and stripped) and source-built Windows x64 PE targets **on Linux**, including installed-package CLI/MCP, independent compiler/linker oracles, negative cases, unchanged input bytes and cleanup. The PR documents the exact coverage and limitations. Keeping this issue open for broader host/format/runtime coverage, shared-library proofs and debug-sidecar/component identity workflows; those are not established by the current fixtures.
Author
Owner

@morluto commented on GitHub (Oct 8, 2026):

Verified fixed on main (7a7460f0). NativeAOT recovery ships as Ghidra extension (bridge/ghidra/extensions/nativeaot/) with NativeAotAdapter, docs/ghidra-nativeaot.md, and scripts/verify-real-ghidra-nativeaot.mjs. Note: scoped to ELF+PE on Linux x64 as documented; #744 remains open for broader decompilation support. Closing per audit.

<!-- gh-comment-id:6071379184 --> @morluto commented on GitHub (Oct 8, 2026): Verified fixed on main (7a7460f0). NativeAOT recovery ships as Ghidra extension (bridge/ghidra/extensions/nativeaot/) with NativeAotAdapter, docs/ghidra-nativeaot.md, and scripts/verify-real-ghidra-nativeaot.mjs. Note: scoped to ELF+PE on Linux x64 as documented; #744 remains open for broader decompilation support. Closing per audit.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#330
No description provided.