BLOG
Table of Content
- Posted on: May 30, 2023
- By Samartha J V
- 9 Mins Read
- Last updated on: Mar 21, 2024
We went through the static analysis of Xamarin based apps on our previous blog that you can find here Xamarin Reverse Engineering: A Guide for Penetration Testers. But in this blog we are going to focus mainly on how to tackle Xamarin based apps on the iOS platform. There is a reason why we are taking up hacking Xamarin apps on iOS separately. Do read till the end to understand the nuances and learn how to blaze through your next mobile app pentest.
Let us consider a scenario where you are given a black-box security testing assignment. To put it simply no information is provided at all regarding the target. All that you know is that you have to perform security analysis on a mobile app and you are just given a link to the App Store to download the application. As a security researcher, it's your responsibility to figure out the kind of app that you’re working on and set up the analysis environment accordingly.
Disclaimer
We do not encourage pentesting against targets that you don’t have permissions for. Even though reverse engineering is not a crime and it is generally legal, do follow the law of the land. We are not liable for any of the consequences that occurred as a result of the use of this article.
For the sake of demonstration, I have chosen an app that is already open source and reverse engineering it's build from the App Store most probably will not reveal anything new. If any vulnerabilities are found, do report it here as requested by the owner of the code.
Here is is the link to get the source code of the application if you are interested and its in C# https://wcoder.github.io/open-source-xamarin-apps/#auth
Link to the App Store build of DigiD: https://apps.apple.com/us/app/digid/id1208460960
Alright, now we're gonna pretend that the above stated disclaimer is totally unknown to us and we have no idea whatsoever. We will approach this app as if it were black-box as stated in the beginning.
Static Analysis
Static analysis is used to analyze applications without executing it. One can gather a ton of information using this method, including the set of data points that are required to perform dynamic analysis. Let's go!!
Once you install the application from the App Store on your jailbroken iPhone, we need to get hold of the IPA file on our host. Apple uses FairPlay DRM to encrypt the app code but to run the application, that app code has to be decrypted and loaded into memory. Using this fact we can easily get hold of the unencrypted IPA, given that you have a jailbroken device. We can use several tools that are out there like Clutch or Frida-ios-dump, etc.
I am gonna use a tool called Bagbak, it is fast and easy to use since it doesn’t require you to know the device IP address etc to SSH into the device, but it requires frida on the device which needs to be connected over USB to make life easier: https://github.com/ChiChou/bagbak
Get the app identifier using its name, use the flag -l and grep the name of the app.
Open the application and run the Bagbak, with option -z to get the app in IPA format or else just dump the file into the Payload folder as shown below.
We can navigate into the folders and begin static analysis. First we shall determine the framework that was used to write the application since it matters a lot further down in the process on how to perform certain checks or the tools that we will use.
One of the easiest ways is to look for keywords such as Flutter, Xamarin, or Cordova, etc. From the IPA extraction image, it contains the paths to libraries that indicate that the application was built using Xamarin, to confirm the same, check for the presence of DLL files. Better have a framework detection script that will save time along the way. We can see below that the unpacked IPA file contains around 55 DLL files indicating that it is indeed built using Xamarin.
Fun Fact: You might be wondering why there would be DLL files inside an app built for iOS, instead of .dylib files??. Well, these files are used at runtime, they contain metadata which the runtime needs and it’s also used if you use reflection. Read more about it in the official documentation.
It’s Decompilation Time!!
We have listed the tools required to decompile DLL in our previous blog, I will just focus on the Apple side of things. If you encounter an app built using Xamarin which contains DLL files, it makes sense to decompile the DLL files and get the IL Code. It would be one of the easiest ways to get our hands on the code that is very close to the source code of the application. This technique totally works if the application is JIT compiled and the developers didn’t strip the IL code.
I do not wish to go deeper into the WHY of things, it is a good topic for another blog, stay tuned. But here is a discussion thread that might shed some light on the topic of preserving or stripping IL code in the interest of reducing the file size of the build or for the sake of security. Take a peak if you’re interested.
https://github.com/xamarin/xamarin-android/issues/1090#issuecomment-350741895
We will just focus on the HOW aspect of hacking instead of going off on tangents. JIT and AOT are the compilation modes offered and one can build Xamarin apps with many flags resulting in different amounts of IL code being preserved. There is a Hybrid mode as well.
After reading tons of documentation for hours and making sense of it all, here are some takeaways that I arrived at:
As per the Xamarin iOS documentation, there is a security restriction on iOS, set by Apple, which disallows the execution of dynamically generated code(JIT) on a device. To ensure that they adhere to these safety protocols, Xamarin.iOS instead uses an Ahead of Time (AOT) compiler to compile the managed code. This produces a native iOS binary, optionally optimized with LLVM for devices, that can be deployed on Apple’s ARM-based processor.
In simple words, No JIT option for Xamarin in the case of iOS and DLL files do not contain methods or the managed code but only the metadata. Which we can confirm using the images below. One from words of mono/Xamarin repo maintainer and another is a screenshot of decompiled DLL files from the DigiD IPA.
From the above image of the decompiled code, we can see that it does not contain the method body but only the names of the class and methods names are preserved. Unfortunately this is not enough to understand the entire app flow and its workings but it is possible to read hardcoded secrets and keys. You can find AOT data (.aot.arm64) files in the unpacked folder which contain the rest of the code in the form of assembly instructions.
Takeaways
-
JIT mode of compilation of applications is not supported on the iOS platform. Fully AOT compiled apps do not contain the method body which is crucial for understanding what’s under the hood of the application and begs us to dig deep instead of calling it a day after decompiling the DLL files and performing analysis on the IL Code.
-
Static Analysis on DLL files is not very useful in case of AOT compiled apps, and it applies both on Android and iOS. Reversing .so files or .aot files are neither time efficient nor easy.
-
If one has got both the android and iOS build of the application and if by luck the android build is JIT compiled and has IL code, then you can read the managed code and understand how the application works, since the managed code or the shared code is common among all the platforms in case of Xamarin but the platform code differs based on the platform of course.
-
If you get an application that has no IL present inside the DLL files, just look for hard coded secrets or api keys and check .config files for juicy stuff that might help to uncover further. We are gonna drop the static analysis here and heavily rely on the dynamic analysis to hack further.
Dynamic Analysis
Dynamic program analysis or dynamic instrumentation is the analysis of a program that involves executing the program as opposed to static analysis.
Let us now delve into the realm of dynamic Instrumentation using Frida.
Dynamic instrumentation is very powerful and I love the fact that you can do whatever the application can in that context. You can read/replace arguments for the methods, rewrite functions and return values, you’ll never get tired of it. If you can’t get your hands on the managed code? It's alright, we can hook into native functions and change the behavior of the application.
If you want to change the behavior of the application but you don’t have access to the source code? Fret not because you can achieve the same using dynamic instrumentation.
Hook Into Xamarin Classes and Methods
Being a security analyst, you have few things that are very important that you can’t skip during a mobile application pentest, such as capturing the traffic of an application using a proxy such as MiTM or BurpSuite. This is not very straightforward as it sounds when applications built using Xamarin often do not follow the system proxy or stop working if they detect the proxy etc. Even if you can capture the traffic, if the body of the requests are encrypted, then it is of very little use unless you derive the keys for the encryption method used.
When you search the internet for tools to dynamically analyze Xamarin based apps, you bump into FridaX. It is a neat little wrapper around mono-api which helps us to do a lot of things related to Xamarin dynamic instrumentation, check it out here:
https://github.com/NorthwaveSecurity/fridax
This worked charmingly on some of the android apps that we knew were Xamarin based but it failed on all of the iOS Xamarin apps I worked on. But one day I encountered an application that did have the mono module and FridaX worked on that application. So I was determined to find why some of the apps contain the mono module and some others don’t. We encountered some of the Xamarin based android apps which didn’t contain mono modules as well.
Here is the replica of the issue logged on the Fridax repo:Mono Runtime Not Found. The script was not able to find the mono module and it concluded that the mono-runtime wasn’t found. Which is partially correct in my opinion because what the script couldn’t find is just the mono_thread_attach export from the mono module, which is missing indeed.
But if you look at the diagram from the official documentation given below, there is mono runtime regardless but the mono symbols are missing in case the build didn’t have the `Debug` flag. At least that is what I tried to figure out.
The above diagram shows how the building process for the iOS AOT works.
This image shows how an IPA built using Xamarin is supposed to work during runtime. Remember the names of the runtimes here because it will help us later.
I compiled a sample Xamarin app with different flags to confirm if the mono module is retained in the Debug build. Again we are running around instead of finding out how to hook into classes and methods but this is just a scenic route that I had to take to find a few missing links.
Visual Code on Mac provides you a nice interface to figure your project and its build options.
The above image shows two apps that were compiled with the same configuration except for the debug flag. The one that has the mono module was compiled with the Debug flag and the other on the left pane of Tmux is compiled without the Debug flag.
I used a simple frida script to enumerate all the modules present to find `mono_get_root_domain`, the module which contained this export must be the mono module. Since we know it’s one of the exports from the mono module, we can work backwards and attach to the module that exported it.
But what about the apps which do not come with the mono module??? Since we do not control the build flags of our targets, right??. We are not giving up yet, there is a way.
If you dig deep enough into how Xamarin works on the iOS platform, you will get to know each of the .Net classes and methods used in the shared code/managed code contain bindings to ObjC code. I want to be as accurate as possible, so here I quote from the official documentation, “Xamarin.iOS is not merely a binding to the underlying Objective-C platform. It extends the .NET type system and dispatches system to better blend C# and Objective-C.”. Alright, let’s not beat around the bush and just jump into the solution.
Hook into Objective-C Methods and Classes in a Xamarin App
First and foremost of dynamic instrumentation is that you interact with the runtime of the respective language to put it roughly, for example ObjC runtime, Java runtime, Mono runtime ..etc, From the official documentation of the Xamarin iOS we could see that there is ObjC runtime in the picture, why not utilize that??
Lets hook to classes such as NSMutableURLRequest (subclass of NSURLRequest) to just prove our point that it is possible to just skip the managed code and directly talk to the underlying platform code and perform dynamic analysis.
DigiD API calls and its contents.
The above script works on the apps which do not have the mono module, as we thought. We are not dependent on the mono module now.
Similarly we can hook into CCCrypt to figure out the keys and operations related to cryptography (CCCrypt is just an example but if you use any tool such as Grapefruit/Objection, you can look at the libraries that are loaded and hook into those accordingly). You can read more about the bindings between the .Net managed code and the ObjC native methods and then try to hook into native methods to achieve exactly what we aimed for, capturing the traffic and decrypting the data if it is encrypted.
Unfortunately I cannot show you the apps that I have worked on and how this approach practically opened us new avenues to deal with Xamarin applications, but I have written down all the techniques and approaches that I use and these techniques constantly evolve over time.
Epilogue
We can conclude that we were able to read variables and intercept/hook functions in Xamarin AOT compiled iOS applications no matter how it was built.
If the mono module is shipped with the build, you can go ahead and use FridaX to perform dynamic analysis. For you to know the methods and its contents, we would require an android counterpart of the iOS app. So that we can decompile DLL files and get hold of the methods with its contents and later modify the behavior on runtime. If either one of the above conditions are not satisfied, then I suggest you to go ahead and directly hook into ObjC symbols which never seems to fail.
Do you think it was too much to digest ?? Are you looking for a security solution for your mobile app?, don’t look further, we at Appknox have a team of security researchers who can take care of complex tasks like these and secure things for you.
Appknox being the highest-rated security solution on Gartner, the pentest team is excellently equipped to identify and neutralize these threats way before an actual attack. It is the world's most robust plug-and-play security platform for developers and businesses that focuses on mobile application security on platforms like Android and iOS, thus allowing app testing for multiple platforms.
References :
Samartha J V
Subscribe now for growth-boosting insights from Appknox
We have so many ideas for new features that can help your mobile app security even more efficiently. We promise you that we wont mail bomb you, just once in a month.