Protect your Xamarin.Android Apps at Runtime with Dotfuscator
This is a guest blog by Bill Leach. Bill is CTO and co-founder of PreEmptive Solutions, makers of Dotfuscator and DashO application protection tools.
Protecting Your Xamarin.Android Apps
In a previous blog we discussed obfuscating your Xamarin application with Dotfuscator Community to protect it from reverse-engineering. That kind of protection is an important and necessary layer in your application’s security posture, but it shouldn’t be the only layer. The application also needs to react to threats at runtime in order to protect its own integrity, and to protect the data that it accesses.
One such threat on the Android platform is that of rooted devices. Once an Android device has been rooted (either deliberately by its owner, or surreptitiously via malware), there is no longer a strong guarantee that the operating system’s security controls are in place and working as intended. When an application is running on a rooted device, it can no longer trust the integrity of its environment. For example, it cannot assume that system calls do what they are supposed to, or that malware is not running on the device, sniffing network traffic, or logging keystrokes.
Now, in Visual Studio 15.8, Dotfuscator Community can help mitigate this threat by injecting Android root detection and response into your Xamarin.Android applications. This article will explain why and how to do that, and what types of responses you might want your application to perform.
Why Root Detection?
Joe Sewell’s article in the May 2018 issue of MSDN Magazine, “Detect and Respond to Rooted Android Devices from Xamarin Apps”. The article outlines a couple reasons why running on a rooted device can be a threat to security:
- Such environments are vulnerable to malware running on the device with elevated privileges (such as the aforementioned keylogger). You want to avoid this if your application handles personally identifiable information (PII) or other sensitive data. For example: the guidance from the Payment Card Industry (PCI) is to shut the application down and “quarantine” it (i.e. prevent it from running in the future), if it detects a rooted device.
- Such environments are a clue that the application might be under attack. One of the OWASP Mobile Top 10 threats is “Code Tampering”. Attackers will often modify and re-sign the target application in order to create a counterfeit version with a malicious payload, or to access locked features, or to circumvent other embedded security controls. The modified application typically runs on a rooted device. As a mitigation against code tampering, OWASP recommends detecting rooted devices and responding by shutting down the application and logging the incident.
- The MSDN article also references a working sample, available on GitHub, with several branches—each pre-configured with Dotfuscator Community to add root detection with a different response strategy. The article itself focuses on the master branch, which implements the “shut down and quarantine” strategy recommended by PCI.
One of the other branches (“phone-home”) demonstrates incident logging by sending a custom event to Visual Studio App Center. You might already be using App Center’s services for usage and crash reporting—this branch shows how you can customize the application’s response to rooted devices to also send security-related telemetry.
Let’s take a closer look at that scenario, to see how it works. To get started, follow the Setting up the Sample steps in the README.md file, on the “phone-home” branch. It tells you how to:
- Obtain and register Dotfuscator Community. (Ensure you have version 5.35 or higher.)
- Set up an App Center project and obtain an “App Secret”, required for sending events to App Center.
- Modify the source code with your “App Secret”.
- Build and verify that Dotfuscator is successfully integrated into the TodoAzure.Droid project’s Release build.
Once you’ve done that, you’ll have a sample Xamarin.Android application that detects when it is running on a rooted device, and responds by sending an event to the App Center analytics service.
If you run the application on a rooted device or emulator, and press the Login button, you ought to see the event in your App Center Analytics dashboard:
Launch the Dotfuscator Community GUI from the Visual Studio Tools menu, and open the config in the TodoAzure.Droid project (DotfuscatorConfig.xml). To see how the Root Check is configured, click on the Injection node on the left, then on the Checks tab to the right. You should see a “RootCheck” listed, as in the screenshot.
Double-clicking on the listed Check opens the Root Check configuration dialog:
Root Checks are associated with one or more methods in the application. These are the locations into which Dotfuscator injects the root detection logic. In this case, the Root Check is configured for a single method, the click handler for the application’s login button.
Root Checks have three properties that control the behavior of the responses:
- Action – a standard response to take if the Root Check is positive. You don’t have to write any extra code for this response–Dotfuscator injects it automatically. In Dotfuscator Community, the available standard response is “Exit”. Dotfuscator Professional includes others, such as “Hang” and “Throw an exception”. In this example, we’ve set it to “None”, because we want the customizable behavior provided by the Application Notification Sink, described below.
- Action Probability – this controls the probability of the Action occurring. In Dotfuscator Community, this is always 100%. In Dotfuscator Professional, it can be set to a lower value in order to introduce an element of randomness and unpredictability to an application under attack.
- Application Notification Sink – this is a set of three properties that collectively wire up the response to custom behavior already included in the application. In this case, the sink is configured to set a Boolean instance field, named “isDeviceRooted”, which is defined on the LoginPage class. Dotfuscator injects code that sets the field to true when a rooted device is detected. In addition to fields, sinks can also be methods or properties, defined anywhere in the application.
You can see how the sample application uses the “isDeviceRooted” field, by looking at the source code in LoginPage.xaml.cs:
The Login button’s click handler checks the value of the field and sends the event to App Center if it’s true.
This is a simple example, chosen to demonstrate how easy it is to add root detection to your application, and connect it to an application defined response. The same GitHub repository contains other branches with more complex responses, including the one outlined in the MSDN article.
In this blog post, we’ve seen how you can use Dotfuscator Community to add root detection to your Xamarin.Android application, in order to mitigate runtime security threats to both the application itself and the data it accesses.
For a deeper dive into root checks, see Joe Sewell’s MSDN article, referenced above. More information about integrating Dotfuscator with the Xamarin build pipeline, and a demonstration of Dotfuscator Community’s renaming obfuscation, can be found in the earlier blog Protecting Your Xamarin Apps with Dotfuscator.
If you want to go beyond Dotfuscator Community, Dotfuscator Professional has a broader portfolio of protection techniques for Xamarin, and is licensed for use on commercial products. Free trials are available upon request, and they include full product support.