Created
October 28, 2025 14:25
-
-
Save wesmatlock/edcc88ede54e5196cb976653fb0e6a36 to your computer and use it in GitHub Desktop.
RASPManager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Foundation | |
| import CryptoKit | |
| import UIKit | |
| import os.log | |
| import Darwin | |
| public final class RASPManager { | |
| public static let shared = RASPManager() | |
| private let logger = Logger(subsystem: "com.app.security", category: "RASP") | |
| private var monitoringTimer: Timer? | |
| private var isMonitoring = false | |
| private init() {} | |
| public enum ThreatLevel: Int { | |
| case none = 0 | |
| case low = 1 | |
| case medium = 2 | |
| case high = 3 | |
| case critical = 4 | |
| } | |
| public struct ThreatDetection { | |
| let type: String | |
| let level: ThreatLevel | |
| let timestamp: Date | |
| let details: [String: Any] | |
| } | |
| public func startMonitoring() { | |
| guard !isMonitoring else { return } | |
| isMonitoring = true | |
| logger.info("RASP monitoring started") | |
| monitoringTimer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true) { [weak self] _ in | |
| self?.performSecurityChecks() | |
| } | |
| setupNotificationObservers() | |
| performInitialChecks() | |
| } | |
| public func stopMonitoring() { | |
| isMonitoring = false | |
| monitoringTimer?.invalidate() | |
| monitoringTimer = nil | |
| logger.info("RASP monitoring stopped") | |
| } | |
| private func performInitialChecks() { | |
| checkDebuggerAttachment() | |
| checkCodeIntegrity() | |
| checkRuntimeManipulation() | |
| checkMemoryIntegrity() | |
| } | |
| private func performSecurityChecks() { | |
| DispatchQueue.global(qos: .background).async { [weak self] in | |
| self?.checkDebuggerAttachment() | |
| self?.checkRuntimeManipulation() | |
| self?.checkMemoryIntegrity() | |
| self?.checkNetworkInterception() | |
| } | |
| } | |
| private func checkDebuggerAttachment() { | |
| var info = kinfo_proc() | |
| var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()] | |
| var size = MemoryLayout<kinfo_proc>.stride | |
| let result = sysctl(&mib, UInt32(mib.count), &info, &size, nil, 0) | |
| if result == 0 && (info.kp_proc.p_flag & P_TRACED) != 0 { | |
| handleThreatDetection(ThreatDetection( | |
| type: "Debugger Attached", | |
| level: .critical, | |
| timestamp: Date(), | |
| details: ["process_flag": info.kp_proc.p_flag] | |
| )) | |
| } | |
| if isBeingDebugged() { | |
| handleThreatDetection(ThreatDetection( | |
| type: "Debugger Detected (ptrace)", | |
| level: .critical, | |
| timestamp: Date(), | |
| details: [:] | |
| )) | |
| } | |
| } | |
| private func isBeingDebugged() -> Bool { | |
| var name: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()] | |
| var info = kinfo_proc() | |
| var info_size = MemoryLayout<kinfo_proc>.size | |
| if sysctl(&name, 4, &info, &info_size, nil, 0) != 0 { | |
| return false | |
| } | |
| return (info.kp_proc.p_flag & P_TRACED) != 0 | |
| } | |
| private func checkCodeIntegrity() { | |
| guard let executablePath = Bundle.main.executablePath else { return } | |
| do { | |
| let data = try Data(contentsOf: URL(fileURLWithPath: executablePath)) | |
| let hash = SHA256.hash(data: data) | |
| let hashString = hash.compactMap { String(format: "%02x", $0) }.joined() | |
| if let storedHash = UserDefaults.standard.string(forKey: "executable_hash") { | |
| if hashString != storedHash { | |
| handleThreatDetection(ThreatDetection( | |
| type: "Code Integrity Violation", | |
| level: .critical, | |
| timestamp: Date(), | |
| details: ["expected": storedHash, "actual": hashString] | |
| )) | |
| } | |
| } else { | |
| UserDefaults.standard.set(hashString, forKey: "executable_hash") | |
| } | |
| } catch { | |
| logger.error("Failed to check code integrity: \(error.localizedDescription)") | |
| } | |
| } | |
| private func checkRuntimeManipulation() { | |
| let handle = dlopen(nil, RTLD_NOW) | |
| defer { if let h = handle { dlclose(h) } } | |
| let suspiciousFunctions = [ | |
| "MSHookFunction", | |
| "MSFindSymbol", | |
| "MSGetImageByName", | |
| "substitute_hook_functions" | |
| ] | |
| for function in suspiciousFunctions { | |
| var symbolFound = false | |
| function.withCString { cString in | |
| if let h = handle, dlsym(h, cString) != nil { | |
| symbolFound = true | |
| } | |
| } | |
| if symbolFound { | |
| handleThreatDetection(ThreatDetection( | |
| type: "Runtime Manipulation", | |
| level: .high, | |
| timestamp: Date(), | |
| details: ["function": function] | |
| )) | |
| } | |
| } | |
| } | |
| private func checkMemoryIntegrity() { | |
| let criticalClasses = [ | |
| "URLSession", | |
| "SecKeychain", | |
| "LAContext" | |
| ] | |
| for className in criticalClasses { | |
| guard let cls = NSClassFromString(className) else { continue } | |
| let methodCount = class_getInstanceMethod(cls, NSSelectorFromString("init")) | |
| if methodCount == nil { | |
| handleThreatDetection(ThreatDetection( | |
| type: "Memory Tampering", | |
| level: .medium, | |
| timestamp: Date(), | |
| details: ["class": className] | |
| )) | |
| } | |
| } | |
| } | |
| private func checkNetworkInterception() { | |
| if let proxySettings = CFNetworkCopySystemProxySettings()?.takeRetainedValue() as? [String: Any] { | |
| var interceptors: [String] = [] | |
| let httpEnableKey = "HTTPEnable" | |
| let httpProxyKey = "HTTPProxy" | |
| let httpsEnableKey = "HTTPSEnable" | |
| let httpsProxyKey = "HTTPSProxy" | |
| if let httpEnabled = proxySettings[httpEnableKey] as? NSNumber, httpEnabled.boolValue, | |
| let httpProxy = proxySettings[httpProxyKey] as? String, !httpProxy.isEmpty { | |
| interceptors.append("HTTP: \(httpProxy)") | |
| } | |
| if let httpsEnabled = proxySettings[httpsEnableKey] as? NSNumber, httpsEnabled.boolValue, | |
| let httpsProxy = proxySettings[httpsProxyKey] as? String, !httpsProxy.isEmpty { | |
| interceptors.append("HTTPS: \(httpsProxy)") | |
| } | |
| if !interceptors.isEmpty { | |
| handleThreatDetection(ThreatDetection( | |
| type: "Network Interception", | |
| level: .medium, | |
| timestamp: Date(), | |
| details: ["proxies": interceptors] | |
| )) | |
| } | |
| } | |
| } | |
| private func setupNotificationObservers() { | |
| NotificationCenter.default.addObserver( | |
| self, | |
| selector: #selector(applicationDidBecomeActive), | |
| name: UIApplication.didBecomeActiveNotification, | |
| object: nil | |
| ) | |
| NotificationCenter.default.addObserver( | |
| self, | |
| selector: #selector(applicationWillResignActive), | |
| name: UIApplication.willResignActiveNotification, | |
| object: nil | |
| ) | |
| } | |
| @objc private func applicationDidBecomeActive() { | |
| performSecurityChecks() | |
| } | |
| @objc private func applicationWillResignActive() { | |
| checkMemoryIntegrity() | |
| } | |
| private func handleThreatDetection(_ detection: ThreatDetection) { | |
| logger.warning("Threat detected: \(detection.type) - Level: \(detection.level.rawValue)") | |
| switch detection.level { | |
| case .critical: | |
| terminateApplication() | |
| case .high: | |
| disableSensitiveFeatures() | |
| notifySecurityTeam(detection) | |
| case .medium: | |
| logSecurityEvent(detection) | |
| increaseMonitoring() | |
| case .low: | |
| logSecurityEvent(detection) | |
| case .none: | |
| break | |
| } | |
| } | |
| private func terminateApplication() { | |
| logger.critical("Critical threat detected. Terminating application.") | |
| DispatchQueue.main.async { | |
| let alert = UIAlertController( | |
| title: "Security Alert", | |
| message: "A security issue has been detected. Please reinstall the app.", | |
| preferredStyle: .alert | |
| ) | |
| if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, | |
| let rootViewController = windowScene.windows.first?.rootViewController { | |
| rootViewController.present(alert, animated: true) { | |
| DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { | |
| exit(0) | |
| } | |
| } | |
| } else { | |
| exit(0) | |
| } | |
| } | |
| } | |
| private func disableSensitiveFeatures() { | |
| NotificationCenter.default.post(name: .disableSensitiveFeatures, object: nil) | |
| } | |
| private func notifySecurityTeam(_ detection: ThreatDetection) { | |
| // Implement security team notification | |
| } | |
| private func logSecurityEvent(_ detection: ThreatDetection) { | |
| logger.info("Security event: \(detection.type) at \(detection.timestamp)") | |
| } | |
| private func increaseMonitoring() { | |
| monitoringTimer?.invalidate() | |
| monitoringTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in | |
| self?.performSecurityChecks() | |
| } | |
| } | |
| } | |
| extension Notification.Name { | |
| static let disableSensitiveFeatures = Notification.Name("DisableSensitiveFeatures") | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment