@_r3ggi
由ISS 描述
ISS 检测内容
- 越狱(即使是带有全新指标 iOS 11+ 的越狱!)
🔥 ) - 附加的调试器 👨🏻🚀
- 如果一个应用在仿真器中运行
👽 - 设备上运行的反向工程工具
🔭
设置
您可以通过以下 4 种方式开始使用 IOSSecuritySuite
1. 添加源
将 IOSSecuritySuite/*.swift
文件添加到您的项目中
2. 使用 Cocoapods 进行设置
pod 'IOSSecuritySuite'
3. 使用 Carthage 进行设置
github "securing/IOSSecuritySuite"
4. 使用 Swift Package Manager 进行设置
.package(url: "https://github.com/securing/IOSSecuritySuite.git", from: "1.5.0")
更新 Info.plist
在您的项目添加 ISS 之后,还需要更新您的主 Info.plist。在越狱检测模块中有一个检查,该检查使用 canOpenURL(_:)
方法,并且需要指定将要查询的 URL。
<key>LSApplicationQueriesSchemes</key>
<array>
<string>undecimus</string>
<string>sileo</string>
<string>zbra</string>
<string>filza</string>
<string>activator</string>
</array>
通知
iPhone信息安全套件适用于iOS/iPadOS。不应用于搭载Apple Silicon的Mac电脑。
如何使用
越狱检测模块
- 最简单的方法可以帮助您判断设备是否已经越狱或被锁定。
if IOSSecuritySuite.amIJailbroken() {
print("This device is jailbroken")
} else {
print("This device is not jailbroken")
}
- 详细模式,如果您还想了解识别到的具体指示器。
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
- 详细 & 可过滤,如果您还想识别例如过去被越狱但现在被锁定的设备。
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")
}
}
调试器检测模块
let amIDebugged: Bool = IOSSecuritySuite.amIDebugged()
所有情况下都拒绝调试器
IOSSecuritySuite.denyDebugger()
模拟器检测模块
let runInEmulator: Bool = IOSSecuritySuite.amIRunInEmulator()
逆向工程工具检测模块
- 最简单的方法如果你只想知道设备是否有逆向工程证据,它会返回 True/False
if IOSSecuritySuite.amIReverseEngineered() {
print("This device has evidence of reverse engineering")
} else {
print("This device hasn't evidence of reverse engineering")
}
- 详细且可过滤,如果你还想要得到检查列表
let reverseStatus = IOSSecuritySuite.amIReverseEngineeredWithFailedChecks()
if reverseStatus.reverseEngineered {
// check for reverseStatus.failedChecks for more details
}
系统代理检测模块
let amIProxied: Bool = IOSSecuritySuite.amIProxied()
实验性功能
运行时钩子检测模块
let amIRuntimeHooked: Bool = amIRuntimeHook(dyldWhiteList: dylds, detectionClass: SomeClass.self, selector: #selector(SomeClass.someFunction), isClassMethod: false)
符号钩子拒绝模块
// 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检测模块
// 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拒绝模块
// 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()
}
文件完整性检查模块
// 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.")
}
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")
}
// 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()
}
在使用此和其他平台的安检查器之前,您必须了解
- 将此工具包含到您的项目中,并不是提高您的应用安全性的唯一方法!您可以在这里阅读一份关于移动安全的一般性白皮书 这里。
- 检测设备是否越狱是在设备本地完成的。这意味着每个越狱检测器都可能被绕过(即使这个也可以)!
- Swift代码被认为比Objective-C更难以在动态中进行操作。因为这个库是用纯Swift编写的,IOSSecuritySuite方法不应该暴露给Objective-C运行时(这使其更难绕过
✅ )。您必须了解,攻击者仍然能够HookFunction/MSFindSymbol Swift符号并动态改变Swift代码的执行流程。 - 对整个项目的代码进行混淆也是一个不错的选择,包括这个库。请参阅 Swiftshield
❤️
是的,请!如果您有更好的想法或者只是想改进这个项目,请通过Twitter(https://twitter.com/_r3ggi)或Linkedin(https://www.linkedin.com/in/wojciech-regula/)给我发消息。欢迎提交pull request!
- kubajakowski 指出
canOpenURL(_:)
方法的错误。 - olbartek 代码审查和pull request。
- benbahrenburg 对于多种ISS改进。
- fotiDim 添加了新的文件路径供检查。
- gcharita 添加了对Swift Package Manager的支持。
- rynaardb 创建了
amIJailbrokenWithFailedChecks()
方法。 - undeaDD 对于多种ISS改进。
- fnxpt 添加了多个JB检测。
- TannerJin 对于MSHook、RuntimeHook、SymbolHook和Watchpoint Detection模块。
- NikoXu 添加了文件完整性模块。
- hellpf 解决了一个悬挂套接字问题。
- Ant-tree 提高了hooking阻力。
- izmcm 实现了
amIReverseEngineeredWithFailedChecks()
方法。 - sanu 提供了新的文件检查。
- marsepu 提交了一个包含新改进的优秀pull request。
待办事项列表(TODO)
- 研究Installer5和Zebra Package Manager检测(Cydia替代品)。
许可协议
请参阅LICENSE文件。
参考文献
在创建这个工具时,我使用了