Jailbreak iOS
Jailbreak iOS
// JailbreakChecker.swift
// IOSSecuritySuite
//
// Created by wregula on 23/04/2019.
// Copyright © 2019 wregula. All rights reserved.
//
// swiftlint:disable cyclomatic_complexity function_body_length
type_body_length trailing_whitespace
import Foundation
import UIKit
import Darwin // fork
import MachO // dyld
import ObjectiveC // NSObject and Selector
struct JailbreakStatus {
let passed: Bool
let failMessage: String // Added for backwards compatibility
let failedChecks: [FailedCheckType]
}
if !result.passed {
failedChecks.append((check: check, failMessage:
result.failMessage))
if !failMessage.isEmpty {
failMessage += ", "
}
}
failMessage += result.failMessage
}
// "cydia://" URL scheme has been removed. Turns out there is app in
the official App Store
// that has the cydia:// URL scheme registered, so it may cause false
positive
private static func checkURLSchemes() -> CheckResult {
let urlSchemes = [
"undecimus://",
"sileo://",
"zbra://",
"filza://",
"activator://"
]
return canOpenUrlFromList(urlSchemes: urlSchemes)
}
"/Library/MobileSubstrate/DynamicLibraries/PreferenceLoader.plist", //
PreferenceLoader
"/Library/MobileSubstrate/DynamicLibraries/PreferenceLoader.dylib", //
PreferenceLoader
"/Library/MobileSubstrate/DynamicLibraries", // DynamicLibraries
directory in general
"/var/mobile/Library/Preferences/me.jjolano.shadow.plist"
]
var paths = [
"/.installed_unc0ver",
"/.bootstrapped_electra",
"/Applications/Cydia.app",
"/Library/MobileSubstrate/MobileSubstrate.dylib",
"/etc/apt",
"/var/log/apt"
]
if FileManager.default.isReadableFile(atPath: path) {
return (false, "Suspicious file can be opened: \(path)")
} else if let result =
FileChecker.checkExistenceOfSuspiciousFilesViaFOpen(path: path,
mode: .writable) {
return result
} else if let result =
FileChecker.checkExistenceOfSuspiciousFilesViaAccess(path: path,
mode: .writable) {
return result
}
}
let paths = [
"/",
"/root/",
"/private/",
"/jb/"
]
if FileChecker.checkRestrictedPathIsReadonlyViaStatvfs(path: "/") ==
false {
return (false, "Restricted path '/' is not Read-Only")
} else if FileChecker.checkRestrictedPathIsReadonlyViaStatfs(path:
"/") == false {
return (false, "Restricted path '/' is not Read-Only")
} else if
FileChecker.checkRestrictedPathIsReadonlyViaGetfsstat(name: "/") ==
false {
return (false, "Restricted path '/' is not Read-Only")
}
if forkResult >= 0 {
if forkResult > 0 {
kill(forkResult, SIGTERM)
}
return (false, "Fork was able to create a new process (sandbox
violation)")
}
let paths = [
"/var/lib/undecimus/apt", // unc0ver
"/Applications",
"/Library/Ringtones",
"/Library/Wallpaper",
"/usr/arm-apple-darwin9",
"/usr/include",
"/usr/libexec",
"/usr/share"
]
For the most part, jailbreak detection procedures are a lot less sophisticated that one might
imagine. While there are countless ways apps can implement checks for jailbroken devices,
they typically boil down to the following:
Existence of directories - Rogue apps love to 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 - Similar to checking existence of directories, but checks
the Unix file permissions of specific files and directories on the system 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 devices
out of jail. sandboxd explicitly denies process forking on devices in jail. By
checking the returned pid on fork(), a rogue app can tell if it has successfully
forked or not, at which point it can determine a device's jailbreak status.
SSH loopback connections - Only a very small number of applications
implement this (as it is not nearly as effective as the others). Due to the very large
portion of jailbroken devices that have OpenSSH installed, some rogue apps will
attempt to make a connection to 127.0.0.1 on port 22. If the connection succeeds,
it means OpenSSH is installed and running on the device, which obviously
indicates that 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.
Please refer to the articles also for properly implementing the checks.
False Sense of Security: A Study on the Effectivity of Jailbreak Detection in Banking Apps (tu-bs.de)