Peter Steinberger

How to Inspect the View Hierarchy of Third-Party Apps

I’m generally not a big fan of jailbreaks. Mostly this is because they’re used for piracy and all the hacks result in weird crashes that generally are impossible to reproduce. Still, I was quite excited about the recent iOS 7 jailbreak, since it enables us to attach the debugger to third-party apps and do a little bit of runtime analysis.

Why? Because it’s fun, and it can inspire you to solve things differently. Studying the view hierarchy of complex apps can be rather revealing and it’s interesting to see how others are solving similar problems. This was one thing that took many iterations to get right in PSPDFKit, our iOS PDF framework.

So, how does this work? It’s actually super simple.

  1. Jailbreak your device of choice. I’ve used an iPad 4 here. Make sure it runs iOS 7.0.x. Both arm7(s) and arm64 devices will work now. Don’t jailbreak a device that’s used in production. Otherwise you lose a lot of security features as well. I only jailbreak a clean device and install some apps to inspect.

  2. Open Cydia and install OpenSSH, nano, and Cydia Substrate (previously called MobileSubstrate).

  3. Copy the Reveal library. Find out the device IP address via Settings and execute the following in your terminal (this assumes you have installed Reveal already):
    scp -r /Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/Reveal.framework root@192.168.0.X:/System/Library/Frameworks
    scp /Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib root@192.168.0.X:/Library/MobileSubstrate/DynamicLibraries.
    For Spark Inspector, you would use scp "/Applications/Spark Inspector.app/Contents/Resources/Frameworks/SparkInspector.dylib" root@192.168.0.X:/Library/MobileSubstrate/DynamicLibraries
    Note: The default SSH password on iOS is ‘alpine.’

  4. SSH into the device and create following text file with nano /Library/MobileSubstrate/DynamicLibraries/libReveal.plist: { Filter = { Bundles = ( "<App ID>" ); }; }
    Previously, this worked with wildcard IDs, but this approach has problems with the updated Cydia Substrate. So simply add the App ID of the app you want to inspect, and then restart the app.

  5. Respring with killall SpringBoard or simply restart the device.

Done! Start your app of choice and select it in Reveal. (This should also work similary for SparkInspector.) Attaching via LLDB is a bit harder and I won’t go into details here since this could also be used to pirate apps. Google for ‘task_for_pid-allow,’ ‘debugserver,’ and ‘ldid’ if you want to try this.