I always liked doing reverse engineering for fun. Back in the days when I had time to play more games on my old Windows XP PC and study random stuff, I had fun using ollydbg for doing reverse engineering on games and hack them. The interest in doing that came back when my bank’s app refused to run on my jailbroken iPhone “for my own security”, other apps do the same. This was the trigger for me to want to do reverse engineering on iOS apps.

Then, some time ago I found out that it was possible to live debug apps on iOS devices as well and tried doing it some times but I always struggled to get gdb or lldb to work. There were a lot of different versions, some specifically to arm64, others to x86 and neither worked well on newer iOS versions, and ended up giving up every time. Also, even when I eventually got it to work, I only got a working debug session using gdb or lldb on my terminal. I couldn’t get a more appropriate, more visual disassembler/debugger like IDA Pro to work.

Happily, I recently found that it’s already possible to get everything working, even a working debugging session on IDA Pro, however, finding all the information I needed to get it to work was quite a challenge. To find all the “parts” I needed to get it to work I needed to grab information from github, iOS hacking forums and even chinese websites, so I decided to document everything here, maybe it helps someone.

So, let’s start!

You need to be jailbroken

First things first, you will need to jailbreak your iDevice. By the time of writing there’s a working jailbreak for the latest and currently signed iOS version: 12.4. It matters to tell that this is not common and happens rarely these days. I’ll not enter into the details on how to jailbreak your iDevice but you can easily find a tutorial with a quick google search, just search for unc0ver.

Also, install some ssh server on your iDevice, like openssh for example. You will need it to run commands remotely on the device.

Important: Remember to change the default ssh password for both mobile and root users the moment you install the ssh server.

For the best experience, I suggest you SSH over USB.

Setup Debugserver

Debugserver is the binary that we will use to attach to the running iOS app that you want to debug. It can be found on your mac if you have Xcode installed.

On your mac run:

$ hdiutil attach /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/12.1\ \(16B5059d\)/DeveloperDiskImage.dmg $ cp /Volumes/DeveloperDiskImage/usr/bin/debugserver ./

I “lipoed” debugserver because I’ve read somewhere that it was necessary, but I’m not sure.

$ lipo -thin arm64 debugserver -output debugserver_arm64

Now you have a thin binary with only arm64 architecture, scp it to your iDevice.

If you’re using unc0ver jailbreak, then the author @Pwn20wnd has written a script to modify debugserver entitlements and copy it to /usr/bin, you can find it at /usr/local/bin/debugserver here is it’s content:

The important part in this script is the one where it uses ldid to modify the entitlements of debugserver with the ones in this file:

So, let’s do this step ourselves on the debugserver_arm64 we scp’ed to the device and then move it to where the script expects it to be.

$ ldid -S/usr/share/entitlements/debugserver.xml debugserver_arm64

$ mv debugserver_arm64 /usr/bin/debugserver

Now, test it! If it worked, it should output something like that:

$ /usr/bin/debugserver

debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-900.3.86

for arm64.

Usage:

debugserver host:port [program-name program-arg1 program-arg2 ...]

debugserver /path/file [program-name program-arg1 program-arg2 ...]

debugserver host:port --attach=<pid>

debugserver /path/file --attach=<pid>

debugserver host:port --attach=<process_name>

debugserver /path/file --attach=<process_name>

debugserver is now ready!

If it exits with Killed:9 then you probably messed up with the modification of entitlements, try again.

Prepare the app you want to debug

Apps downloaded from the appstore are encrypted in your iDevice, so, before starting to debug we need to decrypt them. For that you have plenty options, I’ve read somewhere that the most famous one (Clutch) has some problems with iOS 12, I’ve tested bfdecrypt and it works fine, here’s how:

Add level3tjg’s repo on cydia and install bfdecrypt from it. Repo: https://level3tjg.github.io/

After installing, you can find bfdecrypt in settings, select on it the app you want to dump and decrypt.

