AI prompts
base on iOS platform security & anti-tampering Swift library ## ⭐️ Do you want to become a certified iOS Application Security Engineer? ⭐️
Check out our practical & fully online course at: [https://courses.securing.pl/courses/iase](https://courses.securing.pl/courses/iase?utm_source=githubiosss&utm_medium=githubiosss&utm_campaign=githubiosss&utm_id=githubiosss)
![iASE logo](./iase_bg.png)
## ISS Description
![ISS logo](./logo.png)
### by [@_r3ggi](https://twitter.com/_r3ggi)
🌏 iOS Security Suite is an advanced and easy-to-use platform security & anti-tampering library written in pure Swift! If you are developing for iOS and you want to protect your app according to the OWASP [MASVS](https://github.com/OWASP/owasp-masvs) standard, chapter v8, then this library could save you a lot of time. 🚀
What ISS detects:
* Jailbreak (even the iOS 11+ with brand new indicators! 🔥)
* Attached debugger 👨🏻🚀
* If an app was run in an emulator 👽
* Common reverse engineering tools running on the device 🔭
## Setup
There are 4 ways you can start using IOSSecuritySuite
### 1. Add source
Add `IOSSecuritySuite/*.swift` files to your project
### 2. Setup with CocoaPods
`pod 'IOSSecuritySuite'`
### 3. Setup with Carthage
`github "securing/IOSSecuritySuite"`
### 4. Setup with Swift Package Manager
```swift
.package(url: "https://github.com/securing/IOSSecuritySuite.git", from: "1.5.0")
```
### Update Info.plist
After adding ISS to your project, you will also need to update your main Info.plist. There is a check in jailbreak detection module that uses ```canOpenURL(_:)``` method and [requires](https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl) specifying URLs that will be queried.
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>undecimus</string>
<string>sileo</string>
<string>zbra</string>
<string>filza</string>
</array>
```
### Pricing
Check our EULA license for the details.
TLDR:
If your company employs:
* 0-99 people - **free to use**
* 100-1000 - 3k EUR/year
* 1000+ - 10k EUR/year
If you want to sell a module that uses the iOS Security Suite (it is not used directly in your app) - 10k EUR/year
### Notice
iOS Security Suite is meant to be used on iOS/iPadOS. It should not be used on Macs with Apple Silicon.
## How to use
### Jailbreak detector module
* **The simplest method** returns True/False if you just want to know if the device is jailbroken or jailed
```Swift
if IOSSecuritySuite.amIJailbroken() {
print("This device is jailbroken")
} else {
print("This device is not jailbroken")
}
```
* **Verbose**, if you also want to know what indicators were identified
```Swift
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailMessage()
if jailbreakStatus.jailbroken {
print("This device is jailbroken")
print("Because: \(jailbreakStatus.failMessage)")
} else {
print("This device is not jailbroken")
}
```
The failMessage is a String containing comma-separated indicators as shown on the example below:
`sileo:// URL scheme detected, Suspicious file exists: /Library/MobileSubstrate/MobileSubstrate.dylib, Fork was able to create a new process`
* **Verbose & filterable**, if you also want to for example identify devices that were jailbroken in the past, but now are jailed
```Swift
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailedChecks()
if jailbreakStatus.jailbroken {
if (jailbreakStatus.failedChecks.contains { $0.check == .existenceOfSuspiciousFiles }) && (jailbreakStatus.failedChecks.contains { $0.check == .suspiciousFilesCanBeOpened }) {
print("This is real jailbroken device")
}
}
```
### Debugger detector module
```Swift
let amIDebugged: Bool = IOSSecuritySuite.amIDebugged()
```
### Deny debugger at all
```Swift
IOSSecuritySuite.denyDebugger()
```
### Emulator detector module
```Swift
let runInEmulator: Bool = IOSSecuritySuite.amIRunInEmulator()
```
### Reverse engineering tools detector module
* **The simplest method** returns True/False if you just want to know if the device has evidence of reverse engineering
```Swift
if IOSSecuritySuite.amIReverseEngineered() {
print("This device has evidence of reverse engineering")
} else {
print("This device hasn't evidence of reverse engineering")
}
```
* **Verbose & filterable**, if you also want the list of checks done
```Swift
let reverseStatus = IOSSecuritySuite.amIReverseEngineeredWithFailedChecks()
if reverseStatus.reverseEngineered {
// check for reverseStatus.failedChecks for more details
}
```
### System proxy detector module
Now you can also detect if an app is connected to VPN
```Swift
let amIProxied: Bool = IOSSecuritySuite.amIProxied(considerVPNConnectionAsProxy: true)
```
### Lockdown mode detector module
```Swift
let amIInLockdownMode: Bool = IOSSecuritySuite.amIInLockdownMode()
```
## Experimental features
### Runtime hook detector module
```Swift
let amIRuntimeHooked: Bool = amIRuntimeHook(dyldWhiteList: dylds, detectionClass: SomeClass.self, selector: #selector(SomeClass.someFunction), isClassMethod: false)
```
### Symbol hook deny module
```Swift
// If we want to deny symbol hook of Swift function, we have to pass mangled name of that function
denySymbolHook("$s10Foundation5NSLogyySS_s7CVarArg_pdtF") // denying hooking for the NSLog function
NSLog("Hello Symbol Hook")
denySymbolHook("abort")
abort()
```
### MSHook detector module
```Swift
// Function declaration
func someFunction(takes: Int) -> Bool {
return false
}
// Defining FunctionType : @convention(thin) indicates a “thin” function reference, which uses the Swift calling convention with no special “self” or “context” parameters.
typealias FunctionType = @convention(thin) (Int) -> (Bool)
// Getting pointer address of function we want to verify
func getSwiftFunctionAddr(_ function: @escaping FunctionType) -> UnsafeMutableRawPointer {
return unsafeBitCast(function, to: UnsafeMutableRawPointer.self)
}
let funcAddr = getSwiftFunctionAddr(someFunction)
let amIMSHooked = IOSSecuritySuite.amIMSHooked(funcAddr)
```
### MSHook deny module
```Swift
// Function declaration
func denyDebugger(value: Int) {
}
// Defining FunctionType : @convention(thin) indicates a “thin” function reference, which uses the Swift calling convention with no special “self” or “context” parameters.
typealias FunctionType = @convention(thin) (Int)->()
// Getting original function address
let funcDenyDebugger: FunctionType = denyDebugger
let funcAddr = unsafeBitCast(funcDenyDebugger, to: UnsafeMutableRawPointer.self)
if let originalDenyDebugger = denyMSHook(funcAddr) {
// Call the original function with 1337 as Int argument
unsafeBitCast(originalDenyDebugger, to: FunctionType.self)(1337)
} else {
denyDebugger()
}
```
### File integrity verifier module
```Swift
// Determine if application has been tampered with
if IOSSecuritySuite.amITampered([.bundleID("biz.securing.FrameworkClientApp"),
.mobileProvision("2976c70b56e9ae1e2c8e8b231bf6b0cff12bbbd0a593f21846d9a004dd181be3"),
.machO("IOSSecuritySuite", "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc")]).result {
print("I have been Tampered.")
}
else {
print("I have not been Tampered.")
}
// Manually verify SHA256 hash value of a loaded dylib
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.custom("IOSSecuritySuite")), hashValue == "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc" {
print("I have not been Tampered.")
}
else {
print("I have been Tampered.")
}
// Check SHA256 hash value of the main executable
// Tip: Your application may retrieve this value from the server
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.default), hashValue == "your-application-executable-hash-value" {
print("I have not been Tampered.")
}
else {
print("I have been Tampered.")
}
```
### Breakpoint detection module
```Swift
func denyDebugger() {
// Set breakpoint here
}
typealias FunctionType = @convention(thin) ()->()
let func_denyDebugger: FunctionType = denyDebugger // `: FunctionType` is a must
let func_addr = unsafeBitCast(func_denyDebugger, to: UnsafeMutableRawPointer.self)
let hasBreakpoint = IOSSecuritySuite.hasBreakpointAt(func_addr, functionSize: nil)
if hasBreakpoint {
print("Breakpoint found in the specified function")
} else {
print("Breakpoint not found in the specified function")
}
```
### Watchpoint detection module
```Swift
// Set a breakpoint at the testWatchpoint function
func testWatchpoint() -> Bool{
// lldb: watchpoint set expression ptr
var ptr = malloc(9)
// lldb: watchpoint set variable count
var count = 3
return IOSSecuritySuite.hasWatchpoint()
}
```
## Security considerations
Before using this and other platform security checkers, you have to understand that:
* Including this tool in your project is not the only thing you should do in order to improve your app security! You can read a general mobile security whitepaper [here](https://www.securing.biz/en/mobile-application-security-best-practices/index.html).
* Detecting if a device is jailbroken is done locally on the device. It means that every jailbreak detector may be bypassed (even this)!
* Swift code is considered to be harder to manipulate dynamically than Objective-C. Since this library was written in pure Swift, the IOSSecuritySuite methods shouldn't be exposed to Objective-C runtime (which makes it more difficult to bypass ✅). You have to know that attacker is still able to MSHookFunction/MSFindSymbol Swift symbols and dynamically change Swift code execution flow.
## Contribution ❤️
Yes, please! If you have a better idea or you just want to improve this project, please text me on [Twitter](https://twitter.com/_r3ggi) or [Linkedin](https://www.linkedin.com/in/wojciech-regula/). Pull requests are more than welcome!
### Special thanks: 👏🏻
* [kubajakowski](https://github.com/kubajakowski) for pointing out the problem with ```canOpenURL(_:)``` method
* [olbartek](https://github.com/olbartek) for code review and pull request
* [benbahrenburg](https://github.com/benbahrenburg) for various ISS improvements
* [fotiDim](https://github.com/fotiDim) for adding new file paths to check
* [gcharita](https://github.com/gcharita) for adding the Swift Package Manager support
* [rynaardb](https://github.com/rynaardb) for creating the `amIJailbrokenWithFailedChecks()` method
* [undeaDD](https://github.com/undeaDD) for various ISS improvements
* [fnxpt](https://github.com/fnxpt) for adding multiple JB detections
* [TannerJin](https://github.com/TannerJin) for MSHook, RuntimeHook, SymbolHook and Watchpoint Detection modules
* [NikoXu](https://github.com/NikoXu) for adding file integrity module
* [hellpf](https://github.com/hellpf) for fixing a dangling socket problem
* [Ant-tree](https://github.com/Ant-tree) for improving hooking resistence
* [izmcm](https://github.com/izmcm) for implementing the `amIReverseEngineeredWithFailedChecks()` method
* [sanu](https://github.com/sanu) for new providing new file checks
* [marsepu](https://github.com/marsepu) for a well-done PR with new improvements
* [mkj-is](https://github.com/mkj-is) for a PR improving ISS performance 🚄
* [LongXiangGuo](https://github.com/LongXiangGuo) for a PR adding the privacy manifest
## TODO
* [ ] Research Installer5 and Zebra Package Manager detection ( Cydia Alternatives )
## License
See the LICENSE file.
## References
While creating this tool I used:
* 🔗 https://github.com/TheSwiftyCoder/JailBreak-Detection
* 🔗 https://github.com/abhinashjain/jailbreakdetection
* 🔗 https://gist.github.com/ddrccw/8412847
* 🔗 https://gist.github.com/bugaevc/4307eaf045e4b4264d8e395b5878a63b
* 📚 "iOS Application Security" by David Thiel
", Assign "at most 3 tags" to the expected json: {"id":"11996","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"