Skip to content
Platform
ios
Last updated: September 29, 2023

Obtaining and Extracting Apps

During development, apps are sometimes provided to testers via over-the-air (OTA) distribution. In that situation, you'll receive an itms-services link, such as the following:

itms-services://?action=download-manifest&url=https://s3-ap-southeast-1.amazonaws.com/test-uat/manifest.plist

You can use the ITMS services asset downloader tool to download the IPA from an OTA distribution URL. Install it via npm:

npm install -g itms-services

Save the IPA file locally with the following command:

# itms-services -u "itms-services://?action=download-manifest&url=https://s3-ap-southeast-1.amazonaws.com/test-uat/manifest.plist" -o - > out.ipa

Extracting the App Binary

If you have an IPA with a decrypted app binary, unzip it and you are ready to go. The app binary is located in the main bundle directory (.app), e.g. Payload/Telegram X.app/Telegram X. See the following subsection for details on the extraction of the property lists.

On macOS's Finder, .app directories are opened by right-clicking them and selecting "Show Package Content". On the terminal you can just cd into them.

Decrypting the App Binary

IMPORTANT NOTE: In the United States, the Digital Millennium Copyright Act 17 U.S.C. 1201, or DMCA, makes it illegal and actionable to circumvent certain types of DRM. However, the DMCA also provides exemptions, such as for certain kinds of security research. A qualified attorney can help you determine if your research qualifies under the DMCA exemptions. (Source: Corellium)

If you don't have the original IPA, then you need a jailbroken device where you will install the app (e.g. via App Store). Once installed, you need to extract the app binary from memory and rebuild the IPA file. Because of DRM, the app binary file is encrypted when it is stored on the iOS device, so simply pulling it from the Bundle (either through SSH or Objection) will not be sufficient to reverse engineer it.

You can verify this by running this command on the app binary:

otool -l Payload/Telegram X.app/Telegram X | grep -i LC_ENCRYPTION -B1 -A4
Load command 12
          cmd LC_ENCRYPTION_INFO
      cmdsize 20
     cryptoff 16384
    cryptsize 32768
      cryptid 1

Or with radare2:

rabin2 -I Payload/Telegram X.app/Telegram X | grep crypto
crypto   true

In order to retrieve the unencrypted version, you can use frida-ios-dump. It will extract the unencrypted version from memory while the application is running on the device.

First, configure Frida-ios-dump dump.py:

  • set it to use localhost with port 2222 when using iproxy, or to the actual IP address and port of the device from which you want to dump the binary.
  • update the default username (User = 'root') and password (Password = 'alpine') in dump.py to the ones you have set.

Enumerate the apps installed on the device by running python dump.py -l:

 PID  Name             Identifier
----  ---------------  -------------------------------------
 860  Cydia            com.saurik.Cydia
1130  Settings         com.apple.Preferences
 685  Mail             com.apple.mobilemail
 834  Telegram         ph.telegra.Telegraph
   -  Stocks           com.apple.stocks
   ...

You can dump the selected app, for example Telegram, by running python dump.py ph.telegra.Telegraph

After a couple of seconds, the Telegram.ipa file will be created in your current directory. You can validate the success of the dump by removing the app and reinstalling it (e.g. using ios-deploy ios-deploy -b Telegram.ipa). Note that this will only work on jailbroken devices, as otherwise the signature won't be valid.

You can verify that the app binary is now unencrypted:

rabin2 -I Payload/Telegram X.app/Telegram X | grep crypto
crypto   false

Thinning the App Binary

The app binary may contain multiple architectures, such as armv7 (32-bit) and arm64 (64-bit). That is called a "fat binary".

One example is the Damn Vulnerable iOS App DVIA v1 to demonstrate this.

Unzip the app and run otool:

unzip DamnVulnerableiOSApp.ipa
cd Payload/DamnVulnerableIOSApp.app
otool -hv DamnVulnerableIOSApp

The output will look like this:

DamnVulnerableIOSApp (architecture armv7):
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
   MH_MAGIC      ARM         V7  0x00     EXECUTE    33       3684   NOUNDEFS DYLDLINK TWOLEVEL PIE
DamnVulnerableIOSApp (architecture arm64):
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64    ARM64        ALL  0x00     EXECUTE    33       4192   NOUNDEFS DYLDLINK TWOLEVEL PIE

To ease the app analysis, it's recommended create a so-called thin binary, which contains one architecture only:

lipo -thin armv7 DamnVulnerableIOSApp -output DVIA32

Resources