
iOSプラットフォームのセキュリティと改ざん防止のSwiftライブラリ
## ⭐️ 認定iOSアプリケーションセキュリティエンジニアになりたいですか? ⭐️
実践的で完全オンラインのコースをチェックしてください: [https://courses.securing.pl/courses/iase](https://courses.securing.pl/courses/iase?utm_source=githubiosss&utm_medium=githubiosss&utm_campaign=githubiosss&utm_id=githubiosss)

## ISS 説明

### 作者: [@_r3ggi](https://twitter.com/_r3ggi)
🌏 iOS Security Suiteは、純粋なSwiftで書かれた、高度で使いやすいプラットフォームセキュリティ&改ざん防止ライブラリです!iOS向けの開発を行っていて、OWASP [MASVS](https://github.com/OWASP/owasp-masvs) 標準(第8章)に従ってアプリを保護したい場合、このライブラリは多くの時間を節約できるでしょう。🚀
ISSが検出するもの:
* ジェイルブレイク 🧨
* デバッガの接続 👨🏻🚀
* エミュレータでのアプリ実行の検出 👽
* デバイス上で実行中の一般的なリバースエンジニアリングツール 🔭
## セットアップ
IOSSecuritySuiteの使用を開始するには4つの方法があります。
### 1. ソースを追加
`IOSSecuritySuite/*.swift` ファイルをプロジェクトに追加します。
### 2. CocoaPodsを使用したセットアップ
`pod 'IOSSecuritySuite'`
### 3. Carthageを使用したセットアップ
`github "securing/IOSSecuritySuite"`
### 4. Swift Package Managerを使用したセットアップ
```swift
.package(url: "https://github.com/securing/IOSSecuritySuite.git", from: "1.5.0")
```
### Info.plistの更新
ISSをプロジェクトに追加した後、メインのInfo.plistも更新する必要があります。ジェイルブレイク検出モジュールには ```canOpenURL(_:)``` メソッドを使用するチェックがあり、クエリするURLを指定する[必要](https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl)があります。
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>undecimus</string>
<string>sileo</string>
<string>zbra</string>
<string>filza</string>
</array>
```
### 価格
詳細はEULAライセンスをご確認ください。
TLDR:
あなたの会社の従業員数が:
* 0~99人 - **無料**
* 100~1000人 - 年間3,000ユーロ
* 1000人以上 - 年間10,000ユーロ
iOS Security Suiteを使用したモジュールを販売する場合(アプリ内で直接使用しない場合) - 年間10,000ユーロ
### 注意
iOS Security SuiteはiOS/iPadOSでの使用を想定しています。Apple Silicon搭載のMacでは使用しないでください。
## 使い方
### ジェイルブレイク検出モジュール
* **最もシンプルな方法** デバイスがジェイルブレイクされているかどうかを知りたいだけの場合、True/Falseを返します。
```Swift
if IOSSecuritySuite.amIJailbroken() {
print("This device is jailbroken")
} else {
print("This device is not jailbroken")
}
```
* **詳細版**、どの指標が特定されたかを知りたい場合
```Swift
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailMessage()
if jailbreakStatus.jailbroken {
print("This device is jailbroken")
print("Because: \(jailbreakStatus.failMessage)")
} else {
print("This device is not jailbroken")
}
```
failMessageは、以下の例のようにカンマ区切りの指標を含む文字列です:
`sileo:// URL scheme detected, Suspicious file exists: /Library/MobileSubstrate/MobileSubstrate.dylib, Fork was able to create a new process`
* **詳細&フィルタ可能版**、例えば過去にジェイルブレイクされたが現在はジェイルされているデバイスを特定したい場合
```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")
}
}
```
### デバッガ検出モジュール
```Swift
let amIDebugged: Bool = IOSSecuritySuite.amIDebugged()
```
### デバッガを完全に拒否
```Swift
IOSSecuritySuite.denyDebugger()
```
### エミュレータ検出モジュール
```Swift
let runInEmulator: Bool = IOSSecuritySuite.amIRunInEmulator()
```
### リバースエンジニアリングツール検出モジュール
* **最もシンプルな方法** デバイスにリバースエンジニアリングの証拠があるかどうかを知りたい場合、True/Falseを返します。
```Swift
if IOSSecuritySuite.amIReverseEngineered() {
print("This device has evidence of reverse engineering")
} else {
print("This device hasn't evidence of reverse engineering")
}
```
* **詳細&フィルタ可能版**、実行されたチェックのリストも必要な場合
```Swift
let reverseStatus = IOSSecuritySuite.amIReverseEngineeredWithFailedChecks()
if reverseStatus.reverseEngineered {
// check for reverseStatus.failedChecks for more details
}
```
### システムプロキシ検出モジュール
アプリがVPNに接続されているかどうかも検出できるようになりました。
```Swift
let amIProxied: Bool = IOSSecuritySuite.amIProxied(considerVPNConnectionAsProxy: true)
```
### ロックダウンモード検出モジュール
```Swift
let amIInLockdownMode: Bool = IOSSecuritySuite.amIInLockdownMode()
```
## 実験的機能
### ランタイムフック検出モジュール
```Swift
let amIRuntimeHooked: Bool = amIRuntimeHook(dyldWhiteList: dylds, detectionClass: SomeClass.self, selector: #selector(SomeClass.someFunction), isClassMethod: false)
```
### シンボルフック拒否モジュール
```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検出モジュール
```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拒否モジュール
```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()
}
```
### ファイル整合性検証モジュール
```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.")
}
```
### ブレークポイント検出モジュール
```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")
}
```
### ウォッチポイント検出モジュール
```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()
}
```
## セキュリティに関する考慮事項
このツールや他のプラットフォームセキュリティチェッカーを使用する前に、次のことを理解しておく必要があります:
* このツールをプロジェクトに含めることは、アプリのセキュリティを向上させるためにすべき唯一のことではありません!一般的なモバイルセキュリティのホワイトペーパーは[こちら](https://www.securing.biz/en/mobile-application-security-best-practices/index.html)で読むことができます。
* デバイスがジェイルブレイクされているかどうかの検出は、デバイス上でローカルに行われます。つまり、すべてのジェイルブレイク検出器は(これも含めて)バイパスされる可能性があります!
* SwiftコードはObjective-Cよりも動的な操作が難しいと考えられています。このライブラリは純粋なSwiftで書かれているため、IOSSecuritySuiteのメソッドはObjective-Cランタイムに公開されるべきではありません(これによりバイパスがより困難になります✅)。攻撃者は依然としてMSHookFunction/MSFindSymbolを使用してSwiftシンボルをフックし、Swiftコードの実行フローを動的に変更できることを認識しておく必要があります。
## 貢献 ❤️
はい、ぜひ!より良いアイデアがある場合や、このプロジェクトを改善したい場合は、[Twitter](https://twitter.com/_r3ggi)または[LinkedIn](https://www.linkedin.com/in/wojciech-regula/)までご連絡ください。プルリクエストは大歓迎です!
### スペシャルサンクス:👏🏻
* [kubajakowski](https://github.com/kubajakowski) - ```canOpenURL(_:)``` メソッドの問題を指摘してくれた
* [olbartek](https://github.com/olbartek) - コードレビューとプルリクエスト
* [benbahrenburg](https://github.com/benbahrenburg) - ISSのさまざまな改善
* [fotiDim](https://github.com/fotiDim) - 新しいチェック用ファイルパスの追加
* [gcharita](https://github.com/gcharita) - Swift Package Managerサポートの追加
* [rynaardb](https://github.com/rynaardb) - `amIJailbrokenWithFailedChecks()` メソッドの作成
* [undeaDD](https://github.com/undeaDD) - ISSのさまざまな改善
* [fnxpt](https://github.com/fnxpt) - 複数のJB検出の追加
* [TannerJin](https://github.com/TannerJin) - MSHook、RuntimeHook、SymbolHook、Watchpoint Detectionモジュール
* [NikoXu](https://github.com/NikoXu) - ファイル整合性モジュールの追加
* [hellpf](https://github.com/hellpf) - ダングリングソケット問題の修正
* [Ant-tree](https://github.com/Ant-tree) - フック耐性の改善
* [izmcm](https://github.com/izmcm) - `amIReverseEngineeredWithFailedChecks()` メソッドの実装
* [sanu](https://github.com/sanu) - 新しいファイルチェックの提供
* [marsepu](https://github.com/marsepu) - 新しい改善を含む素晴らしいPR
* [mkj-is](https://github.com/mkj-is) - ISSパフォーマンス向上のPR 🚄
* [LongXiangGuo](https://github.com/LongXiangGuo) - プライバシーマニフェスト追加のPR
* [Coeur](https://github.com/Coeur) - ISSの改善とバグ修正
* [Adobels](https://github.com/Adobels) - 新しいApple要件へのISSの調整
## TODO
* [ ] Installer5 および Zebra パッケージマネージャーの検出を調査 (Cydiaの代替)
* [ ] Dopamine hidejb 検出器
## ライセンス
LICENSEファイルを参照してください。
## 参照
このツールを作成する際に使用したもの:
* 🔗 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" 著: David Thiel