A simple yet powerful tool for dumping metadata from running processes compiled with .NET NativeAOT. Peek under the hood of any NativeAOT application in real-time!
- What is it? π€
- Key Features π
- How does it look? πΈ
- Under the Hood βοΈ
- How to Run π οΈ
- Project Structure π
- Want to Contribute? β€οΈ
When a .NET application is compiled with NativeAOT, it becomes a native executable without any IL code or JIT compilation. This is fantastic for performance but makes analyzing the application much harder.
NativeAotDumper solves this problem. It attaches to a running process and, as if by magic, pulls all available information about types, methods, and more directly from its memory.
It can dump:
- Type Information (classes, structs, interfaces) with their full names.
- MethodTable addresses.
- Methods, fields, and properties of each type, along with their metadata (tokens, offsets).
- Frozen Strings, which the compiler places in a special memory region.
- π₯ Real-time Analysis: Works with running processes, allowing you to inspect the application's state on the fly.
- π§ Deep Metadata Diving: Includes a complete implementation of a .NET Native Format parser, adapted to read from process memory. This isn't just reading a few structs; it's a full-fledged parsing of complex, nested metadata.
- π Simple UI: A user-friendly WinForms interface to display the dumped information clearly. No console madness, everything is right in front of you!
- π§© Clean Architecture: The project is divided into a core library (
NativeAotDumper.Core) and a user interface (NativeAotDumper), making it easy to extend.
Imagine a window split into two parts:
| Type & Member Dump | Frozen String Dump |
|---|---|
| On the left, you see a tree of all types found in the application. Expanding any type reveals a list of its fields, properties, and methods, including their tokens and memory offsets. It's a goldmine for reverse engineering! | On the right, a long list of all string literals found in the special "frozen" region. Useful for finding keys, paths, or other interesting text data. |
The entire process can be broken down into these steps:
- Find the Process:
ProcessMemoryReaderfinds the target process by name and gets a handle to read its memory. - Find the
ReadyToRunHeader:ReadyToRunHeaderParserscans the memory for the'RTR\0'signature to find the entry point for NativeAOT metadata. - Parse Module Sections:
ModuleInfoParserreads information about all sections (likeFrozenObjectRegion,TypeMap,MetadataBlob, etc.). - Extract Strings:
FrozenStringParseriterates through theFrozenObjectRegionsection and extracts all strings by comparing their vtable with a reference one. - Metadata Magic:
MetadataResolverdoes the heavy lifting:- Reads the
TypeMaphash table to map MethodTable addresses to type handles. - Using a custom
MetadataReader, it parses the binary blob containing the metadata (MetadataBlob). - Recursively builds the full names of types by traversing namespaces.
- Gathers all the information into convenient
RuntimeTypeInfostructs.
- Reads the
- Display the Results:
MainFormsimply displays all the collected information inListBoxcontrols.
- Clone the repository:
git clone https://github.com/dadavadd//NativeAotDumper.git
- Open the
NativeAotDumper.slnsolution in Visual Studio. βΌοΈ Important Step: OpenNativeAotDumper/MainForm.csand change the target process name. It's currently set to a placeholder.// NativeAotDumper/MainForm.cs public partial class MainForm : Form { private readonly Dumper _parser; public MainForm() { InitializeComponent(); // π You need to change this line! _parser = new("YourProcessNameHere"); // e.g., "NativeAOTProcess.exe" // ... rest of the code } }
- Build and run the project (
F5). - Make sure the target application (the one you specified in step 3) is already running.
Click to expand
βββ ./
βββ NativeAotDumper
βββ NativeAotDumper (UI Project, WinForms)
β βββ MainForm.cs
β βββ MainForm.Designer.cs
β βββ Program.cs
βββ NativeAotDumper.Core (Core Logic)
βββ Enums
βββ NativeAot
β βββ Extensions
β βββ Interfaces
β βββ Parsers (Header and Section Parsers)
β βββ Utils (Main metadata parser and its dependencies)
β β βββ Metadata
β β βββ NativeFormat
β β βββ MetadataResolver.cs
β βββ Dumper.cs (Main Class)
β βββ ProcessMemoryReader.cs
βββ Structs (Structs for in-memory data)
βββ NativeAot
βββ ReadyToRun
All contributions are welcome! Feel free to fork, create branches, and send Pull Requests. If you find a bug or have an idea for a new feature, please create an Issue.
- Fork the Project.
- Create your Feature Branch (
git checkout -b feature/AmazingFeature). - Commit your Changes (
git commit -m 'Add some AmazingFeature'). - Push to the Branch (
git push origin feature/AmazingFeature). - Open a Pull Request.
This project is distributed under the MIT License. See LICENSE for more information.
- A huge thanks to the .NET team for making the
dotnet/runtimesource code open. Much of the metadata parsing logic was lovingly adapted from there. - To everyone who inspires the creation of tools like this.
