[GH-ISSUE #744] [Bug] NativeAOT Decompilation Support #333

Closed
opened 2026-10-15 18:24:00 +00:00 by bsakaguchi · 5 comments
Owner

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

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

Currently, the agent hits a wall when trying to reverse engineer or reconstruct C# source code from .NET 8 NativeAOT compiled binaries. The agent notes that REA / Ghidra is only extracting raw x86_64 assembly and cannot reconstruct or lift the binary back to a readable C# project state. We spoke in Discord and you mentioned adding support for it.

Reproduction

  1. Provide a NativeAOT compiled .NET executable to the agent.
  2. Ask the agent to use REA to decompile or analyze it.
  3. The agent fails or refuses because the C# code is destroyed and only raw assembly remains.

Expected behavior

Implement a workflow or specific tooling to lift NativeAOT binaries into a more readable format, as discussed.

Impact and scope

Agent cannot decompile or reconstruct NativeAOT binaries, effectively walling off analysis on modern .NET 8 compiled executables.

REA version

Latest MCP deployment

Runtime and platform

Windows x64

Target and artifact context

.NET 8 NativeAOT single-file executable

Interface

MCP

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Agent states: "The developer compiled it with NativeAOT. The source code is permanently destroyed and only raw x86_64 assembly remains."

Typed outcome or recovery expected

The tool should attempt to lift .NET NativeAOT structures, or at least identify it as NativeAOT and parse available metadata instead of failing back to raw unreadable assembly.

Analysis or suspected cause

NativeAOT compilation strips C# IL and metadata, leaving only x86_64 assembly. REA currently treats it as a standard native binary instead of attempting to rebuild or de-obfuscate .NET structures.

Additional context

Requested via Discord conversation with the repository owner.

Originally created by @bobjonesrocks67-sudo on GitHub (Oct 6, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/744 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior Currently, the agent hits a wall when trying to reverse engineer or reconstruct C# source code from .NET 8 NativeAOT compiled binaries. The agent notes that REA / Ghidra is only extracting raw x86_64 assembly and cannot reconstruct or lift the binary back to a readable C# project state. We spoke in Discord and you mentioned adding support for it. ### Reproduction 1. Provide a NativeAOT compiled .NET executable to the agent. 2. Ask the agent to use REA to decompile or analyze it. 3. The agent fails or refuses because the C# code is destroyed and only raw assembly remains. ### Expected behavior Implement a workflow or specific tooling to lift NativeAOT binaries into a more readable format, as discussed. ### Impact and scope Agent cannot decompile or reconstruct NativeAOT binaries, effectively walling off analysis on modern .NET 8 compiled executables. ### REA version Latest MCP deployment ### Runtime and platform Windows x64 ### Target and artifact context .NET 8 NativeAOT single-file executable ### Interface MCP ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence ```text Agent states: "The developer compiled it with NativeAOT. The source code is permanently destroyed and only raw x86_64 assembly remains." ``` ### Typed outcome or recovery expected The tool should attempt to lift .NET NativeAOT structures, or at least identify it as NativeAOT and parse available metadata instead of failing back to raw unreadable assembly. ### Analysis or suspected cause NativeAOT compilation strips C# IL and metadata, leaving only x86_64 assembly. REA currently treats it as a standard native binary instead of attempting to rebuild or de-obfuscate .NET structures. ### Additional context Requested via Discord conversation with the repository owner.
bsakaguchi 2026-10-15 18:24:00 +00:00
Author
Owner

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

#748 adds verified NativeAOT metadata recovery and readable native pseudocode for .NET 8.0.22 x64 ELF / Windows PE targets analyzed on Linux, plus agent guidance to continue native analysis and distinguish generated metadata from original C# names/source. Real Windows PE proof recovered hierarchy, interfaces, virtual slots and frozen strings; representative arithmetic pseudocode is return param_2 * 0xb + 5;.

Keeping this report open: its Windows-host workflow is not verified/supported by this integration. Windows Ghidra P0 retains its existing no-mutation boundary; Linux analysis of a Windows target is a different claim. This also does not reconstruct original C# source or custom field layouts.

<!-- gh-comment-id:6021242792 --> @N0zoM1z0 commented on GitHub (Oct 6, 2026): #748 adds verified NativeAOT metadata recovery and readable native pseudocode for .NET 8.0.22 x64 ELF / Windows PE targets analyzed on Linux, plus agent guidance to continue native analysis and distinguish generated metadata from original C# names/source. Real Windows PE proof recovered hierarchy, interfaces, virtual slots and frozen strings; representative arithmetic pseudocode is `return param_2 * 0xb + 5;`. Keeping this report open: its **Windows-host** workflow is not verified/supported by this integration. Windows Ghidra P0 retains its existing no-mutation boundary; Linux analysis of a Windows target is a different claim. This also does not reconstruct original C# source or custom field layouts.
Author
Owner

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

Triage note (2026-10-09): keeping open. #748 is merged and delivers Linux-host NativeAOT metadata recovery plus readable native pseudocode, but per #748's own scoping note the Windows-host workflow in this report remains open (Windows Ghidra P0 has no mutation authority). The remaining ask here — a usable Windows-host NativeAOT workflow — is still unaddressed.

<!-- gh-comment-id:6072407397 --> @morluto commented on GitHub (Oct 9, 2026): Triage note (2026-10-09): keeping open. #748 is merged and delivers Linux-host NativeAOT metadata recovery plus readable native pseudocode, but per #748's own scoping note the Windows-host workflow in this report remains open (Windows Ghidra P0 has no mutation authority). The remaining ask here — a usable Windows-host NativeAOT workflow — is still unaddressed.
Author
Owner

@pablodiazjorge commented on GitHub (Oct 11, 2026):

Windows-host results for the part of this issue that is still open. Host: Windows 11 x64, non-elevated, rea main at fb43dd97, Ghidra 12.1.4, Temurin 21.

Fixture. scripts/generate-nativeaot-fixtures.mjs on Windows with .NET SDK 8.0.416: PASS source-built win-x64 NativeAOT fixture, independent RTR 9.1 oracle and SHA-256 157a3b54…f9b95552; no target execution. One host note: ILCompiler 8.0's findvcvarsall.bat only looks for Visual Studio 2019 or 2022 (vswhere -version [16,18)), so with only Build Tools 2026 installed the publish fails with "Platform linker not found". It builds after calling Build Tools 2026's vcvars64.bat and setting IlcUseEnvironmentalTools=true.

Checks. The read-only parts of verify-real-ghidra-nativeaot.mjs (symbols mode) over MCP, without REA_GHIDRA_NATIVEAOT_JAR, comparing with the oracle and the linker map (NativeAotFixture.map):

Check Result
open_binary with Ghidra pass
inspect_native_load_image metadata recovery pass: dotnet-nativeaot, complete, RTR 9.1, signature-heuristic, 324 method tables and 324 types
Independent symbols in the map (base, derived, interface, Compute) found
summary.types identity at the derived method table type: null, since no database type exists without the adapter
inspect_native_data_type by address at the derived method table pass: generated name (original_name: null), and the method table, base type, interface and a virtual slot reaching Compute all match the map
analyze_function on Compute pass: return param_2 * 0xb + 5;
analyze_function on Dispatch pass, pseudocode present
read_bytes at the first virtual slot (0x1400a9228) 0 bytes, complete: false
search_strings for the three frozen strings none found

Why the last two fail. The method tables and frozen objects live in the hydrated section, which is BSS (0 bytes on disk) at 0x14009a000 and is filled from dehydrated data at startup. The file holds no bytes there, and the frozen strings do not appear in it in UTF-16 or ASCII. Without the adapter writing rehydrated memory into the database, which Windows P0 does not allow, REA reports those bytes as unavailable instead of inventing them. That fits the P0 boundary rather than being a bug.

So, on a Windows host today: metadata recovery through the snapshot parser and decompilation work; frozen strings and raw reads inside hydrated need the adapter, so they stay Linux-only. If useful, I can open a docs PR for windows-ghidra-p0.md and ghidra-nativeaot.md with exactly this split, the inspect_native_data_type by address route when type is null, and the Build Tools 2026 note. Would you prefer that, or a different follow-up?

<!-- gh-comment-id:6113245253 --> @pablodiazjorge commented on GitHub (Oct 11, 2026): Windows-host results for the part of this issue that is still open. Host: Windows 11 x64, non-elevated, rea `main` at `fb43dd97`, Ghidra 12.1.4, Temurin 21. **Fixture.** `scripts/generate-nativeaot-fixtures.mjs` on Windows with .NET SDK 8.0.416: `PASS source-built win-x64 NativeAOT fixture, independent RTR 9.1 oracle and SHA-256 157a3b54…f9b95552; no target execution`. One host note: ILCompiler 8.0's `findvcvarsall.bat` only looks for Visual Studio 2019 or 2022 (`vswhere -version [16,18)`), so with only Build Tools 2026 installed the publish fails with "Platform linker not found". It builds after calling Build Tools 2026's `vcvars64.bat` and setting `IlcUseEnvironmentalTools=true`. **Checks.** The read-only parts of `verify-real-ghidra-nativeaot.mjs` (symbols mode) over MCP, without `REA_GHIDRA_NATIVEAOT_JAR`, comparing with the oracle and the linker map (`NativeAotFixture.map`): | Check | Result | |---|---| | `open_binary` with Ghidra | pass | | `inspect_native_load_image` metadata recovery | pass: `dotnet-nativeaot`, `complete`, RTR 9.1, `signature-heuristic`, 324 method tables and 324 types | | Independent symbols in the map (base, derived, interface, `Compute`) | found | | `summary.types` identity at the derived method table | `type: null`, since no database type exists without the adapter | | `inspect_native_data_type` by `address` at the derived method table | pass: generated name (`original_name: null`), and the method table, base type, interface and a virtual slot reaching `Compute` all match the map | | `analyze_function` on `Compute` | pass: `return param_2 * 0xb + 5;` | | `analyze_function` on `Dispatch` | pass, pseudocode present | | `read_bytes` at the first virtual slot (`0x1400a9228`) | 0 bytes, `complete: false` | | `search_strings` for the three frozen strings | none found | **Why the last two fail.** The method tables and frozen objects live in the `hydrated` section, which is BSS (0 bytes on disk) at `0x14009a000` and is filled from dehydrated data at startup. The file holds no bytes there, and the frozen strings do not appear in it in UTF-16 or ASCII. Without the adapter writing rehydrated memory into the database, which Windows P0 does not allow, REA reports those bytes as unavailable instead of inventing them. That fits the P0 boundary rather than being a bug. **So, on a Windows host today:** metadata recovery through the snapshot parser and decompilation work; frozen strings and raw reads inside `hydrated` need the adapter, so they stay Linux-only. If useful, I can open a docs PR for `windows-ghidra-p0.md` and `ghidra-nativeaot.md` with exactly this split, the `inspect_native_data_type` by `address` route when `type` is null, and the Build Tools 2026 note. Would you prefer that, or a different follow-up?
Author
Owner

@matbrgz commented on GitHub (Oct 12, 2026):

.NET NativeAOT Reverse Engineering Strategy Notes

Decompiling .NET 8/9 NativeAOT binaries presents different challenges than standard managed .NET (CIL):

  • Nature of NativeAOT: NativeAOT compiles C# directly to native machine code (x86-64 / ARM64). There are no CIL bytecodes or ordinary #Strings/#Blob ECMA-335 tables to decompile with ILSpy.
  • Analysis Route:
    • Route through native decompilers (Ghidra/IDA) as standard PE/ELF/Mach-O binaries.
    • NativeAOT embeds unmanaged runtime data structures (MethodTable, EEType, interface dispatch maps, and reflection blobs). Implementing a static NativeAOT type descriptor parser can recover high-level class hierarchies, method names, and virtual dispatch tables to annotate the native disassembly.
<!-- gh-comment-id:6134690767 --> @matbrgz commented on GitHub (Oct 12, 2026): ### .NET NativeAOT Reverse Engineering Strategy Notes Decompiling .NET 8/9 NativeAOT binaries presents different challenges than standard managed .NET (CIL): - **Nature of NativeAOT:** NativeAOT compiles C# directly to native machine code (x86-64 / ARM64). There are no CIL bytecodes or ordinary `#Strings`/`#Blob` ECMA-335 tables to decompile with ILSpy. - **Analysis Route:** - Route through native decompilers (Ghidra/IDA) as standard PE/ELF/Mach-O binaries. - NativeAOT embeds unmanaged runtime data structures (`MethodTable`, `EEType`, interface dispatch maps, and reflection blobs). Implementing a static NativeAOT type descriptor parser can recover high-level class hierarchies, method names, and virtual dispatch tables to annotate the native disassembly.
Author
Owner

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

Closing the minimum requested NativeAOT metadata/native-analysis workflow as addressed in qualified main fffb07419.

The Windows-host MCP results already recorded in this issue verify the previously missing host path: inspect_native_load_image identified NativeAOT/RTR 9.1, address-based inspect_native_data_type recovered method-table/base/interface/virtual-slot relationships against an independent map, and analyze_function returned readable native pseudocode. Those are the reporter's runtime results, not a new engine run by this audit. Current docs preserve the Windows P0 read-only boundary and distinguish generated names from original C# source.

Reconstructing the original C# project is not claimed. Hydrated-section raw bytes and frozen strings still require the adapter and remain outside Windows P0's mutation authority. Current CI's NativeAOT job builds the fixture; it does not repeat Windows-host Ghidra analysis. These limits do not negate the report's alternative request to identify NativeAOT and parse available metadata.

<!-- gh-comment-id:6178774527 --> @morluto commented on GitHub (Oct 14, 2026): Closing the minimum requested NativeAOT metadata/native-analysis workflow as addressed in qualified main [`fffb07419`](https://github.com/morluto/rea/commit/fffb0741936067530d1ce9777461cd53e87398c2). The [Windows-host MCP results already recorded in this issue](https://github.com/morluto/rea/issues/744#issuecomment-6113245253) verify the previously missing host path: `inspect_native_load_image` identified NativeAOT/RTR 9.1, address-based `inspect_native_data_type` recovered method-table/base/interface/virtual-slot relationships against an independent map, and `analyze_function` returned readable native pseudocode. Those are the reporter's runtime results, not a new engine run by this audit. Current docs preserve the Windows P0 read-only boundary and distinguish generated names from original C# source. Reconstructing the original C# project is not claimed. Hydrated-section raw bytes and frozen strings still require the adapter and remain outside Windows P0's mutation authority. Current CI's NativeAOT job builds the fixture; it does not repeat Windows-host Ghidra analysis. These limits do not negate the report's alternative request to identify NativeAOT and parse available metadata.
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#333
No description provided.