8

I'm trying to make an app which only works on jailbroken iDevices. I already have jailbreak detection code:

([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]]);{
    UIAlertView *cydiaisinstalled=[[UIAlertView alloc]initWithTitle:@"Cydia is installed!"
                                                            message:@"You can use Respring!"
                                                           delegate:self
                                                  cancelButtonTitle:@"OK"
                                                  otherButtonTitles:nil];
    [cydiaisinstalled show];
}}

But now I need to be able to detect if the device is not jailbroken.

GeoSn0w
  • 684
  • 1
  • 9
  • 20
  • 3
    Why detecting jailbroken devices if it works only on them? If you can install the app from other source then appstore, then it's a jailbroken device. – Sulthan Oct 11 '12 at 00:28
  • Just try to write anything to /var/mobile. You shouldn't be able to if you're not jailbroken. – GeoSn0w Apr 07 '21 at 09:40
  • I'd also like to mention that your jailbreak detection is wrong. It works only if Cydia is installed, which in many cases might not be. I can enumerate at least 3 jailbreaks that don't even come with Cydia, but rather with Sileo. You should instead try to write outside the Sandbox to /var/mobile. that is universal. – GeoSn0w Apr 07 '21 at 10:04

4 Answers4

8

Try accessing any file outside the app's sandbox. For example:

BOOL IsDeviceJailbroken(void) {
    #if TARGET_IPHONE_SIMULATOR
    return NO;
    #else
    return [[NSFileManager defaultManager] fileExistsAtPath: @"/bin/bash"];
    #endif
}

Note that having Cydia installed and having a jailbroken device are two different things.

Tomas Andrle
  • 13,132
  • 15
  • 75
  • 92
  • This could work as long as /bin/bash is owned by mobile (501:501). If for some reason it's owned by root (0:0), then you will get deny(); from the sandbox even on a jailbroken device so your check will say the file does not exist when it is. You'd need chmod your binary (6775) and call setuid(0), and setgid(0) at startup to make sure you can access that file no matter who owns it. – GeoSn0w Apr 07 '21 at 09:47
6

I wrote a function that detects whether the device is jailbroken for another question, but it seems relevant here:

- (BOOL) isJailbroken() {

    //If the app is running on the simulator
    #if TARGET_IPHONE_SIMULATOR
        return NO;

    //If its running on an actual device
    #else
        BOOL isJailbroken = NO;

        //This line checks for the existence of Cydia
        BOOL cydiaInstalled = [[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"];

        FILE *f = fopen("/bin/bash", "r");

        if (!(errno == ENOENT) || cydiaInstalled) {

            //Device is jailbroken
            isJailbroken = YES;
        }            
        fclose(f);
        return isJailbroken;
    #endif
}

This function uses two checks to see if the phone is jailbroken: it first checks if Cydia is installed. Not all jailbroken devices have Cydia installed, though most do, so I also check for the existence of bash, which also only appears on jailbroken devices. Note that this function will work in nearly all cases, but it's probably not 100%. The only people that don't have Cydia on their jailbroken iDevice are probably those that are experimenting with jailbroken devices and not using them for advantages like tweaks and themes.

pasawaya
  • 11,515
  • 7
  • 53
  • 92
  • 1
    shouldn't `isJailbroken` be `YES` if `cydiaInstalled`? you have a `!` in front of `cydiaInstalled` in your code. – Nate Sep 09 '12 at 23:16
  • @Nate - Thanks for that. Guess I just overlooked that. – pasawaya Sep 09 '12 at 23:40
  • Souldn't the "&&" be a "||" and why do the check for "/bin/bash" at all, when we already found the Cydia.app? – Andreas Oct 10 '12 at 16:41
  • @Andreas - Because not all jailbroken devices have Cydia installed. I explain this at the end of my answer. But thanks - the && should be an || – pasawaya Oct 11 '12 at 00:17
  • Yes, I got the "not all deviced have Cydia" installed part, but when we check for Cydia first _and_ find it, there's no need to check for "/bin/bash". Just a minor optimization ;) – Andreas Oct 11 '12 at 07:58
  • @Andreas - Oh ok. I think I misunderstood your previous comment. Anyway, thanks! – pasawaya Oct 11 '12 at 12:06
  • OK I found the jailbreakdetection on my own check out the feed! –  Oct 16 '12 at 20:29
  • Testing errno without checking fopen(3) return value is not correct. – freestyler Aug 19 '13 at 08:41
  • Cydia may not be installed, but the device can still be jailbroken. Nowadays there are many other package managers such as Sileo, Zebra, Installer 5, etc. – GeoSn0w Apr 07 '21 at 09:45
3

OK thanks for all the answers but I found it out on my own. Here is the code:

if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]]) {
    //insert action if cydia is installed
}
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]] == NO) {
    //insert action if Cydia is not installed
}

With this code you can detect any application on your idevice as long as the app has an URL scheme you can find most of the URL scheme here: http://handleopenurl.com

PS: You have to replace the green part whith your actions:)

pasawaya
  • 11,515
  • 7
  • 53
  • 92
  • Like I said in my answer, opening Cydia is not a universally correct method for checking whether the device is jailbroken because not every jailbroken iDevice has Cydia installed. – pasawaya Oct 16 '12 at 20:34
  • But the normale user hase cydia installed:) –  Oct 19 '12 at 13:11
  • That's true, and I'm sure that you're targeting this user base, so for your purposes only checking for Cydia is fine. – pasawaya Oct 19 '12 at 18:19
  • 2
    This will always fail on iOS 9 because Apple has locked down canOpenURL. You will need to add an 'LSApplicationQueriesSchemes' entry in your Info.plist for "cydia". – Daniel Aug 14 '15 at 01:11
  • 1
    @Daniel in iOS9.1 it seems that the scheme check fails returning -canOpenURL: failed for URL: "cydia://" - error: "This app is not allowed to query for scheme cydia" even if the scheme is in the list. – loretoparisi Sep 11 '15 at 16:41
  • @user1658674 Cydia is not always installed. There are other package managers as well. Sileo, Zebra, Installer 5, Saily, etc. – GeoSn0w Apr 07 '21 at 09:44
0

For those coming here in 2021, here's a very quick way to detect if you're jailbroken and unlike other answers, this would have the benefit on working on all the dozens of different jailbreaks that exist:

FILE * filepath = fopen("/var/mobile/test-jb", "w");
    
    if (!filepath) {
        fclose(filepath);
        fprintf(stderr,"Random processes are running sandboxed. Not jailbroken\n");
        return -2;
    }
    
    printf("Detected sandbox escape. This device is likely jailbroken.\n");
    fclose(filepath);

What this does, is to attempt to write a test file to /var/mobile. It normally works if you're jailbroken and have proper entitlements. On a non-jailbroken device, this would fail with deny() in the console.

Make sure you sign your app with these entitlements:

<key>com.apple.private.security.no-container</key>
    <true/>
<key>platform-application</key>
    <true/>
GeoSn0w
  • 684
  • 1
  • 9
  • 20