
iOS 플랫폼 보안 및 위변조 방지 Swift 라이브러리
실용적이고 완전 온라인 강좌를 확인하세요: https://courses.securing.pl/courses/iase


🌏 iOS Security Suite는 순수 Swift로 작성된 고급스럽고 사용하기 쉬운 플랫폼 보안 및 변조 방지 라이브러리입니다! iOS 개발을 하고 있고 OWASP MASVS 표준의 v8장에 따라 앱을 보호하려는 경우, 이 라이브러리가 많은 시간을 절약해 줄 수 있습니다. 🚀
ISS가 탐지하는 것:
IOSSecuritySuite 사용을 시작하는 4가지 방법이 있습니다.
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를 사용하는 모듈을 판매하려는 경우 (앱에서 직접 사용되지 않음) - 연간 10,000 EUR
iOS Security Suite는 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()
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()
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()
// 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)
// 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()
}
이 라이브러리 및 기타 플랫폼 보안 검사기를 사용하기 전에 다음을 이해해야 합니다:
네, 환영합니다! 더 나은 아이디어가 있거나 이 프로젝트를 개선하고 싶다면 Twitter 또는 LinkedIn으로 연락해 주세요. 풀 리퀘스트는 언제나 감사합니다!
canOpenURL(_:) 메서드 문제 지적amIJailbrokenWithFailedChecks() 메서드 생성amIReverseEngineeredWithFailedChecks() 메서드 구현LICENSE 파일을 참조하세요.
이 도구를 만드는 동안 사용한 자료: