⭐️ 你想成为一名认证的 iOS 应用安全工程师吗? ⭐️

查看我们的实践性强且完全在线的课程:https://courses.securing.pl/courses/iase

iASE logo

ISS 描述

ISS logo

作者:@_r3ggi

🌏 iOS Security Suite 是一款先进且易于使用的平台安全和反篡改库,完全使用 Swift 编写!如果您正在为 iOS 开发,并且希望根据 OWASP MASVS 标准的 v8 章节保护您的应用,那么这个库可以为您节省大量时间。🚀

ISS 检测内容

设置

您可以通过以下 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>
</array>

定价

请查看我们的 EULA 许可协议了解详情。

TLDR:如果您的公司雇佣了

如果您想销售使用 iOS Security Suite 的模块(该模块未直接在您的应用中使用)- 1 万欧元/年

注意

iOS Security Suite 旨在用于 iOS/iPadOS。不应在搭载 Apple 芯片的 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()

逆向工程工具检测器模块

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
}

系统代理检测器模块

现在您还可以检测应用是否连接到 VPN

let amIProxied: Bool = IOSSecuritySuite.amIProxied(considerVPNConnectionAsProxy: true)

锁定模式检测器模块

let amIInLockdownMode: Bool = IOSSecuritySuite.amIInLockdownMode()

实验性功能

运行时 Hook 检测器模块

let amIRuntimeHooked: Bool = amIRuntimeHook(dyldWhiteList: dylds, detectionClass: SomeClass.self, selector: #selector(SomeClass.someFunction), isClassMethod: false)

符号 Hook 拒绝模块

// 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()
}

安全注意事项

在使用此工具和其他平台安全检查器之前,您必须了解

贡献 ❤️

是的,非常欢迎!如果您有更好的想法或者您只是想改进这个项目,请在 TwitterLinkedin 上给我发消息。非常欢迎 Pull Request!

特别鸣谢:👏🏻

待办事项

许可

请参阅 LICENSE 文件。

参考

在创建此工具时,我使用了