Even though there are already many, many blog posts, tutorials and even youtube videos about "reverse engineering iOS apps", every time Apple releases a new iOS version the "game" changes; researchers have to find a new way to jailbreak the new released version of iOS and we have to update our tools to work with the new jailbroken environment. This is especially true for the latest iOS 11 jailbreak, both LiberiOS and Electra jailbreaks, which are based on Ian Beer's async_wake exploit, have very different techniques than the previous jailbreaks and most (all?) of the existing tools are broken on these jailbreaks.

I'm going to focus on LiberiOS for this post since that's the only jailbreak I've tested. But also because I'm a huge fan of Jonathan Levin's work and his contributions to the community. The LiberiOS jailbreak is what's called a KPP-less jailbreak (KPP stands for Kernel Patch Protection). It basically means there are no modifications to the kernel areas that KPP guards, and most of the jailbreak tools (like Clutch, dumpdecrypted) and all of the tweaks that depend on Cydia Substrate haven't been updated to work with this approach.

This post ended up being a bit too long, so I decided to split it in two parts:

  • Part 1: Will help you setup your device and decrypt iOS apps
  • Part 2: Will help you dump the app's classes, disassemble its instructions and manipulate the runtime to change the app's behaviour

Syllabus

Part 1

  • Jailbreak your device (external link)
  • Setup iTunnel
  • Setup bfinject
  • Decrypt Starbucks iOS app using bfinject decrypt

Part 2

  • Dump Starbucks app's Classes using class-dump
  • Disassemble the Starbucks app using Hopper
  • Runtime manipulation using bfinject cycript

To begin RE'ing iOS apps you need a jailbroken device. In this post I'm assuming you are on iOS 11 so let's start with jailbreaking your device. I like the iClarified tutorials and they have a great one for jailbreaking your iPhone/iPod/iPad (iDevice) on iOS 11-11.1.2:

  • Follow iClarified's tutorial to jailbreak your iDevice using LiberiOS here.
    Now that your iDevice is jailbroken we can start reverse engineering iOS Apps!

Setup iTunnel

Even though LiberiOS' version of Dropbear SSH has wifi connectivity enabled, I find USB faster and more reliable. To SSH into your device via USB using your lighting cable you'll need to setup iTunnel (or a similar tool).

  • Download the latest version of iTunnel from here
  • Extract the contents of the .zip file
  • Copy the itnl binary to /usr/local/bin
  • Copy the libmd.dylib library to /usr/local/lib
    You can also leave both files in a folder and execute the itnl command with the ./ prefix.

Setup bfinject

As I said before, many of the existing tools don't work as in previous jailbreaks, but thanks to Bishop Fox we can now use Clutch in LiberiOS by doing the following:

  • Create a folder called bfinject in your desktop
  • Download the latest tarball in the bfinject folder
  • Run itnl to forward the ssh traffic to a different port, --lport is the local port and --iport is the iDevice port:
> itnl --lport 2222 --iport 22
  • In a different terminal session SSH into the iDevice:
> ssh -p 2222 root@localhost
  • Enter the root password, the default password is alpine (though you should change it)
    liberios-ssh
  • To enable the binpack add the binaries directories to PATH:
# export PATH=$PATH:/jb/usr/bin:/jb/bin:/jb/sbin:/jb/usr/sbin:/jb/usr/local/bin:/sbin:/usr/sbin:/usr/local/bin:
  • Create a bfinject folder in /jb and change directory to it:
# mkdir /jb/bfinject && cd /jb/bfinject
  • In a different terminal session, copy the tarball to the device:
> scp -P 2222 bfinject.tar root@localhost:/jb/bfinject

Update: if you get the bash: scp: command not found error, you'll need to execute /jb/makeMeAtHome.sh before being able to use scp. (Thanks @jackmccr for the heads up):

# cd /jb
# ./makeMeAtHome.sh
  • Enter the root password and wait for the file to be transfered
  • Extract the tarball contents:
# tar xvf bfinject.tar
  • Add the /jb/bfinject path to PATH:
# export PATH=$PATH:/jb/bfinject:
  • Optional: you can move or copy the .dylib libraries to /usr/local/lib to be able to run bfinject from any directory
    From now on you can add /jb/bfinject to the list of binpack paths. For more information about bfinject visit their GitHub repo.

