Skip to content

C# binaries with ahead-of-time (AOT) compilation not supported #401

@Windows81

Description

@Windows81

Resource Type

Mono; GodotSharp?

https://chickensoft.games/docs/how_csharp_works

Describe the problem or limitation you are having

I'm attempting to decompile the recently-released Polytoria 2.0 Beta (link to 2.0.0-beta83).

It was built with Godot 4.6.2. Since Polytoria was previously made with Unity, it'd only make sense for them to use GodotSharp.

[application]

...

config/features=PackedStringArray("4.6", "C#", "Forward Plus")

GDRETools' Project Recovery is unable to glean any meaningful info beyond the names of C# source files. Why?

Image

GDRETools assumes that all of Polytoria's functionalities are stored in Polytoria.dll. Problem is that tools such as dnSpy and ILSpy can not parse them.

Looking in x64dbg, I found three exports from Polytoria.dll.

Image

One entry seemed interesting to me:
Address=00007FFFA320B680 Type=Export Ordinal=2 Symbol=godotsharp_game_main_init

After adding a breakpoint and restarting the program, I found that execution to godotsharp_game_main_init lands on the following stack trace:

Thread ID                        Address           To                From              Size              Party     Comment                                                                                                                                                                                                                                                      
15576 - Main Thread                                                                                                
                                 0000000000BFF1C8  00007FF7F705D88D  00007FFFA320B680  240               User      polytoria.godotsharp_game_main_init
                                 0000000000BFF408  00007FF7F9126AB1  00007FF7F705D88D  1F0               User      polytoria creator.NoHotPatch+D091ED
                                 0000000000BFF5F8  00007FF7F63B4508  00007FF7F9126AB1  1C0               User      polytoria creator.NoHotPatch+2DD2411
                                 0000000000BFF7B8  00007FF7F63C0954  00007FF7F63B4508  260               User      polytoria creator.NoHotPatch+5FE68
...

I discovered that the call returns to address 00007FF7F705D88D, which corresponds to source code in the Godot engine's modules/mono/mono_gd/gd_mono.cpp:

godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle) {
	String assembly_name = Path::get_csharp_project_name();

#if defined(WINDOWS_ENABLED)
	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dll");
#elif defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dylib");
#elif defined(ANDROID_ENABLED)
	String native_aot_so_path = "lib" + assembly_name + ".so";
#elif defined(UNIX_ENABLED)
	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".so");
#else
#error "Platform not supported (yet?)"
#endif

	Error err = OS::get_singleton()->open_dynamic_library(native_aot_so_path, r_aot_dll_handle);

	if (err != OK) {
		return nullptr;
	}

	void *lib = r_aot_dll_handle;

	void *symbol = nullptr;

	err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "godotsharp_game_main_init", symbol);
	ERR_FAIL_COND_V(err != OK, nullptr);
	return (godot_plugins_initialize_fn)symbol;
}
#endif

In here, the "godotsharp_game_main_init" string shows up.

That string is otherwise rare to find in GitHub Code Search.

Also, a string reference to ".NET: Initializing module..." appear

  1. in the same compiled function block: at 00007FF7F705D698, and
  2. in the source code: the parent function GDMono::initialize which lies in the same module file.

Therefore, my bet is safe.


Then I read about what the name try_load_native_aot_library means. AOT stands for ahead-of-time, as opposed to the just-in-time compilation that most .NET modules use.

It's harder to decompile AOT binaries than normal .NET binaries because most of the metadata is stripped.

For more info, refer to https://harfanglab.io/insidethelab/reverse-engineering-ida-pro-aot-net/.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Once the literature is found on how to decompile AOT binaries, implement that into GDRETools.

Otherwise, detect that the dll is indeed AOT-compiled and link to this issue.

This will save people hours of research that I had to undertake to reach my conclusion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions