Bypassing Jailbreak Detection in iOS

In today’s connected modern world every organization wants to have a mobile application for its own services. This also requires that these applications go through a security check / penetration test. We at NotSoSecure constantly receive such requests and work on various mobile assessments. In this blog post Anto Joseph is discussing some of the advance protections that are added by application developers and how they can be bypassed.

A lot of these protections hinder the ability of a blackbox pentest and hence its essential that the penetration testers also know about various ways in which this can be bypassed.

Application Analysis:

In a recent pentest, we were asked to look at the controls implemented within an iOS application to ensure the app cannot be run on a jailbroken device. Running the application in a jail broken device for security assessment is not possible since the Jailbreak Detection Code kicks in and the application exits. So the first challenge would be to understand the detection logic and bypass that.

Enter GDB:

Quote from Wikipedia: “GDB (the GNU debugger) is a powerful and popular debugging tool; it lets you do whatever you like with your program running under GDB.
Lets try to attach gdb to the above process and see if we can come up with a bypass.

GDB Debugger not attaching GDB Debugger not attaching

Well , there is nothing wrong with our GDB. This is the result of developer adding protection against GDB using PT_DENY_ATTACH. We will go ahead and check what ptrace.h does in the “/usr/include/sys/” folder.


Implementation of the above protection scheme in code would look like this.

PT_DENY_ATTACH implementation PT_DENY_ATTACH implementation

To bypass this protection, you would have to patch the application or use GDB trickery which is detailed in the iphonedevwiki. Changing 31 to an arbitrary number can make this system call invalid and help us bypass the protection.

Patching the system call using Hopper:

The simplest way to find the reference to ptrace would be to use the strings section in Hopper and follow the XREF to the method in which it is called as shown below.

Patching with Hopper Disassembler Patching with Hopper Disassembler

Once the application is patched, we can re-sign the binary and we will be able to attach gdb to the process. Most jailbreaks allow you to run unsigned code , but if yours don’t , you could resign the binary using an apple developer certificate or use ldid tool from the cydia repo. You can also use this tool to dump / set binary entitlements as shown below .

ldid binary signing ldid binary signing

From here on, we are in control of the process. We could patch methods, change registers and what not.
But wait, developers could also make use of the below macro to detect if the application is being debugged when sensitive methods are being called. It is recommended to inline these checking logic so that its difficult for an attacker to reverse it. Again, a skillful attacker can also statically patch this check too.

Debug Check Debug Check

Assuming that we have patched both the above protections statically, we can successfully attach a debugger to the process , and start by analyzing the jailbreak detection logic.
Typically, the detection logic checks for presence of certain files in the file system that exists after user jailbreaks their device. Some of these files include checks for the presence of Cydia , Mobile Substrate , Root Apps , ssh etc .
The below screenshot shows a list of files checked by the free version of Shmoopi Anti-Piracy Library.

Shmoopi Anti-Piracy Library Checks Shmoopi Anti-Piracy Library Checks

Our next step would be to write a substrate hook or use runtime hooking to patch the method which checks for the presence of these files. It’s extremely easy using Cycript . But how do we get a list of files that the application access to determine root, Enter Frida .

So what exactly is Frida ?

Quoting from their website: “it’s a dynamic code instrumentation toolkit. It lets you inject snippets of JavaScript into native apps on Windows, Mac, Linux, iOS and Android. “
We managed to hook the fopen syscall from our target application, which prints the location of the file being accessed like shown below.

Frida in Action Frida in Action

Now that we know the locations of the files being accessed to test for jailbreak, we could write a substrate hook to return false for these file checks or we could use an easier solution.

Enter Cycript

Quoting from website “cycript allows de
velopers to explore and modify running applications on either iOS or Mac OS X using a hybrid of Objective-C++ and JavaScript syntax through an interactive console that features syntax highlighting and tab completion. “
Now, lets try to hook some interesting methods and re-write their implementations. As shown below, executing the example methods via cycript runs the application logic and returns the result, but using cycript , we re-wrote the implementation of these functions and now we see that the function returns our value instead . Thus we have successfully altered the application Logic.

Cycript in Action Cycript in Action

Some Root Checks might also include checks for known URL Scheme’s. Their implementation in code would be as shown below.

- (BOOL)isMyAppInstalled {

   return [[UIApplication sharedApplication] canOpenURL:

[NSURL URLWithString:@"rootApplication:"]];


Again, these checks can be trivially bypassed by patching the strings used for the check or runtime hooking the method, which is responsible for the checks as shown below . We just have to look for the keyword “URLWithString” , which maps us to the SFAntiPiracy Method : checkURL .

SFAntiPiracy method checkURL SFAntiPiracy method checkURL


With a little effort, we were able to bypass several protections included by the developer and successfully evade jailbreak detection. Some of the advanced app protection solutions also checks for application tampering, run time hook detection and adds features like control flow obfuscations and string encryption which makes it much harder, but again never impossible ☺