了解我们实用且完全在线的课程:https://courses.securing.pl/courses/iase


🌏 iOS Security Suite 是一个高级且易于使用的平台安全与防篡改库,完全使用纯 Swift 编写!如果你正在为 iOS 开发,并且希望根据 OWASP MASVS 标准(第 v8 章)保护你的应用,那么这个库可以为你节省大量时间。🚀
ISS 检测的内容:
有四种方式可以开始使用 IOSSecuritySuite
将 IOSSecuritySuite/*.swift 文件添加到你的项目中
pod 'IOSSecuritySuite'
github "securing/IOSSecuritySuite"
.package(url: "https://github.com/securing/IOSSecuritySuite.git", from: "1.5.0")
将 ISS 添加到项目后,你还需要更新主 Info.plist。越狱检测模块中有一个检查使用了 canOpenURL(_:) 方法,并且需要指定将要查询的 URL。
<key>LSApplicationQueriesSchemes</key>
<array>
<string>undecimus</string>
<string>sileo</string>
<string>zbra</string>
<string>filza</string>
</array>
详情请查看我们的 EULA 许可协议。
简而言之: 如果你的公司员工人数:
如果你想销售一个使用了 iOS Security Suite 的模块(并非直接在应用中使用) - 1万欧元/年
iOS Security Suite 旨在用于 iOS/iPadOS。不应在 Apple Silicon 的 Mac 上使用。
if IOSSecuritySuite.amIJailbroken() {
print("此设备已越狱")
} else {
print("此设备未越狱")
}
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailMessage()
if jailbreakStatus.jailbroken {
print("此设备已越狱")
print("因为:\(jailbreakStatus.failMessage)")
} else {
print("此设备未越狱")
}
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("这是真正的越狱设备")
}
}
let amIDebugged: Bool = IOSSecuritySuite.amIDebugged()
IOSSecuritySuite.denyDebugger()
let runInEmulator: Bool = IOSSecuritySuite.amIRunInEmulator()
if IOSSecuritySuite.amIReverseEngineered() {
print("此设备存在逆向工程证据")
} else {
print("此设备不存在逆向工程证据")
}
let reverseStatus = IOSSecuritySuite.amIReverseEngineeredWithFailedChecks()
if reverseStatus.reverseEngineered {
// 查看 reverseStatus.failedChecks 获取更多详情
}
现在你还可以检测应用是否连接到 VPN
let amIProxied: Bool = IOSSecuritySuite.amIProxied(considerVPNConnectionAsProxy: true)
let amIInLockdownMode: Bool = IOSSecuritySuite.amIInLockdownMode()
let amIRuntimeHooked: Bool = amIRuntimeHook(dyldWhiteList: dylds, detectionClass: SomeClass.self, selector: #selector(SomeClass.someFunction), isClassMethod: false)
// 如果我们想拒绝 Swift 函数的符号 Hook,必须传递该函数的混淆名称
denySymbolHook("$s10Foundation5NSLogyySS_s7CVarArg_pdtF") // 拒绝 Hook NSLog 函数
NSLog("Hello Symbol Hook")
denySymbolHook("abort")
abort()
// 函数声明
func someFunction(takes: Int) -> Bool {
return false
}
// 定义 FunctionType:@convention(thin) 表示“瘦”函数引用,使用 Swift 调用约定,没有特殊的“self”或“context”参数。
typealias FunctionType = @convention(thin) (Int) -> (Bool)
// 获取要验证的函数的指针地址
func getSwiftFunctionAddr(_ function: @escaping FunctionType) -> UnsafeMutableRawPointer {
return unsafeBitCast(function, to: UnsafeMutableRawPointer.self)
}
let funcAddr = getSwiftFunctionAddr(someFunction)
let amIMSHooked = IOSSecuritySuite.amIMSHooked(funcAddr)
// 函数声明
func denyDebugger(value: Int) {
}
// 定义 FunctionType:@convention(thin) 表示“瘦”函数引用,使用 Swift 调用约定,没有特殊的“self”或“context”参数。
typealias FunctionType = @convention(thin) (Int)->()
// 获取原始函数地址
let funcDenyDebugger: FunctionType = denyDebugger
let funcAddr = unsafeBitCast(funcDenyDebugger, to: UnsafeMutableRawPointer.self)
if let originalDenyDebugger = denyMSHook(funcAddr) {
// 使用 1337 作为 Int 参数调用原始函数
unsafeBitCast(originalDenyDebugger, to: FunctionType.self)(1337)
} else {
denyDebugger()
}
// 判断应用程序是否被篡改
if IOSSecuritySuite.amITampered([.bundleID("biz.securing.FrameworkClientApp"),
.mobileProvision("2976c70b56e9ae1e2c8e8b231bf6b0cff12bbbd0a593f21846d9a004dd181be3"),
.machO("IOSSecuritySuite", "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc")]).result {
print("我已遭篡改。")
}
else {
print("我未遭篡改。")
}
// 手动验证已加载 dylib 的 SHA256 哈希值
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.custom("IOSSecuritySuite")), hashValue == "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc" {
print("我未遭篡改。")
}
else {
print("我已遭篡改。")
}
// 检查主可执行文件的 SHA256 哈希值
// 提示:你的应用程序可以从服务器获取此值
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.default), hashValue == "your-application-executable-hash-value" {
print("我未遭篡改。")
}
else {
print("我已遭篡改。")
}
func denyDebugger() {
// 在此处设置断点
}
typealias FunctionType = @convention(thin) ()->()
let func_denyDebugger: FunctionType = denyDebugger // `: FunctionType` 是必需的
let func_addr = unsafeBitCast(func_denyDebugger, to: UnsafeMutableRawPointer.self)
let hasBreakpoint = IOSSecuritySuite.hasBreakpointAt(func_addr, functionSize: nil)
if hasBreakpoint {
print("在指定函数中发现了断点")
} else {
print("在指定函数中未发现断点")
}
// 在 testWatchpoint 函数设置断点
func testWatchpoint() -> Bool{
// lldb: watchpoint set expression ptr
var ptr = malloc(9)
// lldb: watchpoint set variable count
var count = 3
return IOSSecuritySuite.hasWatchpoint()
}
在使用此工具和其他平台安全检查器之前,你需要了解:
当然可以!如果你有更好的想法或只想改进这个项目,请在 Twitter 或 LinkedIn 上联系我。非常欢迎 Pull Request!
canOpenURL(_:) 方法的问题amIJailbrokenWithFailedChecks() 方法amIReverseEngineeredWithFailedChecks() 方法参见 LICENSE 文件。
在创建此工具时,我使用了: