Introduction to the Exploitation of Xamarin Apps

Post Date

Published on
Authors
Authors
Introduction to the Exploitation of Xamarin Apps

TL;DR: If you’re new to Xamarin or unsure how to analyze a Xamarin application, this post is for you. We’ll explore the key differences between Xamarin and native applications, walk you through the process of performing static analysis, and show you how to modify an app. Whether you're conducting security research or just want to learn more about app analysis, this guide will provide you with the essential tools and techniques.

In this first article, we will specifically focus on:

  1. How to determine if an application was developed by Xamarin Framework.
  2. How to automate the process for discovering Xamarin apps (research purposes).
  3. How to detect Xamarin Applications using Nuclei.
  4. Some useful tools to statically analyze and modify Xamarin applications like DNSPY, Pyxamstore and Uber APK Signer.
  5. How to decompile, modify and recompile a Xamarin application to bypass RootCheck.

Introduction to Xamarin Applications

Xamarin

Xamarin is a framework created by Microsoft. According to their website, "Xamarin is an open-source platform for building modern and performant applications for iOS, Android, and Windows with .NET. Xamarin is an abstraction layer that manages communication of shared code with underlying platform code. Xamarin runs on a managed environment that provides conveniences such as memory allocation and garbage collection." In simpler terms, it helps you develop Android and iOS applications using .NET.

Representative diagram from Xamarin Develop Model
Representative diagram from Xamarin Develop Model

Downloading Applications

If you don’t have a Xamarin application to analyze, the first challenge is finding one. This might sound easy, but we don't have exact numbers on how many applications are developed using Xamarin, though the number is lower than in Android and iOS native applications and frameworks like Flutter or React Native.

To find a Xamarin app, we downloaded several applications into a Pixel device (we started with a Pixel device instead of an iOS device because the device was charged and available). We searched through Google Play, downloading apps from categories like mobile gaming, fintech, healthcare, and travel.

Once we had a decent list of apps, we created a Python script to automate the process of identifying Xamarin apps. The script looks for certain indicators, like the presence of a .blob file, which is common in Xamarin apps.

Several applications downloaded
Several applications downloaded

Detecting Xamarin Apps

Detecting Xamarin apps on Android usually involves identifying specific files commonly found in Xamarin applications. These are .dll files and .blob files, which are part of the Mono framework used by Xamarin.

Representative diagram from Xamarin Develop Model
Representative diagram from Xamarin Develop Model

Automated tools and scripts can further help to streamline the process. If you don’t want to manually search through dozens of apps, automating the flow with a Python script makes things faster and easier.

Automating Xamarin Detection

To streamline the process of detecting Xamarin apps, we wrote a script. This script checks for the .blob file, a known marker in Xamarin apps. It avoids downloading apps developed by Google to ignore apps we don’t need to analyze.

Below is a brief overview of the script’s flow:

  • Download apps from Google Play
  • Check the app's internal files for Xamarin indicators such as .blob files
  • Exclude apps developed by Google
Automating Xamarin Detection
Python script snippet developed by the Just Mobile Security Team to find Xamarin Apps from decompiled Android Applications.

In iOS, remember that the app must be decrypted first before performing static analysis, because if not, the information within the application will be inaccessible. You can check how to download the decrypted application in our blog post How to Improve Your Android & iOS Static Analysis with Nuclei! where we cover how to dump the ipa file from your device.

Conclusion of detecting applications

After downloading 259 apps randomly only 9 were developed using Xamarin. This shows how relatively uncommon these frameworks are compared to others like React Native or Flutter.

Conclusion of detecting applications
The output after run the Xamarin recognition Python script

Creating a Nuclei Template

Next, let’s create a Nuclei template to help identify Xamarin applications. Nuclei is a fast, customizable vulnerability scanner, and it can be used to automate various types of scans. If you don't know Nuclei you can check our Blog Post where we cover the first steps for analyzing applications with Nuclei

Here’s a basic template structure for Xamarin apps to get you started:

id: xamarin-common-files
 
info:
  name: Xamarin Application Detection in Common Files
  author: Juan Urbano Stordeur
  severity: informational
  tags: xamarin_apps
 
files:
  - path: /path/to/your/files
	recursive: true
	matchers:
  	- type: grep
    	part: content
    	condition: any
    	words:
      	- "assemblies/assemblies.blob"
      	- "Xamarin"
      	- "dll"
 
	extractors:
  	- type: regex
    	regex: "Xamarin.*\.dll|.*\.dll|assemblies/assemblies\.blob)"

