In the first part of our series, we looked at how to modify an iOS application binary by inserting load commands to inject custom dynamic libraries. In Part 2, we take this a step further by introducing a toolchain designed to make some of our favorite iOS application hacking tools available on non-jailbroken devices.

To facilitate this, we forked the fantastic Theos project by DHowett. For the uninitiated, Theos is basically a build environment that allows you to (among other things) easily write, build, and deploy Cydia Substrate tweaks for apps on jailbroken devices. Theos takes care of all the cross-compiling, linking, etc., leaving you free to write the code you want without any fuss.

Until now, Theos only worked on jailbroken devices because it requires additional frameworks and libraries to be installed on your iOS device, as well as requiring a modification to the operating system to inject dynamic libraries into applications at runtime. We have circumvented this by including all of the required frameworks and libraries; our approach also involves modifying application binaries instead of the operating system. Full details of how this was done will be released later, but until then, let’s concentrate on how to use this thing.

We’ll run through an example of how to patch an app by modifying the Trulia house-hunting app to spoof our location, so that our device always appears to be located inside the White House in Washington, D.C.

Getting Started

First, check out the code from GitHub. I installed it into ~/Projects/theos-jailed on my laptop. From there, create a new tweak just as you normally would with Theos:

Upon completion, Theos-jailed creates a Trulia directory inside the current directory, which in this case is ~/Projects/trulia.

Extracting the App

To extract the Trulia app from the iPhone it’s installed on, we use the iFunBox application. Right click on Trulia, then choose “Backup to .ipa package.”


We save the .ipa file in ~/Projects/trulia and rename it trulia.ipa.

Uninstalling the App

Due to namespace collisions, you can’t reinstall a patched app over the original app. You have to uninstall the original first. You can either do this on your device or do it with iFunBox, as shown below:


Decrypting the App

Apps are encrypted on Apple devices. To patch an app, it is necessary to decrypt it; however, this step can – at present – only be done on a jailbroken device. Thus, we copy the Trulia .ipa file to a jailbroken iPad Mini; again, we use iFunBox to do this:

Hit “Install App” and choose the .ipa file you previously saved. In a few seconds, the app should be installed on the jailbroken device. Ensure that you have installed the Clutch tool, which we will use for decrypting the Trulia app. Now, SSH into your device and run clutch Trulia to decrypt Trulia and save a new .ipa file containing the decrypted app (Note: We’re using port redirection to connect to the ipad:22):

Let’s rename it to something more user-friendly:

Finally, back on our laptop, we copy the decrypted .ipa from the jailbroken iPad into our ~/Projects/trulia/ folder:

Success! We now have a fully decrypted, hackable version of the Trulia app in trulia.ipa.

Writing a Tweak

Remember: Our intention is to spoof our location to the Trulia app. To do this, we have to hook/swizzle some of the Apple CLLocationManager framework methods, specifically the class that implements the CLLocationManagerDelegate protocol. The process of doing this is exactly the same for Theos-jailed as it is for a regular Theos tweak – you can use %hook, %end, %ctor, etc. as normal.

We open up ~/Projects/trulia/Tweak.xm and insert this code:

The code replaces –[CLLocationManager setDelegate:] with a new version that ensures all callbacks to the delegate method locationManager:didUpdateLocations: are intercepted, modified with new coordinates, and then passed to the original delegate method.

To build the tweak, simply run “make:”

Upon completion, we will have a new shared library called Trulia.dylib that we will eventually inject into the Trulia app.

But first, we must prepare our provisioning profile.

Preparing a Provisioning Profile – The App ID

As any iOS developer knows, installing an app onto an iOS device requires a matching provisioning profile that contains a lot of information pertaining to developer certificates, app entitlements, etc. It can get pretty hairy, but we’ve tried to make this part of the process as easy as possible.

First, you need to know the correct entitlements for the Trulia app. Entitlements are essentially permissions given to the app by you, the developer. You can grant entitlements for things like Apple Pay, push notifications, etc. Our version of Theos-patched comes with a tool that will tell you the entitlements required to repackage any given app. To run it, just do this:

In this case, there are no special entitlements required for Trulia to operate. You’ll also see a “Bundle ID.” This is important and you’ll need it later. For now though, sign into the Apple Developer Member Center and select “Certificates, Identifiers & Profiles”:

From here, select “Identifiers:”

You need to add a new App ID. When prompted for the “Bundle ID,” enter the value provided by the “ info …” command. In this case, it’s “com.trulia.Trulia-patched:”

You’ll be prompted to enter “App Services.” These are actually the entitlements mentioned earlier. In the case of Trulia, we don’t need any additional entitlements, so it’s safe to leave all of these options unchecked:

Follow the wizard to the end. You’ll get there eventually; you can see I called this App ID “Trulia Patched:”


Preparing a Provisioning Profile: The Profile

Once you’ve generated an App ID, you can generate a matching provisioning profile. Select the menu option to do so, then add a new profile:

You’re going to use an “iOS App Development” profile:

You’ll be asked to choose a corresponding “App ID.” Choose the one you just created:

You’ll be asked to select the certificates used for signing. Choose your cert – I only have one:

You’ll also be asked to select the devices to which you’d like to install the provisioning profile. I chose all of mine – seven in total. Finally, you’ll be asked to give the profile a name. I called mine “Trulia Patched Profile:”

Great success! It worked:

Hit “Download” and copy the .mobileprovision file into your project folder, which in our case is ~/Projects/trulia/:

Now, we’re ready to install it on a device.

Installing the Provisioning Profile

You can use Xcode to install a provisioning profile onto your non-jailbroken device. Go to Window/Devices and right click on your device:

You’ll be shown a list of profiles already installed on the device. Click the + button to add your newly generated profile:

Choose the Trulia .mobileprovision file and it will be installed for you:


Patching the IPA File

Go ahead and inject the Trulia.dylib file (and accompanying libraries) into the Trulia app. The tool automates the entire process. Simply run:

That’s it! The tool inserts the relevant load command, adds your Cydia Substrate tweak, performs code signing using your developer certificate, and rebuilds the .ipa file as trulia-patched.ipa.

Installing the Patched App

The last step is to use Xcode to install the patched app back onto the iOS device. For this, we use the device manager again:

When prompted, choose the newly generated trulia-patched.ipa file. Xcode will install it onto the device. You should see an entry like this in the Xcode console when the installation is finished:

The devices window will also show that Trulia is installed:

You should now be able to launch your app. If it crashes and you see this in the Xcode console, it means you forgot to decrypt the app using Clutch:

Just go back to the beginning and use Clutch to decrypt the app using a jailbroken device.

Testing the Spoofed Location

Everything should happen like magic. If the patch was successful, this is where Trulia will think it is:

Taking It Further: Cycript

We promised Cycript, and it’s enabled by default in Theos-jailed. Any time you run your app, a Cycript server is automatically instantiated on port 31337/TCP of the device. To connect to it, you will need the Cycript tools installed on your MacBook (download them here). After that:

Here you see us passing the -r option to Cycript, which specifies the IP address of the target iPhone and port 31337. From here, Cycript can be used as normal. For example, let’s enumerate the view controllers on screen:

The output has been truncated for readability, but above we can see the UILabel object corresponding to the following label on the app’s UI:

We can easily change it:

The change is immediately reflected in the UI:

All of your normal Cycript tricks should work just fine. Have fun!

That’s All (For Now) Folks!

There’s a lot going on under the hood to make this happen. We also implemented the Fishhook library to dynamically rebind function symbols within iOS apps. This gives us functionality equivalent to MSHookFunction. More documentation will follow on that soon.