7

the App we are working on was rejected because the Device in the Review Process was detected as jailbroken ^^

To detect a jailbroken Device, several Tests were performed:

NSString* bundlePath = [[NSBundle mainBundle] bundlePath];

// scan for itunes metadata
BOOL isDirectory = NO;
NSString* directoryPath = [bundlePath stringByAppendingPathComponent:@"SC_Info/"];
BOOL directoryIsAvailable = [[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:&isDirectory];
BOOL contentSeemsValid = ([[[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:NULL] count] == 2);
if (directoryIsAvailable && contentSeemsValid) {
    return YES;
}
contentSeemsValid = [[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat:@"%@/iTunesMetadata.​plist", bundlePath]];
if (contentSeemsValid) {
    return YES;
}

// scan for cydia app
NSURL* testURL = [NSURL URLWithString:@"cydia://"];
if ([[UIApplication sharedApplication] canOpenURL:testURL]) {
    return YES;
}

// scan for paths available
NSArray* paths = @[@"/Applications/Cydia.app", @"/Applications/RockApp.app", @"/Applications/Icy.app", @"/usr/sbin/sshd", @"/usr/bin/sshd", @"/private/var/lib/apt", @"/private/var/lib/cydia", @"/private/var/stash", @"/usr/libexec/sftp-server"];
for (NSString* string in paths) {
    if ([[NSFileManager defaultManager] fileExistsAtPath:string]) {
        return YES;
    }
}

// scan for forking
int forkValue = fork();
if (forkValue >= 0) {
    return YES;
}

// try to write in private space
NSString* testString = @"test";
NSError* error = nil;
[testString writeToFile:@"/private/test.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (error == nil) {
    return YES;
}

// seems not jailbroken
return NO;

One (or more) of these Tests return YES on the Devices Apple use for Review, but none of our DevDevices. Which one could it be? Does anybody know more Details about the Devices Apple use for the Review? Any Hints or other Guesses? (The Context from the App is HealthCare in Hospitals, so we need to be sure that the Patient Data were save)

Best Regards,
Zeek

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Zeek
  • 71
  • 1
  • 2
  • 1
    Those tests don't seem very solid and that `fork()` test looks very dangerous... Not that that has anything to do with your question... – trojanfoe Jul 15 '14 at 08:25
  • 3
    Why don't you just appeal the rejection, just say you detect jailbreak to insure data safety. – rckoenes Jul 15 '14 at 08:26
  • @rckoenes: Patient Data were very sensitive, so we delete all Data and quit the App. – Zeek Jul 15 '14 at 08:34
  • 3
    Have you got the email/message that Apple sent you when rejecting your app. Please can you share it? Sharing this would be very helpful to see exactly what they said to you. – Popeye Jul 15 '14 at 08:34
  • @trojanfoe: fork() works fine and save, it returns -1 one on non-jailbreak devices. FYI: http://stackoverflow.com/questions/15893849/will-fork-in-ios-app-likely-be-rejected-by-apples-vetting-process – Zeek Jul 15 '14 at 08:36
  • 1
    @Zeek wait do you quit the app programmatically? Are does the user do it themselves by pressing the Home button at the bottom of the device. Apple will reject apps that quit programmatically, such as quit buttons within the app itself that call something like `exit(0)` – Popeye Jul 15 '14 at 08:36
  • 1
    @Zeek And what does `fork()` do on a jailbroken device? Don't you think you should be exiting the child process in the event it succeeded? – trojanfoe Jul 15 '14 at 08:37
  • 8
    @Zeek I suspect that it has really been rejected because of `"Apps that read or write data outside its designated container area will be rejected"` you are reading outside of the designated container when you check to see if the device is jailbroken, you seem to be reading things from your `path` variable that aren't allowed. Such as paths to `/private/...` and `/usr/...` You aren't allowed access to these. – Popeye Jul 15 '14 at 08:41
  • Popeye´s answer is the correct one. You cannot detect jailbroken phones without break the Apple guides. But when you publish your app with a enterprise account, then you can do this. – Mirko Brunner Jul 15 '14 at 11:55
  • 3
    These tests will be hacked in less then 2min. You should write such tests in C. – Starbax Jul 15 '14 at 12:01
  • I agree with @Popeye - I think all of these tests break the rules. Perhaps you should just put up a disclaimer when the app is first opened saying "do not use on a jailbroken device" – JeremyP Jul 15 '14 at 16:43
  • Apple has been reported to use special test fixtures or non-stock OS builds that monitor for any attempts by an app to use a private APIs or access a directory outside the iOS security sandbox, or any attempts to fork another process. Those monitors may allow an illegal operation to succeed in order to catch and report it. – hotpaw2 Jul 15 '14 at 17:04
  • At first, thanks for your input :) I think the answer from @Popeye is the most logical one. What is with the rest of the scans? We all know, Security is only an Illusion, with enough effort everything can cracked down (Starbax). Through _bring your own devices_ policy and marketing :( publishing as an Enterprise App is no possibility (MirkoBrunner) – Zeek Jul 15 '14 at 20:56
  • @Zeek if you can't go through the Enterprise app way then you are stuffed with this code. This will never get through the review process, you'll have to rethink what your app is doing and how it does it. – Popeye Jul 16 '14 at 06:50
  • @Popeye Why do most fork implementations call `exit(0)` if `pid` is nil? Doesn't that mean fork failed so device is not jailbroken? This is common example: ` int pid = fork(); if (!pid){ [self terminateApplication]; } if (pid >= 0) { return YES; }` – AnonProgrammer Dec 19 '18 at 16:48

1 Answers1

5

From https://www.theiphonewiki.com/wiki/Bypassing_Jailbreak_Detection

While there are countless ways apps can implement checks for jailbroken devices, they typically boil down to the following:

Existence of directories - Check your file system for paths like /Applications/Cydia.app/ and /private/var/stash, amongst a handful of others. Most often, these are checked using the -(BOOL)fileExistsAtPath:(NSString*)path method in NSFileManager, but more sneaky apps like to use lower-level C functions like fopen(), stat(), or access().

Directory permissions - Check the Unix file permissions of specific files and directories using NSFileManager methods as well as C functions like statfs(). Far more directories have write access on a jailbroken device than on one still in jail.

Process forking - sandboxd does not deny App Store applications the ability to use fork(), popen(), or any other C functions to create child processes on non-jailbroken devices. sandboxd explicitly denies process forking on devices in jail. if you check the returned pid on fork(), your app can tell if it has successfully forked or not, at which point it can determine a device's jailbreak status.

SSH loopback connections* - Due to the large portion of jailbroken devices that have OpenSSH installed, some apps will attempt to connect to 127.0.0.1 on port 22. If the connection succeeds, it means OpenSSH is installed and running on the device, therefore it is jailbroken.

system() - Calling the system() function with a NULL argument on a device in jail will return 0; doing the same on a jailbroken device will return 1. This is since the function will check whether /bin/sh exists, and this is only the case on jailbroken devices.[1]

dyld functions - By far the hardest to get around. Calling functions like _dyld_image_count() and _dyld_get_image_name() to see which dylibs are currently loaded. Very difficult to patch, as patches are themselves part of dylibs.

*Only a very small number of applications implement this (as it is not nearly as effective as the others)

These methods seem like they would be less likely to be rejected by apple and are very simple to use.

The above passage has been edited for brevity

MoralCode
  • 1,954
  • 1
  • 20
  • 42
  • 1
    I know this is old, but how is it all the anti jail functions are simple boolean functions which is easily be hooked and neutered? How do the big players like banking and media block jailbreak extremely effectively? I like to implement similar functionality, but I cannot seem to find anything as whenever I search, I find what I am trying to prevent. Not prevent what they're doing! – Jon Weinraub Jul 12 '17 at 16:17