After selecting it, open the app, it will show a message that bfdecrypt is decrypting the app and after it’s done you can netcat it to your pc (if you choose yes in bfdecrypt popup)with nc *your_device_ip* 31336 > decrypted.ipa or grab the decrypted ipa should be found at /var/mobile/Containers/Data/Application/*Your App*/Documents/ and copy it to your computer with scp.

Important: You need to re-sign and reinstall the app using the decrypted ipa. You can do that entirely on your iDevice by using ipapatcher (available on level3tjg’s repo) to re-sign it and install it using Filza or just use Cydia Impactor on your mac.

The app is now ready to be debugged.

Debugging the app

Now that you have working debugserver and your decrypted app is installed on your iDevice we should be ready to debug it, follow these steps:

On your iDevice, start the remote debugger with debugserver:

$ debugserver localhost:1111 -a *ExecutableName*

-- or

$ debugserver localhost:1111 /var/containers/Bundle/Application/.../*AppName**.app/**AppName**

I used localhost:1111 because I’m using iProxy to proxy 1111 port on my iDevice to 1111 port on my mac.

On your mac, connect lldb to debugserver

$ lldb

$ process connect connect://127.0.0.1:1111

The output should be something like that:

(lldb) process connect connect://127.0.0.1:1111

Process 5572 stopped

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP

frame #0: 0x000000020a0ac0f4 libsystem_kernel.dylib`mach_msg_trap + 8

libsystem_kernel.dylib`mach_msg_trap:

-> 0x20a0ac0f4 <+8>: ret libsystem_kernel.dylib`mach_msg_overwrite_trap:

0x20a0ac0f8 <+0>: mov x16, #-0x20

0x20a0ac0fc <+4>: svc #0x80

0x20a0ac100 <+8>: ret

Target 0: (App) stopped.

(lldb)

Note: If your lldb shows a python traceback about weakref stuff, it is fine. This is probably due to you having python2 installed by brew. Still, if you want to get rid of it, two possible solutions are: unlinking brew’s python2 or putting the one in /usr/bin/ first on your path (e.g. export PATH=/usr/bin/:$PATH).

Thats it, you are ready to start debugging the app! You can read some lldb tips on lldb’s page.

If you want to setup IDA Pro continue reading the next section.

Using IDA Pro remote iOS debugger

Open the binary from the decrypted ipa on IDA

An ipa is just a zip file with the ipa extension, so just extract it:

$ unzip decrypted.ipa

Inside it’s contents, there must be a binary at Payload/*Application*.app/*Application*

The file doesn’t have an extension, so select “All Files (*)” in the “Select file to disassemble” window in IDA.

Activate Remote iOS Debugger

After IDA finishes analysing the binary, select Remote iOS Debugger in Debugger>Switch Debugger menu.

(Optional) Setup symbols

IDA relies heavily on the use of symbol files in order to achieve fast and detailed debugging (as does Xcode — it usually stores symbols in ~/Library/Developer/Xcode/iOS DeviceSupport/<iOS Version>/Symbols when you first connect your device).

In IDA, copy this path to ‘Symbol path’ in Debugger>Debugger options>Set specific options:

Connecting to the debugserver using ida’s remote ios debugger

Here you have 2 options, launch the app you want to debug in your iDevice and attach to it using debugserver as we done before:

$ debugserver localhost:1111 -a *ExecutableName*

After that you can go ahead and attach to the process using IDA:

If you have attached the debugserver to an already running process on you iDevice, then it doesn’t really matter what you put at “Application” and “Input file” text boxes, it will just attach to it. Alternativelly you could run the debugserver on the iDevice only listening:

$ debugserver localhost:1111

And have IDA launch the process. For that you have to set both paths above to the path on your device where the binary resides, it’s usually inside a path like this:

/var/containers/Bundle/Application/*Application UUID*/*Application*.app/*Application*

That’s it, if you done everything right IDA will attach to the debugserver and after it ends analysing the binary you will be able to set breakpoints and start debugging the app!

More Informations

If you hit problems, here are additional sources of information where I grabbed most of the knowledge to make this post:

Random Chinese post (I suggest using google translator)

Hex-Rays documentation

Github Issue 1 | Github Issue 2