Xamarin and Dotfuscator: Do you believe in magic?
I am not a superstitious person and I don’t believe in magic, but even still – I have to confess that the way Xamarin spits out Android and iOS apps (along with all the other platforms) feels kind of magical to me. Of course, when something breaks, I am reminded all too quickly that there is no magic happening here – Xamarin has just encapsulated a lot of complex steps into a neat and tidy black box.
For me, and I bet I am not alone here, I am very happy to leave that black box alone – and I am also happy to ignore as much of the platform-specific details as I possibly can.
Unfortunately, when it comes to security, there are platform-specific issues that simply cannot be ignored.
For example, C# developers know all too well that .NET assemblies are easily reverse-engineered yielding code as complete as the original.
This is not unique to C# and .NET. Android apps are just as easily reverse-engineered (true for all of Java – not just for Android).
Fortunately, easy reverse engineering of Android is also common knowledge – as is the availability of a free obfuscator, ProGuard (which is kind of like Dotfuscator CE).
Unfortunately, ProGuard can’t obfuscate Xamarin.Android apps (it can shrink them though).
Fortunately, Dotfuscator CE (and Professional) CAN obfuscate both Xamarin.Android and Xamarin.iOS apps. In fact, there’s a nice Xamarin guest blog on this very subject here: Protecting Your Xamarin Apps with Dotfuscator.
Unfortunately, (but not surprisingly) the fidelity between the original source code and the code extracted from the Xamarin.Android app is striking and clearly demonstrates that, as with all managed code, executable == source.
Figure 1: Side-by-side comparison of the original Xamarin.Android source code with the output generated by freely available reverse engineering utilities.
This particular code example was taken from the sample app used in the May MSDN Magazine article: Security - Detect and Respond to Rooted Android Devices from Xamarin Apps and highlights a second security issue that is unique to Android. In the Android world, preventing reverse engineering is often not enough to secure your app or its data. Increasingly, standards bodies, regulators, and lawmakers are recommending and in some cases even requiring that Android apps detect and defend against risks stemming from running apps on a rooted device.
Rooting is the process of allowing users of smartphones and other devices running Android to attain privileged control (known as root access) over various Android subsystems. Rooting an Android device gives similar access to administrative (superuser) permissions.
Further complicating matters, there is no guaranteed way to detect if an Android device has been rooted. This makes coding rooted device detection controls non-trivial for a native Android developer – and for those of us relying on Xamarin Magic, it is quite likely just an SDK too far.
What is a Xamarin.Android app developer to do?
Fortunately, Dotfuscator can also inject rooted device detection logic as well as response logic at the same time as a Xamarin.Android app is being obfuscated. This frees the Xamarin developer from having to develop the Android skills to detect a rooted device and automates the implementation of the control itself.
Further, the logic of the control is further concealed from the potential attacker through Dotfuscator’s obfuscation – making it especially difficult to defeat the rooted device control.
|App without Dotfuscator||App hardened by Dotfuscator|
|Skill Set Required||
||Use Dotfuscator GUI to create configuration file that controls Dotfuscator.|
|Effort||Days to weeks per app||Minutes to hours per app|
|Automation||None||Complete integration with Microsoft dev tool chain.|
|Auditability||Code review||Audit logs are included in build output. Fully auditable.|
|Root detection security||Detection and respond open to hacking||Also obfuscated.|
Table 1: comparing the skill, effort, and auditability of rooted device controls between unprotected Xamarin.Android apps with those that have been processed by Dotfuscator.
Code from obfuscated Xamarin.Android App using Dotfuscator Professional
Figure 2: Reverse engineering output after Dotfuscator Professional obfuscation and injection.
Figure 2 shows the output results after Dotfuscator Professional applied renaming, control flow, and string encryption transforms after first injecting rooted device detection and (in this case) the developer’s custom response – all post-compile.
In addition to the automation and auditability of the rooted device control implementation, the results of the reverse-engineering process are significantly more difficult for an attacker to analyze and exploit.
A closer inspection of the reverse-engineered code shows:
- Most names defined by the app are now meaningless letters – the method is named “i" (line 5) in a class named “a” (line 1). There’s no way for an attacker to ascertain the meaning of this method by looking at these names.
- The body of the method is non-obvious (line 7 and onward). The simple if statement and for loop have been exploded into a mess of nested switch statements and while loops, making the printed order of the code different than the execution order. This makes an attacker’s job even harder.
- The “AppStatus” string is gone. In its place is a seemingly-meaningless string (line 55), preventing an attacker from searching the decompiled code for this key. This key is only turned into “AppStatus” at runtime.
- There is no longer a constant field in this class preventing an attacker from gaining additional meaning for the string.
The app as a whole is protected against reverse engineering securing the developers’ intellectual property as well as offering another line of defense against unauthorized use of an emulator or debugger with the injected rooted device control.
What is available with Dotfuscator Community Edition (CE)?
Unfortunately, control flow and string encryption are not included with Dotfuscator CE.
Fortunately, renaming and rooted device detection and response for Xamarin.Android are included.
Figure 3: Side-by-side comparison of original source code with output after Dotfuscator CE obfuscation and injection.
Figure 3 shows the comparable results after Dotfuscator Community Edition applied renaming after first injecting its own rooted device detection algorithm and the developer’s custom response – post-compile.
Unfortunately, if you’re developing Xamarin.Android apps that handle PII, process payments, manage medical records or any of the other thousands of sensitive scenarios that may be subject to regulatory or statutory obligations, you will most likely have to address the risks stemming from rooted Android devices.
Fortunately, with the combined capabilities of Xamarin and Dotfuscator, this does not have to turn into a massive science project. You will have more time, energy, and resources to devote to building better apps and fantastic user experiences.
“Any sufficiently advanced technology is indistinguishable from magic.” Arthur C. Clarke