tl;dr of why we need to decrypt apps first

The app binary of an app downloaded from the App Store is encrypted using Apple's FairPlay DRM to protect the dev's intellectual property and avoid tampering.

Decrypt Starbucks iOS app using bfinject decrypt

  • Download the Starbucks app from the App Store
  • Run itnl to forward the ssh traffic to a different port (if you haven't already done so):
> itnl --lport 2222 --iport 22
  • In a different terminal session SSH into the iDevice (if you haven't already done so):
> ssh -p 2222 root@localhost
  • Enter the root password
  • Change directories to /private/var/containers/Bundle/Application, this is the directory where iOS stores all the apps downloaded from the App Store:
# cd /private/var/containers/Bundle/Application
  • Here you'll see a list of UUID folders, iOS generates a random UUID every time you download an app. If you have many applications installed, a quick hack to know which one is the last installed one is to sort the files by date:
# ls -lat

liberios-sorted-by-date

  • Change directories to the very first UUID folder, in this case it should be the Starbucks app. You will see something like this:
    starbucks-folder
  • Take a note of the name of the .app bundle, in this case is just Starbucks.app but other apps might have different names. This name is important because bfinject decrypt takes it as a parameter and will search for a bundle named exactly as your parameter

Side note

If you change directories to the Starbucks.app, here you'll see all the files included with the Starbucks app bundle. As you can see not a single file is encrypted. When Apple says they encrypt the app, they mean the actual binary not the assets and extra files. (Tip: sometimes you might get lucky and find some server configuration files or secret keys because some devs might not realize we can extract these files). Don't worry about transferring these files to your machine, you'll have access to them once we decrypt the app.

  • On your iDevice, open the Starbucks app
  • On your terminal type:
# bash bfinject -P Starbucks -L decrypt

If you didn't move/copy the .dylib libraries to /usr/local/lib you will need to change directories to /jb/bfinject and execute the command from there.

  • On your device you should see a pop up dialog like the following:
    starbucks-decrypted
  • Optional: Tap on YES and follow the instructions if you want to transfer the decrypted app using NetCat
  • I prefer using scp to transfer the decrypted app. The decrypted app will be stored in the /Documents folder of the original app. The directory for the Data section of the iOS apps is /private/var/mobile/Containers/Data/Application/. Change directories to the Data section:
# cd /var/mobile/Containers/Data/Application/
  • Again, you'll see a list of UUID folders, you can sort by date again to get the latest modified folder, change directories to that UUID and then to the Documents folder, you should see a decrypted-app.ipa file:
    starbucks-data
  • In a different terminal session transfer the decrypted-app.ipa file to your machine:
> scp -P 2222 root@localhost:/var/mobile/Containers/Data/Application/{UUID}/Documents/decrypted-app.ipa decrypted-app.ipa

Update: if you get the bash: scp: command not found error, you'll need to execute /jb/makeMeAtHome.sh before being able to use scp. (Thanks @jackmccr for the heads up):

# cd /jb
# ./makeMeAtHome.sh
  • Optional: I don't like having files laying around, after transferring the decrypted-app.ipa to my machine, I usually delete it from the device:
# rm /var/mobile/Containers/Data/Application/{UUID}/Documents/decrypted-app.ipa
  • On your machine, rename and change the file's extension to Starbucks.zip:
> mv decrypted-app.ipa Starbucks.zip
  • Extract the .zip contents:
> unzip -a Starbucks.zip
  • You should get a folder named Payload and inside a bundle called Starbucks.app, right-click on the Starbucks.app bundle and select Show Package Contents, now you should see all the files contained in the Starbucks bundle, including the decrypted version of the Starbucks binary, yay!

I know this is a lot of information and instructions, that's why I divided this post in two parts. Try repeat these steps with a few different apps to get familiar with the flow and the tools and next we'll get a sense of how to disassemble and dump the decrypted app's classes.

Note: The reason why I chose the Starbucks app is because they have a bug bounty program on HackerOne and their iOS app is in scope of that program, so if by following this tutorial you manage to find a vulnerability you get to report it to them.