Decompressing Xamarin DLLs

While auditing a mobile application for a customer a few weeks ago, we ran into problems during the initial analysis.

The inspected software was an Android application based on .NET Xamarin. Xamarin is a framework which allows .NET code to run on multiple platforms such as Android and IOS.

Usually, the Xamarin Android APK file brings a number of Mono DLLs that directly contain “Intermediary Language” (IL) program code of the application, which we wanted to take a look at with a decompiler.

The Problem

Multiple IL analysis tools such as ILSpy refused to open the DLLs, but the files were in good shape and not encrypted. They clearly contained readable string fragments and other data, which ruled out encryption and similar obstacles. So what was going on?

After some reversing, we noticed that the DLLs were actually compressed with a custom format, which explained why ILSpy refused to work with them, but substrings of the function names and other human-readable data were still there. After searching for the magic file header XALZ, we found the public Xamarin pull request from May 2020 that described the new file format. The Xamarin developers had recently introduced LZ4 compression to make the APKs smaller, and the customer application was already built with this feature (enabled by default).

Building a Solution

Through the public documentation, we knew the file format:

[ 4 byte magic header ]
[ 4 byte header index ]
[ 4 byte uncompressed payload length ]
[ rest: lz4 compressed payload ]

Using this, we were able to whip up a quick python script that could decompress the DLLs.

Here is the essential script section:

    data = xalz_file.read()
    header_uncompressed_length = struct.unpack('<I', data[8:12])[0]
    payload = data[12:]
    decompressed = lz4.block.decompress(payload, uncompressed_size=header_uncompressed_length)

In a nutshell, we’re calling the lz4 library decompression function with the compressed payload and the parsed header_uncompressed_length header information about the original file size.

The full script can be found at the X41 GitHub

Conclusion

In the end, we ran into additional tooling problems and skipped deeper decompilation analysis, in part because we had access to most of the original source code through the customer. However, the decompression script was still useful so that basic tools such as strings could be used to quickly verify the presence of individual code functions in the build.

When looking at low-level aspects of software, writing a proof-of-concept or reversing file formats, small scripts like this often solve a special task where no suitable public solution exists yet. And since the ILSpy developers decided not to parse the new format, the script may be useful for the next audit of this type as well.

About X41 D-Sec GmbH

X41 D-Sec GmbH is an expert provider of application security services. With extensive experience and expertise in the information security industry and a strong core security team of world-class experts, X41 can provide premium security services. Their fields of expertise in the area of application security are security-centered code reviews, binary reverse engineering, and vulnerability discovery. Custom research and IT security consulting and support services are the core competencies of X41.

Date: September 22, 2020