Static Analysis

When it comes to performing static analysis to Native Android applications we are used to using the same old good tools like Jadx, Jadx-gui, apktool, etc. but what happens when we want to use the same techniques and tools over a Xamarin app? Basically we are going to see only the Java/Kotlin/Smali code with the application logic that is intended to load the Xamarin components but we will not be able to see any applications logic within the Java/Kotlin/Smali code.

That's why performing static analysis for Xamarin applications is different than Native applications, because, Xamarin apps are typically written in C# and .NET and compiled into Intermediate Language code, which is packaged in .dll files.

When it comes to static analysis, tools like DNSPY are the best option for analyzing Xamarin applications. DNSPY is a debugger and .NET assembly editor. You can use it to edit and debug assemblies, with the following main features:

  • Debug .NET assemblies
  • Edit .NET assemblies
  • Light and dark themes
DNSPY running example

Comparing Static Analysis Tools

As we’ve mentioned before, analyzing Xamarin and Native Android apps are different types of analysis and they require the use of different tools, that's why we wanted to show you and compare how different reverse engineering tools shows their respective outputs while analyzing Xamarin Apps.

  • JADX: Take a look at how, in the main package, there are only a few attributes and only one class that is related to the app itself. The same thing happens with Apktool and the Smali code. That is because all the application logic is inside the .dll file in the assemblies.blob file. Basically, we can't get any information if we don't decompile the dll files.
Comparing Static Analysis Tools
  • DNSPY Take a look at the DNSPY output and you will see that here we are able to read the application’s logic, classes, methods, and more.
Comparing Static Analysis Tools

As we mentioned DNSPY is a powerful .NET decompiler and debugger, perfect for analyzing Xamarin apps, since they rely on .NET assemblies. It allows security researchers to inspect the app's code, look for vulnerabilities, binary protections and understand its internal logic.

To use DNSPY, simply:

  • Open DNSPY.
  • Navigate to File > Open, and select the .dll files from the app you want to analyze (commonly found in Xamarin apps).
  • Once loaded, you can view the code, inspect classes, methods, and even edit them.
DNSPY selecting dlls
Example of loading all the dll files from a Xamarin app into DNSPY

Additional Xamarin Reverse Engineering Tools

Other useful tools that we can use to reverse-engineer Xamarin apps are Pyxamstore and Uber APK Signer.

Pyxamstore

In some cases after we decompile the APK we will see that inside the unknown/assemblies/ folder we find the .dll files inside it, so we can use dnSpy directly over the .dlls to analyze the app. But sometimes we will find the assemblies.blob and the assemblies.manifest files inside the unknown/assemblies/ folder, and that's where pyxamstore comes into play. This is a tool used for unpacking the assemblies.blob file in Xamarin apps, allowing access to the .NET assemblies for further analysis.

Uber APK Signer

This is a utility tool that simplifies signing multiple APKs with the same key, ensuring consistency across signed Android applications.

Common Vulnerabilities

Xamarin apps can be vulnerable to static binary modifications (client-side modifications), which allow for the creation of unintended behaviors. For example, in Unity apps, this can lead to cheats in games, while in Xamarin apps, it might enable bypassing paywalls for in-app purchases. A classical scenario is when we need to analyze a Xamarin application with several binary protections or when it uses some kind of protector.

Binary Protections

To mitigate misuse, many apps implement various protections such as:

  • SSL Pinning: ensures that the app only communicates with trusted servers, preventing traffic interception. Obfuscation: makes the code more difficult to reverse engineer by obscuring the app’s logic.
  • Root Check: prevents the app from running on rooted devices, limiting potential tampering.
  • Anti-emulation: detects whether the app is being run in a virtual environment, often used for testing and debugging.

However, these protections are often bypassable. In the following section, we’ll demonstrate how to bypass root check protection in the CAPTIO app (a public application downloaded from the PlayStore).

Bypassing Root Check on Xamarin Application

  1. After finding a Xamarin app among the 259 downloaded applications, we proceeded to start the application and found that it has Root Check as can be seen in the following image
Potentially evidence for a binary protection
Potentially evidence for a binary protection
  1. So we proceeded to download the APK from the device using adb. It should be noted that we carried out this step in a Windows PC, so the commands may differ a little from Linux commands. Feel free to choose the one that best suits your needs. To download the APK we will use the following commands:

In Linux:

adb shell pm list packages | grep captio

In Windows:

adb shell pm list packages | Select-String caption

Then:

adb shell pm path caption.ongest.com
adb pull /data/app/{appFolderHash}/captio.ongest.com{Hash}/base.apk

It should be noted that, in this particular case, the application uses multiple APKs for the installation, also known as Split Config, if you want to understand better why Split Config APKs are needed you can follow this link. In order to be able to reinstall the application after modifying it, we will need to download all the APKs listed in the folder. Use $ adb pull to get all de APKs

ADB pull apks
  1. Once we have the APK, we will decompile it using Apktool with the following command
apktool d base.apk
  1. Now that the process has finished, and we have our app decompiled with Apktool, we will use pyxamstore to unpack the assemblies.blob file using the following commands:
cd base/unknown/assemblies/
pyxamstore unpack -d /<pathToDecompiledApkFolder>/base/unknown/assemblies/
APKTool pyxamstore
  1. Now we have all the .dll files inside the generated "out" folder. Now we can proceed to open them with DNSPY. We are going to open DNSPY -> go to file -> open -> and select all the files and folders contained in the "out" folder.
DNSPY selecting dlls
  1. Now that we have all the dll files opened in DNSPY, we can proceed to search for whatever you want to analyze within the application. In this case, it’s Root Check validations. We use the search functionality and enter the key word “Rooted” and without much effort, we’ve found the RootCheck class and methods.
DNSPY searching rootcheck
  1. Now we can right-click on the method/class we want to edit and click on the edit option.
DNSPY edit method
  1. Now we are in the editor where we can change whatever we want, like logic operators, parameter values, etc.

  2. In this particular case, we have seen that the implementation of the RootCheck functionality was creating some sort of RootCheck Profile which validated if the device was rooted.

  3. There are various techniques that could help us in the process of Statically bypassing Binary Protections, you can check our Blog Post where we cover some of those techniques which may include, tampering the strings that are validated to determine if a device is rooted, changing the return value to false as result of the validation and more, in this particular case we needed to avoid the creation of the RootCheck Profile so we decided that the most efficient and quickest way to bypass the RootCheck was to erase the contents of the “CheckDeviceRooted” class.

  4. Then we hit the compile button and our class gets modified.

DNSPY compile
  1. Now we just have to save the changes, and we are ready to start compiling and packing the app again. To save the changes, go to File -> Save All.
DNSPY save all changes
  1. Now let's go back to the assemblies folder, because all the changes we’ve made are in the generated “out” folder. We need to use pyxamstore to repack the .blob file. These are the commands:
cd base/unknown/assemblies/
pyxamstore pack

(Here, we will see multiple files created with the .new extension added to them, so we are going to replace the old files with the new ones.)

