1. Setting Up the Folder Structure and Files
-
Create the RootDetection Group in Xcode:
- Open your React Native project in Xcode.
- In the Project Navigator, right-click on your project’s folder (usually named
ios/[YourProjectName]
). - Select New Group and name it
RootDetection
. - This group will hold both the Objective-C and Swift files (
JailbreakDetector.m
andJailbreakDetector.swift
), organizing your jailbreak detection code in one place.
-
Add
JailbreakDetector.swift
to the RootDetection Group:- Right-click on
RootDetection
and select New File. - Choose Swift File and name it
JailbreakDetector.swift
. - Xcode will prompt you to create a bridging header if you don’t already have one. Accept the prompt, and Xcode will automatically create the bridging header file.
- Right-click on
-
Add
JailbreakDetector.m
to the RootDetection Group:- Right-click on
RootDetection
again and select New File. - Choose Objective-C File and name it
JailbreakDetector.m
.
- Right-click on
Now, you have the following structure under the RootDetection
group:
RootDetection/
├── JailbreakDetector.m
└── JailbreakDetector.swift
2. Writing the Swift Jailbreak Detection Logic in JailbreakDetector.swift
The JailbreakDetector.swift
file contains various checks to identify if the device is jailbroken. Here’s the complete code:
import Foundation
import UIKit
import React
@objc(JailbreakDetector)
class JailbreakDetector: NSObject {
@objc static func requiresMainQueueSetup() -> Bool {
return true
}
@objc
func isJailbroken(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) {
if hasJailbreakIndicators() || canOpenSuspiciousURIs() {
resolver(true)
} else {
resolver(false)
}
}
// Check if any indicators of jailbreak are found
private func hasJailbreakIndicators() -> Bool {
return hasWritableSystemDirectory() ||
hasSuspiciousPaths(jailbreakPaths) ||
hasSuspiciousPaths(appPaths) ||
hasSuspiciousPaths(fridaPaths)
}
// Check if the system directory is writable
private func hasWritableSystemDirectory() -> Bool {
let testString = "Jailbreak Test"
let path = "/private/jailbreak.txt"
do {
try testString.write(toFile: path, atomically: true, encoding: .utf8)
try FileManager.default.removeItem(atPath: path)
return true
} catch {
return false
}
}
// Check if any suspicious paths exist
private func hasSuspiciousPaths(_ paths: [String]) -> Bool {
for path in paths {
if FileManager.default.fileExists(atPath: path) {
return true
}
}
return false
}
// Check if any suspicious URI schemes can be opened
private func canOpenSuspiciousURIs() -> Bool {
let uriSchemes = ["cydia://package/com.example.package", "cydia://", "undecimus://", "sileo://", "zebra://", "dopamine://"]
for scheme in uriSchemes {
if let url = URL(string: scheme), UIApplication.shared.canOpenURL(url) {
return true
}
}
return false
}
// Constants for commonly found jailbreak and reverse engineering paths
private let jailbreakPaths = [
"/bin/bash", "/usr/sbin/sshd", "/etc/apt", "/private/var/lib/apt/",
"/Library/MobileSubstrate/DynamicLibraries", "/private/var/lib/cydia",
"/var/cache/apt", "/var/lib/cydia", "/var/log/syslog", "/var/tmp/cydia.log",
"/Applications/Icy.app", "/Applications/FakeCarrier.app", "/Applications/IntelliScreen.app",
"/Applications/SBSettings.app", "/Applications/MxTube.app", "/Applications/RockApp.app"
]
private let appPaths = [
"/Applications/FakeCarrier.app", "/Applications/Icy.app", "/Applications/IntelliScreen.app",
"/Applications/SBSettings.app", "/Applications/Dopamine.app", "/Applications/Cydia.app",
"/Applications/Sileo.app", "/Applications/Zebra.app"
]
private let fridaPaths = [
"/data/local/tmp/frida-server", "/usr/lib/frida/frida-server", "/usr/lib/frida/frida-agent.dylib"
]
}
3. Creating the Bridging Header in JailbreakDetector.m
The JailbreakDetector.m
file serves as the bridging file to expose the Swift JailbreakDetector
module to React Native.
#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(JailbreakDetector, NSObject)
RCT_EXTERN_METHOD(isJailbroken:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
@end
Why This Bridging Header is Necessary
The bridging header enables Swift classes to be exposed to Objective-C, allowing React Native’s JavaScript code to access them. This makes it possible to call the isJailbroken
method from JavaScript.
4. Using Jailbreak Detection in JavaScript
Explanation of Security Checks
-
Swift Jailbreak Detection: Uses
JailbreakDetector
to perform a comprehensive jailbreak check on iOS. -
Exit Condition: If the app detects a jailbroken device, it shows a warning and exits using
RNExitApp
.
Conclusion
With this setup, your app can detect jailbroken devices on iOS, adding an essential layer of security. This prevents the app from running in compromised environments, protecting sensitive data and improving overall security.
Top comments (0)