
Biblioteca Swift de seguridad y anti-manipulación para plataforma iOS
Consulta nuestro curso práctico y completamente en línea en: https://courses.securing.pl/courses/iase


🌏 iOS Security Suite es una librería avanzada y fácil de usar de seguridad de plataforma y anti-manipulación, escrita en Swift puro. Si desarrollas para iOS y quieres proteger tu aplicación según el estándar OWASP MASVS, capítulo v8, ¡entonces esta librería podría ahorrarte mucho tiempo! 🚀
Lo que ISS detecta:
Hay 4 formas de empezar a usar IOSSecuritySuite
Agrega los archivos IOSSecuritySuite/*.swift a tu proyecto
pod 'IOSSecuritySuite'
github "securing/IOSSecuritySuite"
.package(url: "https://github.com/securing/IOSSecuritySuite.git", from: "1.5.0")
Después de agregar ISS a tu proyecto, también necesitarás actualizar tu Info.plist principal. Hay una verificación en el módulo de detección de jailbreak que usa el método canOpenURL(_:) y requiere especificar las URLs que se consultarán.
<key>LSApplicationQueriesSchemes</key>
<array>
<string>undecimus</string>
<string>sileo</string>
<string>zbra</string>
<string>filza</string>
</array>
Consulta nuestra licencia EULA para más detalles.
Resumen: Si tu empresa emplea:
Si quieres vender un módulo que use iOS Security Suite (no se usa directamente en tu aplicación) - 10k EUR/año
iOS Security Suite está diseñado para usarse en iOS/iPadOS. No debe usarse en Macs con Apple Silicon.
if IOSSecuritySuite.amIJailbroken() {
print("Este dispositivo está jailbroken")
} else {
print("Este dispositivo no está jailbroken")
}
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailMessage()
if jailbreakStatus.jailbroken {
print("Este dispositivo está jailbroken")
print("Porque: \(jailbreakStatus.failMessage)")
} else {
print("Este dispositivo no está jailbroken")
}
El failMessage es una cadena que contiene indicadores separados por comas, como se muestra en el siguiente ejemplo:
sileo:// Esquema de URL detectado, Archivo sospechoso existe: /Library/MobileSubstrate/MobileSubstrate.dylib, Fork pudo crear un nuevo proceso
let jailbreakStatus = IOSSecuritySuite.amIJailbrokenWithFailedChecks()
if jailbreakStatus.jailbroken {
if (jailbreakStatus.failedChecks.contains { $0.check == .existenceOfSuspiciousFiles }) && (jailbreakStatus.failedChecks.contains { $0.check == .suspiciousFilesCanBeOpened }) {
print("Este es un dispositivo realmente jailbroken")
}
}
let amIDebugged: Bool = IOSSecuritySuite.amIDebugged()
IOSSecuritySuite.denyDebugger()
let runInEmulator: Bool = IOSSecuritySuite.amIRunInEmulator()
if IOSSecuritySuite.amIReverseEngineered() {
print("Este dispositivo tiene evidencia de ingeniería inversa")
} else {
print("Este dispositivo no tiene evidencia de ingeniería inversa")
}
let reverseStatus = IOSSecuritySuite.amIReverseEngineeredWithFailedChecks()
if reverseStatus.reverseEngineered {
// consulta reverseStatus.failedChecks para más detalles
}
Ahora también puedes detectar si una aplicación está conectada a una 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)
// Si queremos denegar el hook de símbolo de una función Swift, tenemos que pasar el nombre mangled de esa función
denySymbolHook("$s10Foundation5NSLogyySS_s7CVarArg_pdtF") // denegando el hook de la función NSLog
NSLog("Hello Symbol Hook")
denySymbolHook("abort")
abort()
// Declaración de función
func someFunction(takes: Int) -> Bool {
return false
}
// Definiendo FunctionType : @convention(thin) indica una referencia de función "thin", que usa la convención de llamada de Swift sin parámetros especiales "self" o "context".
typealias FunctionType = @convention(thin) (Int) -> (Bool)
// Obteniendo la dirección del puntero de la función que queremos verificar
func getSwiftFunctionAddr(_ function: @escaping FunctionType) -> UnsafeMutableRawPointer {
return unsafeBitCast(function, to: UnsafeMutableRawPointer.self)
}
let funcAddr = getSwiftFunctionAddr(someFunction)
let amIMSHooked = IOSSecuritySuite.amIMSHooked(funcAddr)
// Declaración de función
func denyDebugger(value: Int) {
}
// Definiendo FunctionType : @convention(thin) indica una referencia de función "thin", que usa la convención de llamada de Swift sin parámetros especiales "self" o "context".
typealias FunctionType = @convention(thin) (Int)->()
// Obteniendo la dirección de la función original
let funcDenyDebugger: FunctionType = denyDebugger
let funcAddr = unsafeBitCast(funcDenyDebugger, to: UnsafeMutableRawPointer.self)
if let originalDenyDebugger = denyMSHook(funcAddr) {
// Llama a la función original con 1337 como argumento Int
unsafeBitCast(originalDenyDebugger, to: FunctionType.self)(1337)
} else {
denyDebugger()
}
// Determina si la aplicación ha sido manipulada
if IOSSecuritySuite.amITampered([.bundleID("biz.securing.FrameworkClientApp"),
.mobileProvision("2976c70b56e9ae1e2c8e8b231bf6b0cff12bbbd0a593f21846d9a004dd181be3"),
.machO("IOSSecuritySuite", "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc")]).result {
print("He sido manipulado.")
}
else {
print("No he sido manipulado.")
}
// Verificar manualmente el valor hash SHA256 de un dylib cargado
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.custom("IOSSecuritySuite")), hashValue == "6d8d460b9a4ee6c0f378e30f137cebaf2ce12bf31a2eef3729c36889158aa7fc" {
print("No he sido manipulado.")
}
else {
print("He sido manipulado.")
}
// Verificar el valor hash SHA256 del ejecutable principal
// Consejo: Tu aplicación puede recuperar este valor del servidor
if let hashValue = IOSSecuritySuite.getMachOFileHashValue(.default), hashValue == "tu-valor-hash-del-ejecutable-de-la-aplicación" {
print("No he sido manipulado.")
}
else {
print("He sido manipulado.")
}
func denyDebugger() {
// Establece un punto de interrupción aquí
}
typealias FunctionType = @convention(thin) ()->()
let func_denyDebugger: FunctionType = denyDebugger // `: FunctionType` es obligatorio
let func_addr = unsafeBitCast(func_denyDebugger, to: UnsafeMutableRawPointer.self)
let hasBreakpoint = IOSSecuritySuite.hasBreakpointAt(func_addr, functionSize: nil)
if hasBreakpoint {
print("Se encontró un punto de interrupción en la función especificada")
} else {
print("No se encontró un punto de interrupción en la función especificada")
}
// Establece un punto de interrupción en la función testWatchpoint
func testWatchpoint() -> Bool{
// lldb: watchpoint set expression ptr
var ptr = malloc(9)
// lldb: watchpoint set variable count
var count = 3
return IOSSecuritySuite.hasWatchpoint()
}
Antes de usar este y otros verificadores de seguridad de plataforma, debes entender que:
¡Sí, por favor! Si tienes una mejor idea o simplemente quieres mejorar este proyecto, contáctame en Twitter o LinkedIn. ¡Las pull requests son más que bienvenidas!
canOpenURL(_:)amIJailbrokenWithFailedChecks()amIReverseEngineeredWithFailedChecks()Consulta el archivo LICENSE.
Al crear esta herramienta utilicé: