Mobile Application Testing on Apple Silicon

Are you torn between testing your mobile application on a Mac or a jailbroken iPhone? With the introduction of Apple Silicon, the decision may not be as clear-cut as it once was.

In this blog post, we will explore the benefits of performing Mobile Application Tests on Apple Silicon, the setup for testing on Apple Silicon systems and provide a hands-on example. While discussing the benefits we will also point out limitations and drawbacks.

What is Apple Silicon?

Before we dive in; What is Apple Silicon anyway? Apple Silicon refers to the “chips” manufactured by Apple that are used in most of the company’s devices today. Back in November 2020 Apple introduced the M1 Chips (and later M2) as part of all new Mac systems. Until then Apple used Intel Processors, which use the x86 CPU Architecture, while Apple Silicon is built on the ARM64 Architecture.

Mobile applications can now be run natively on Mac systems with M1 or M2 Chips, thanks to the fact that iPhones and iPads are built on the same ARM architecture.

Benefits of Testing on Apple Silicon

Y-Security performs Mobile Application Tests against various platforms and implements a testing methodology which align and complete common methodologies and frameworks. In particular the OWASP Web Security Testing Guide, the BSI Leitfaden IT-Sicherheits-Penetrationstest, applicable CIS Benchmarks, the MITRE ATT&CK® Framework and Mobile Application specific security guidelines.

In the past, iOS Mobile Application Tests have traditionally been performed on physical devices, such as iPhones or iPads. To perform a Penetration Test according to our methodology, we require root-level access to the device. This can usually only be obtained by using a Jailbreak. Jailbreaking refers to the process of removing software restrictions imposed by Apple on its iOS operating system, which allows users to access and customize the device in ways that are not normally possible. Basically, it gives users root/full access to the iOS file system and allows them to install applications, tweaks, and extensions that are not available in the Apple App Store.

Usually, Jailbreak exploits aren’t available for the latest iOS versions as Apple remediates those quickly after a public disclosure happened. Depending on the used iOS version and device a jailbreak may not be working as expected or usable. Therefore, the M1and M2 Macs are a good alternative.

With one of the new M1 or M2 Macs, we don’t need to worry about any of that. We already have full control of the computer, meaning we also have root-level access. Our only obstacle will be getting the app to run properly and bypassing any jailbreak detection within the application. This is something we would also have to deal with on a jailbroken device.

Updating the Mac regularly and keeping it on the latest version of macOS is no longer a problem as we are no longer dependent on the availability of jailbreaks and exploits.

Collaboration is simplified by using a Mac for testing. It can be set up on a shared network and made accessible to colleagues, eliminating the need for physical device access. This is an added benefit of using a Mac for testing.

Drawbacks

On the other hand, testing on a Mac is not without its disadvantages, which I would also like to discuss briefly.

  • It is currently not possible to use FaceID or TouchID when running an application on Mac since both of these features are depended on hardware only available in iPhones. Some apps, e.g. banking apps, might require this feature and might not work as expected.
  • Not every application will work out of the box, especially applications that are built for older iOS versions.

The iOS Keychain is still usable and can be dumped and modified with a tool such as objection. Unfortunately, items that are protected by TouchID or FaceID might not be accessible due to the reason listed above.

Because of those few drawbacks, it’s always good to have a physical iPhone available that could be used for basic testing as Penetration Testers should never limit themselves to a single tool.

What do we need?

Before we can start a Penetration Test, these things are required:

  • A Mac system (M1/M2) with root-level access
  • A Decrypted IPA file (preferably built for iOS & iPadOS)

In order to run unsigned code, we need to disable System Integrity Protection (SIP), as described by Apple in their post about Disabling and Enabling System Integrity Protection.
Please Note:This should only be done on testing devices and never on personal devices since it will drastically decrease the security of the system.

It is not required that the app is built for iPadOS, although it ensures that it runs natively on the Mac and it would even be possible to download it from the App Store on the Mac. Most applications, such as WhatsApp or Snapchat, are only built for iOS and thus are not available through the Mac App Store.

How does it work?

Some applications are already built for iPadOS and will likely run without any tools or modification. This case is the best-case scenario for a Penetration Test as there won’t be many complications in carrying it out.

However, most applications have only been built for iOS and iPadOS. These applications will crash without any modifications. There are already tools available, which will modify and be able to launch those apps with a single mouse click. However, I would like to quickly outline how these tools accomplish this seemingly magical task.

As discovered by secura in their iOS Apps on ARM Macs: Pentesting Opportunities Part II blog post, Apple uses some undocumented API calls to launch a graphical application. These calls require a parameter that tells the operating system what kind of bundle structure it should expect, e.g. an iOS bundle or MacOS bundle. Secura also pointed out the structural differences between iOS and MacOS applications in their first post about iOS Apps on ARM Macs: Pentesting Opportunities.

When trying to launch the copied mobile application binary, the operating system still sets the argument as PLATFORM_MACOS and expects a MacOS application, resulting in a crash. It is necessary to change this argument to PLATFORM_IOS as well as calling some of those undocumented API calls to simulate a correct application launch. Secura implemented this procedure in their own tool named launchr.

Purpose Notes
launchr Tool for launching graphical iOS and macOS apps on ARM Macs by modifying and controlling the launch process of the desired application. No modifcation of application binary needed.
PlayCover Tool to run iOS apps and games on ARM Macs with a multitude of features, such as Emulation of different devices and built-in Jailbreak detection Bypasses. Modifies the application binary and injects custom dylibs.
PlayTools Library used in PlayCover, which implements most of the core features, such as Controls, Keymaps and the mentioned Bypasses. Can be disabled for specfic applications.
Frida Dynamic instrumentation toolkit for developers, which allows us to inject intro running processes to hook and trace any function.
objection Objection is a runtime mobile exploration toolkit, powered by Frida, built to help you assess the security posture of your mobile applications, without needing a jailbreak. Frida is required to run objection.
fridump Python script leveraging Frida to dump the memory of a running process. Slight modification required.
Tools discussed in this blog post

OWASP Crackme on Apple Silicon

In a short demo we show how to set up and test the OWASP iOS Crackmes. They can be downloaded via the OWASP iOS Crackmes site. They are great for demonstrating the whole setup and even some basic testing methods.

PlayCover

To run the app, we will use the PlayCover tool, which allows us to run almost any iOS app on Apple Silicon Macs. It was originally developed with the aim of running mobile games like Genshin Impact on a Mac and having the ability to play on a larger screen. Though it can be used to run regular apps just fine too.

While launchr works as an external tool to literally set up and launch the target application with the desired parameters, PlayCover modifies the target binary and injects its own dylib PlayTools. This dylib implementes all interesting features like setting the correct platform to make the application work with MacOS. It is also responsible for defeating several known Jailbreak detection mechanisms within PlayShadow and more.

The installation works like any regular application for MacOS. Just download the latest release and drag it into the Applications folder. PlayCover has a great wiki containing detailed information about the installation and its various features.

To import an app into PlayCover, simply click the + sign and select the .ipa file via the Finder application.

Alternatively, you can use the IPA Library to add apps via a source file. This will be a URL to a JSON file, which includes a list of apps with information such as name, version and the download link.

After importing, it should be possible to launch the app by double-clicking on it. Before we do that, we should adjust some of the settings. Most importantly we want to disable the “Discord activity” feature, which lets you share your game status through Discord RPC. This feature is enabled by default and adds addtional code to the application, which we won’t need for testing.

Other things we can configure include the device that is being emulated along with its screen size, key-mapping and even a built-in Jailbreak detection bypass.

All applications that are installed via PlayCover can be found under /Users/<user>/Library/Containers/io.playcover.PlayCover/. The data directory, which might store files related to the app, can be found at /Users/<user>/Library/Containers/sg.vp.UnCrackable1.

Hands-On

Now it is time to run the app and solve the challenge. The task is pretty simple:

A secret string is hidden somewhere in this binary. Find a way to extract it. The app will give you a hint when started.

OWASP’s UnCrackable1 (iOS)

With the app running, it is time to finally set up our favorite tool for mobile assessments, frida. It has become essential for any mobile application assessment and allows to observe and alter the behavior of an app while it’s running. All we need to do is install the frida-tools package via pip and then grab the latest frida-server for macos-arm64.

The OWASP’s UnCrackable1 app consists of a single input field with a button below it, that lets us verify if our input was correct or not. It also contains a hint, telling us that the secret can be found within a hidden label in the UI. There are multiple ways to reveal the secret from the hidden label. I used the tool objection, which is built on top of frida, to dump the UI of the app and read the secret.

The only thing that should be noted when using frida or objection on a Mac is that the connection is made via the network and not via the standard USB port.

Looking at the above output, we can see two UILabels within the UIView, one of them being marked as hidden.

<UILabel: 0x12212c810; frame = (0 20; 85 21); text = 'i am groot!'; hidden = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60000242a620>>

Upon entering this string into the textbox, a success message pops up and the Crackme is solved.

Additional OWASP Checks

Since this Crackme is a rather small application and not very representative of a typical penetration test, I want to show some common Penetration Testing steps taken from the OWASP Mobile Security Testing Guide, which we also implement in our Mobile Application Testing methodology.

Memory Dump

A good example is dumping process memory to search for sensitive information, as explained in the OWASP MSTG. Normally we would use fridump to read the process memory of the iOS device via a USB connection. In our case, there is no USB device to connect to, so the script fails. The following diff shows the changes to allow fridump to connect via the frida port.

Caution: Never directly expose the port opened by frida-server, instead forward it locally via SSH.

35a36,39
>     parser.add_argument('-H', '--host', type=str,
>                         help='host to connect to')
>     parser.add_argument('-P', '--port', type=int,
>                         help='port to connect to')
53a58,59
> HOST = arguments.host
> PORT = arguments.port
73a80,81
>     elif HOST != None:
>         session = frida.get_device_manager().add_remote_device(f'{HOST}:{PORT}').attach(APP_NAME)

The patch can be applied with patch fridump.py fridump.diff -o fridump_mod.py. Now it’s possible to use with just the frida port:

:~/fridump$ python3 fridump_mod.py -H localhost -P 27042 'UnCrackable1'

        ______    _     _
        |  ___|  (_)   | |
        | |_ _ __ _  __| |_   _ _ __ ___  _ __
        |  _| '__| |/ _` | | | | '_ ` _ \| '_ \
        | | | |  | | (_| | |_| | | | | | | |_) |
        \_| |_|  |_|\__,_|\__,_|_| |_| |_| .__/
                                         | |
                                         |_|
        
Current Directory: /home/thore/y-tools/fridump
Output directory is set to: /home/thore/y-tools/fridump/dump
Starting Memory dump...
Progress: [################################################--] 96.71% Complete
Finished!

Alternatively, we can use the builtin debugger lldb to generate a core file. That way we don’t have rely on any third-party tools.

sh-3.2# lldb --attach-pid 13827
...
(lldb) process save-core "uncrackable1.dmp"

Now these memory dumps can be analyzed and searched for sensitive information, such as passwords or other secrets.

Keychain Access

The Apple Keychain is a secure storage to manage secrets for an application or a specific use-case. All items in the Keychain are encrypted with an identifier unique to the device it is being saved on. Though it depends on the device, the Keychain still works similarly when using mobile applications on Apple Silicon. There are two different ways to access the Keychain and read its content.

With objection we can easily add new Keychain items and dump them. The UnCrackable1 application, doesn’t have any Keychain items, however I will show how to add one with objection.

Below is command that adds a new Keychain entry for the user ysec with the secret mysecret, which will be associated with the UnCrackable1 application. If the service parameter is left empty, the entry will show up as unknown in the Keychain.

sg.vp.UnCrackable1 on (iPad: 16.2) [net] # ios keychain add --account ysec --service UnCrackable1 --data mysecret
Adding a new entry to the iOS keychain...
Account:  ysec
Service:  UnCrackable1
Data:     mysecret
Successfully added the keychain item
sg.vp.UnCrackable1 on (iPad: 16.2) [net] # ios keychain dump
Note: You may be asked to authenticate using the devices passcode or TouchID
Save the output by adding `--json keychain.json` to this command
Dumping the iOS keychain...
Created                    Accessible    ACL   Type      Account  Service       Data
-------------------------  ------------  ----  --------  -------  ------------  --------
2023-05-09 07:54:06 +0000  WhenUnlocked  None  Password  ysec     UnCrackable1  mysecret

Alternatively, the Keychain can be accessed through the built-in Keychain Access application on MacOS.

Conveniently, this interface allows to manage all Keychain items, not just those related to a single application. By double-clicking on an item, we can modify it and reveal the associated password.

As previously mentioned, we lack the possibility to configure FaceID and TouchID, since these are iOS only features.

It should be noted that new versions of PlayCover now emulate an entire Keychain with their own implementation named PlayKeychain. When using this Keychain, a separate Keychain directory under /Users/<user>/Library/Containers/io.playcover.PlayCover/PlayChain/sg.vp.UnCrackable1/ will be created for the application. Each item will be stored in a plist file, which makes analyzing the Keychain usage of the application easier.

Conclusion

With this post we wanted to demonstrate how Apples switch to Apple Silicon made Mobile Application Testing a lot easier. While it isn’t perfect yet, it removes a lot of headaches by eliminating the dependency on Jailbreaks and sophisticated exploits against iPhones. It gives the tester a lot more control and reduces the complexity of a classic mobile testing setup since no physical iPhone is required.

Get In Touch With Us For Consultancy

We have more to say and present which doesn’t all fit into a post. If you are interested in further information about our Mobile Application Testing Methodology, or Penetration Testing and Attack Simulation Services, then give us a ping via request@y-security.de.

Thore Imhof
thore@y-security.de
Y-Security GmbH
14. June 2023