Managed code keeps the client readable
A Xamarin.Android or .NET MAUI package carries the application layer as managed assemblies. The Android runtime for .NET loads a native runtime library and then reads those assemblies, so the package holds both the native runtime and a managed payload. The assemblies keep type names, method names, field names and string constants unless a separate .NET obfuscator changed them. That is the structural difference from a Kotlin app put through R8, where names disappear and calls are inlined into their callers.
The practical result is that the HTTP client and the signing code can be read in a decompiler window. The engagement then becomes a reconstruction and testing job rather than an instrumentation job, and the estimated effort drops with it.
The order to read the package
- List the package contents and find the managed payload. Builds commonly store the assemblies in one compressed bundle with a manifest that lists them, so the entries inside the package do not carry the assembly names. Other builds keep assemblies as individual entries. Either way, locate the store before looking for a class.
- Unpack the store into individual assemblies. An assembly store has a fixed internal layout, and a short script or an existing extraction tool produces separate files that a decompiler can open.
- Open the assemblies in a .NET decompiler. A tool such as ILSpy, dnSpy or dotPeek shows C# with names intact and searches across the whole application instead of one file at a time.
- Identify the HTTP client style. A raw HttpClient call site builds a request and awaits a response. A declarative client such as Refit declares routes in attributes on an interface, which turns the endpoint inventory into a list of interface methods. RestSharp builds a request object with a path and a verb as constructor arguments. Each style needs a different search.
- Read the models and their serialisation attributes. Property names and their attributes define the JSON keys, including names that differ from the C# property.
- Read the startup configuration and the request pipeline. The base URL, the default headers, the authentication handler and any message handler that signs requests are usually registered in one place.
What .NET MAUI changes
MAUI is the successor to Xamarin.Forms, and it keeps the same managed runtime and the same packaging model. The user interface layer changed and startup moved into a host builder, so the code that registers services looks different. The API surface still sits in a service layer written in C#, and the reading order is unchanged. Two build settings alter what you get. Trimming and linking remove code the build believes is unused, so a method can be absent or folded into its caller. Ahead-of-time compilation translates some method bodies into native code while leaving declarations in the assembly, so a decompiler shows a stub where the body used to be.
Reproduce the client outside the app
The reconstruction covers more than an endpoint list. Record the base host and any path prefix, the verbs and paths, the headers that every request carries, the payload shapes, and the calls that obtain and refresh a token. Then handle the values that change per request: a signature, a timestamp, a nonce or a device value. Finally, describe the state that has to survive between calls, because a client that treats each call as independent breaks on the second one. The result ships as a Python, JavaScript or TypeScript client alongside an importable Postman collection and documentation.
Where a Xamarin project stalls
- A compressed or encrypted assembly store stops a direct decompile, so the unpacking step has to be solved before any reading starts.
- A .NET obfuscator renames members and can encrypt strings, which removes the readable names that make these builds attractive.
- Ahead-of-time compilation moves bodies into a native library, so the decompiler shows declarations without implementations.
- Values derived from the keystore, from attestation or from a server handshake cannot be copied out of the code and need a reproduction strategy instead.
Each condition has a documented next step, and none of them changes the order of the work. A project that starts with the store, moves to the service layer and ends with a test run against the live account stays predictable.
Deliverable
The work ends with a client that authenticates, performs the flows in scope and survives token rotation. Xamarin and .NET MAUI Android reverse engineering describes the engagement.
Related work
Reviewed 28 September 2026 · SReverse research desk