rm assemblies.blob assemblies.manifest
rm -r out/
mv assemblies.blob.new assemblies.blob
mv assemblies.manifest.new assemblies.manifest
cd /<pathToDecompiledApkFolder>/Captio/Training/
apktool b base/ -o CaptioModified.apk
Rename and remove old assemblies
  1. Once we have our modified and recompiled APK. we can use zipalign to align the APK and get it ready for installation, but remember that we had multiple APKs because of the Split Config. We need to sign all the APKs. To achieve this effectively we recommend using zipalign to align all the APKs, if you want to understand more about the Zip Aligning process you can refer to this link.

  2. Then we will use the Uber APK Signer utility to sign them. We need to do this because, when we use zipalign to re-align the split config APKs (even though we didn't modify them), the resulting files are unsigned and can be signed directly with Uber APK Signer to avoid any kind of signature conflicts. The commands are the following:

mkdir AlignedAPKs (this is to maintain order within so many APKs)

zipalign -p -f -v 4 CaptioModified.apk AlignedAPKs/CaptioModified_Aligned.apk
zipalign -p -f-v 4 split_config.arm64_v8a.apk AlignedAPKs/split_config.arm64_v8a_Aligned.apk
zipalign -p -f -v 4 split_config.en.apk AlignedAPKs/split_config.en_Aligned.apk
zipalign -p -f -v 4 split_config.es.apk AlignedAPKs/split_config.es_Aligned.apk
zipalign -p -f -v 4 split_config.xxhdpi.apk AlignedAPKs/split_config.hdpi_Aligned.apk
Zipalign
  1. Now we have re-alligned all the APKs, and we can continue with:
java - jar /home/ubuntu/Downloads/uber-apk-signer-1.3.0.jar --apks /<pathToDecompiledApkFolder>/Captio/Training/AlignedAPKs/
Uber APK Signer
  1. It looks like everything is ready to install the modified app! Let’s use adb to install it!
cd .\AlignedAPKs\Signed\
adb install-multiple .\CaptioModified_Aligned-aligned-debugSigned.apk \
.\split_config.arm64_v8a_Aligned-aligned-debugSign ed.apk \
.\split_config.en_Aligned-aligned-debugSigned.apk \
.\split_config.es_Aligned-aligned-debugSigned.apk \
.\split_config.xxhdpi_Aligned-aligned-debugSigned.apk
ADB Install fail
  1. Something failed during the installation. This is a common problem that we can face while reverse-engineering applications. Sometimes, during the decompiling process with Apktool, some errors may show up. However, the process will not stop and the extraction will be completed with some errors. In this case, we can see this error when the installation fails. Let's take just a second to analyze the error and continue.

  2. This particular error says:

adb: failed to finalize session
Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during
installPackageLI: /data/app/vmdL931850051.tmp/base.apk (at Bin
ary XML file line #29): ‹meta-data› requires an android: value or android:resource attribute]
  1. Basically, it tells us that the error occurred in the Android Manifest in line 29 and says that a value is required for the “android:resource” attribute. Let's find that file and fix the error.

  2. We don’t need to decompile the application again. Just delete the modified, aligned and signed APKs to avoid confusions and search for the AndroidManifest.xml file within the folder named "base", which was created by Apktool in step 3. Open the file with any text editor and go to line 29. The line says the following.

<meta-data android: name="com.google.firebase-messaging.default_notification_icon" android:resource="@null"/>
  1. Great! The problem seems to be the "@null" value. We make a really quick Google search to find that this problem can be fixed by changing the "@null" value for @string/default_notification_channel_id and adding the com.google.firebase-messaging.default_notification_icon with the value captio.ongest.com

AndroidManifest.xml (Replace the null value)

<meta-data android: name="com.google.firebase-messaging.default_notification_icon" android:resource="@string/default_notification_channel_id"/>

/res/values/strings.xml (Add the new string value)

<string name="default_notification_channel_id">captio.ongest.com</string>
  1. Now, the problem should be solved, and we can rebuild the APK once more. Let’s use all the commands for rebuilding, aligning and signing the APKs again:
apktool b base/ -o CaptioModified.apk
mkdir AlignedAPKs

(this is to maintain order within so many APKs)

zipalign -p -f -v 4 CaptioModified.apk AlignedAPKs/CaptioModified_Aligned.apk
zipalign -p -f-v 4 split_config.arm64_v8a.apk AlignedAPKs/split_config.arm64_v8a_Aligned.apk
zipalign -p -f -v 4 split_config.en.apk AlignedAPKs/split_config.en_Aligned.apk
zipalign -p -f -v 4 split_config.es.apk AlignedAPKs/split_config.es_Aligned.apk
zipalign -p -f -v 4 split_config.xxhdpi.apk AlignedAPKs/split_config.hdpi_Aligned.apk
java - jar /home/ubuntu/Downloads/uber-apk-signer-1.3.0.jar --apks /<pathToDecompiledApkFolder>/Captio/Training/AlignedAPKs/
  1. Almost done! Now we try to install the app one more time
cd .\AlignedAPKs\Signed\
 
adb install-multiple .CaptioModified_Aligned-aligned-debugSigned.apk \
  .split_config.arm64_v8a_Aligned-aligned-debugSign ed.apk \
  .split_config.en_Aligned-aligned-debugSigned.apk \
  .split_config.es_Aligned-aligned-debugSigned.apk \
  .split_config.xxhdpi_Aligned-aligned-debugSigned.apk
ADB Install success
  1. We did it! We opened the application and found that the RootCheck bypass worked.
Captio APP un routed
  1. Great! We have bypassed the RootCheck of a Xamarin Application! Here we recorded this video with all the steps :) Youtube - Bypassing Root Check in a Xamarin Application

Conclusion

While Xamarin offers powerful tools for mobile app development, they also introduce unique security challenges. Of the 259 apps we analyzed, only 9 were Xamarin-based, highlighting their rarity. Still, understanding how to identify and analyze apps built with these frameworks is essential for mobile security research.