From dbd5b30b435677a7f19100cb1718725e8042be1e Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Wed, 18 Dec 2024 16:54:53 +0100 Subject: [PATCH 1/9] add DebuggerDetection.swift --- Sources/DebuggerDetection.swift | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Sources/DebuggerDetection.swift diff --git a/Sources/DebuggerDetection.swift b/Sources/DebuggerDetection.swift new file mode 100644 index 0000000..2b0a6e7 --- /dev/null +++ b/Sources/DebuggerDetection.swift @@ -0,0 +1,29 @@ +import Foundation +import Darwin + +// MARK: - Internal +internal final class DebuggerDetection { + + static func threatDetected() -> Bool { + hasTracerFlagSet() + } +} + +// MARK: - Private +fileprivate extension DebuggerDetection { + + /// Check P_TRACED flag from Darwin Kernel + /// if the process is traced + static func hasTracerFlagSet() -> Bool { + var info = kinfo_proc() + var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()] // Kernel info, process info, specific process by PID, get current process ID + var size = MemoryLayout.stride(ofValue: info) + + let result = sysctl(&mib, u_int(mib.count), &info, &size, nil, 0) + if result != 0 { + fatalError("sysctl failed") + } + + return (info.kp_proc.p_flag & P_TRACED) != 0 + } +} From 21deb2e13134d306aa6aab40840f1f871a22e198 Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Wed, 18 Dec 2024 17:05:06 +0100 Subject: [PATCH 2/9] add DebuggerDetection to ThreatDetectionCenter --- Sources/DebuggerDetection.swift | 1 + Sources/ThreatDetectionCenter.swift | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Sources/DebuggerDetection.swift b/Sources/DebuggerDetection.swift index 2b0a6e7..e2f4733 100644 --- a/Sources/DebuggerDetection.swift +++ b/Sources/DebuggerDetection.swift @@ -22,6 +22,7 @@ fileprivate extension DebuggerDetection { let result = sysctl(&mib, u_int(mib.count), &info, &size, nil, 0) if result != 0 { fatalError("sysctl failed") + // Better to return false? } return (info.kp_proc.p_flag & P_TRACED) != 0 diff --git a/Sources/ThreatDetectionCenter.swift b/Sources/ThreatDetectionCenter.swift index ecd3745..35f9ea1 100644 --- a/Sources/ThreatDetectionCenter.swift +++ b/Sources/ThreatDetectionCenter.swift @@ -14,6 +14,10 @@ public final class ThreatDetectionCenter { SimulatorDetection.threatDetected() } + public static var isDebuggerAttached: Bool { + DebuggerDetection.threatDetected() + } + // MARK: - Async Threat Detection @@ -22,6 +26,7 @@ public final class ThreatDetectionCenter { case rootPrivileges case hooks case simulator + case debugger } /// Stream that contains possible threats that could be detected @@ -40,6 +45,10 @@ public final class ThreatDetectionCenter { continuation.yield(.simulator) } + if DebuggerDetection.threatDetected() { + continuation.yield(.debugger) + } + continuation.finish() } } From 728b244b9c8f1fec14948a30398a9391eb256a11 Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Wed, 18 Dec 2024 17:17:34 +0100 Subject: [PATCH 3/9] add debugger detection view to SecurityToolkitExample --- .../Resources/en.lproj/Localizable.strings | 2 ++ .../SecurityToolkitExample/Sources/ThreatStatus.swift | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/SecurityToolkitExample/SecurityToolkitExample/Resources/en.lproj/Localizable.strings b/SecurityToolkitExample/SecurityToolkitExample/Resources/en.lproj/Localizable.strings index 5a78803..d9aa6b6 100644 --- a/SecurityToolkitExample/SecurityToolkitExample/Resources/en.lproj/Localizable.strings +++ b/SecurityToolkitExample/SecurityToolkitExample/Resources/en.lproj/Localizable.strings @@ -5,6 +5,8 @@ "threat.hooks.description" = "Intercept system or application calls and then modify them (modify the return value of a function call for example)"; "threat.simulator.title" = "Simulator"; "threat.simulator.description" = "Running the application in a simulator"; +"threat.debugger.title" = "Debugger"; +"threat.debugger.description" = "A tool that allows developers to inspect and modify the execution of a program in real-time, potentially exposing sensitive data or allowing unauthorized control."; // MARK: Threat List "threat.list.title" = "Protection"; diff --git a/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift b/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift index 9cc9854..e2e3047 100644 --- a/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift +++ b/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift @@ -22,6 +22,11 @@ struct ThreatStatus: Hashable { description: R.string.localizable.threatSimulatorDescription(), isDetected: ThreatDetectionCenter.isSimulatorDetected ), + ThreatStatus( + title: R.string.localizable.threatDebuggerTitle(), + description: R.string.localizable.threatDebuggerDescription(), + isDetected: ThreatDetectionCenter.isDebuggerAttached + ), ] } From bf4a68b997df4f02ded4345748e7038a1fc7d5a1 Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Wed, 18 Dec 2024 17:55:50 +0100 Subject: [PATCH 4/9] add documentation for isDebuggerAttached --- Sources/ThreatDetectionCenter.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/ThreatDetectionCenter.swift b/Sources/ThreatDetectionCenter.swift index 35f9ea1..f5dd2e3 100644 --- a/Sources/ThreatDetectionCenter.swift +++ b/Sources/ThreatDetectionCenter.swift @@ -14,6 +14,11 @@ public final class ThreatDetectionCenter { SimulatorDetection.threatDetected() } + /// Checks whether your application is being traced by a debugger. + /// + /// A debugger is a tool that allows developers to inspect and modify the execution of a program in real-time, potentially exposing sensitive data or allowing unauthorized control. + /// + /// Please note that Apple itself uses a debugger during a review and you could prevent Apple from carrying out a complete review. Which Apple will certainly not like. public static var isDebuggerAttached: Bool { DebuggerDetection.threatDetected() } From 48d5c6b438cdaeb2a55b9b3476652ae68eb62728 Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Wed, 18 Dec 2024 19:31:43 +0100 Subject: [PATCH 5/9] fix typo: isDebuggerAttached -> isDebuggerDetected --- .../SecurityToolkitExample/Sources/ThreatStatus.swift | 2 +- Sources/ThreatDetectionCenter.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift b/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift index e2e3047..306cf4f 100644 --- a/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift +++ b/SecurityToolkitExample/SecurityToolkitExample/Sources/ThreatStatus.swift @@ -25,7 +25,7 @@ struct ThreatStatus: Hashable { ThreatStatus( title: R.string.localizable.threatDebuggerTitle(), description: R.string.localizable.threatDebuggerDescription(), - isDetected: ThreatDetectionCenter.isDebuggerAttached + isDetected: ThreatDetectionCenter.isDebuggerDetected ), ] } diff --git a/Sources/ThreatDetectionCenter.swift b/Sources/ThreatDetectionCenter.swift index f5dd2e3..5ff6ce7 100644 --- a/Sources/ThreatDetectionCenter.swift +++ b/Sources/ThreatDetectionCenter.swift @@ -19,7 +19,7 @@ public final class ThreatDetectionCenter { /// A debugger is a tool that allows developers to inspect and modify the execution of a program in real-time, potentially exposing sensitive data or allowing unauthorized control. /// /// Please note that Apple itself uses a debugger during a review and you could prevent Apple from carrying out a complete review. Which Apple will certainly not like. - public static var isDebuggerAttached: Bool { + public static var isDebuggerDetected: Bool { DebuggerDetection.threatDetected() } From 55c7a8a546b7a61b5ee96d4d20a0ec2fb8d56f2e Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Fri, 17 Jan 2025 14:40:41 +0100 Subject: [PATCH 6/9] Comment made even more clear --- Sources/ThreatDetectionCenter.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/ThreatDetectionCenter.swift b/Sources/ThreatDetectionCenter.swift index 5ff6ce7..bfdd68b 100644 --- a/Sources/ThreatDetectionCenter.swift +++ b/Sources/ThreatDetectionCenter.swift @@ -14,11 +14,12 @@ public final class ThreatDetectionCenter { SimulatorDetection.threatDetected() } - /// Checks whether your application is being traced by a debugger. + /// Will check if your application is being traced by a debugger. + /// Returns true if a debugger is detected. /// /// A debugger is a tool that allows developers to inspect and modify the execution of a program in real-time, potentially exposing sensitive data or allowing unauthorized control. /// - /// Please note that Apple itself uses a debugger during a review and you could prevent Apple from carrying out a complete review. Which Apple will certainly not like. + /// Please note that Apple itself may require a debugger for the app review process. public static var isDebuggerDetected: Bool { DebuggerDetection.threatDetected() } From 08c73be98d138c66dce57e8983144f614527401b Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Fri, 17 Jan 2025 14:43:51 +0100 Subject: [PATCH 7/9] hasTracerFlagSet() additionally made private --- Sources/DebuggerDetection.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/DebuggerDetection.swift b/Sources/DebuggerDetection.swift index e2f4733..7c31fc7 100644 --- a/Sources/DebuggerDetection.swift +++ b/Sources/DebuggerDetection.swift @@ -14,7 +14,7 @@ fileprivate extension DebuggerDetection { /// Check P_TRACED flag from Darwin Kernel /// if the process is traced - static func hasTracerFlagSet() -> Bool { + private static func hasTracerFlagSet() -> Bool { var info = kinfo_proc() var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()] // Kernel info, process info, specific process by PID, get current process ID var size = MemoryLayout.stride(ofValue: info) From cc20ff6c548525f139a075bb20ccc96f781ef9a0 Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Fri, 17 Jan 2025 14:46:36 +0100 Subject: [PATCH 8/9] No explicit Darwin import needed and therefore rmd no explicit Darwin import needed and therefore removed --- Sources/DebuggerDetection.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/DebuggerDetection.swift b/Sources/DebuggerDetection.swift index 7c31fc7..17195b7 100644 --- a/Sources/DebuggerDetection.swift +++ b/Sources/DebuggerDetection.swift @@ -1,5 +1,4 @@ import Foundation -import Darwin // MARK: - Internal internal final class DebuggerDetection { From 1633ef30fd179bd98a790f5f7dd7a0cd8df2d90a Mon Sep 17 00:00:00 2001 From: "Halder, Jannis" Date: Tue, 28 Jan 2025 15:59:21 +0100 Subject: [PATCH 9/9] Use of optional bool for isDebuggerDetected return Use of optional bool for public function isDebuggerDetected. This decision is the result of a joint discussion that took place in the associated PR #10 : https://github.com/EXXETA/iOS-Security-Toolkit/pull/10 Motivation: No exception should be thrown. It should be communicated that something went wrong in the decision-making process and that no clear statement can be made. Decision: We now return nil in an unclear case. nil: The detection process did not produce a definitive result. This could happen due to system limitations, lack of required permissions, or other undefined conditions. --- Sources/DebuggerDetection.swift | 12 ++++-------- Sources/ThreatDetectionCenter.swift | 11 ++++++++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Sources/DebuggerDetection.swift b/Sources/DebuggerDetection.swift index 17195b7..7d3026b 100644 --- a/Sources/DebuggerDetection.swift +++ b/Sources/DebuggerDetection.swift @@ -3,7 +3,7 @@ import Foundation // MARK: - Internal internal final class DebuggerDetection { - static func threatDetected() -> Bool { + static func threatDetected() -> Bool? { hasTracerFlagSet() } } @@ -13,17 +13,13 @@ fileprivate extension DebuggerDetection { /// Check P_TRACED flag from Darwin Kernel /// if the process is traced - private static func hasTracerFlagSet() -> Bool { + private static func hasTracerFlagSet() -> Bool? { var info = kinfo_proc() var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()] // Kernel info, process info, specific process by PID, get current process ID var size = MemoryLayout.stride(ofValue: info) - let result = sysctl(&mib, u_int(mib.count), &info, &size, nil, 0) - if result != 0 { - fatalError("sysctl failed") - // Better to return false? - } + let unixStatusCode = sysctl(&mib, u_int(mib.count), &info, &size, nil, 0) - return (info.kp_proc.p_flag & P_TRACED) != 0 + return unixStatusCode == 0 ? (info.kp_proc.p_flag & P_TRACED) != 0 : nil } } diff --git a/Sources/ThreatDetectionCenter.swift b/Sources/ThreatDetectionCenter.swift index bfdd68b..72ab0a7 100644 --- a/Sources/ThreatDetectionCenter.swift +++ b/Sources/ThreatDetectionCenter.swift @@ -15,12 +15,17 @@ public final class ThreatDetectionCenter { } /// Will check if your application is being traced by a debugger. - /// Returns true if a debugger is detected. + /// + /// - Returns: + /// `true`: If a debugger is detected. + /// `false`: If no debugger is detected. + /// `nil`: The detection process did not produce a definitive result. This could happen due to system limitations, lack of required permissions, or other undefined conditions. /// /// A debugger is a tool that allows developers to inspect and modify the execution of a program in real-time, potentially exposing sensitive data or allowing unauthorized control. /// + /// ## Notes /// Please note that Apple itself may require a debugger for the app review process. - public static var isDebuggerDetected: Bool { + public static var isDebuggerDetected: Bool? { DebuggerDetection.threatDetected() } @@ -51,7 +56,7 @@ public final class ThreatDetectionCenter { continuation.yield(.simulator) } - if DebuggerDetection.threatDetected() { + if DebuggerDetection.threatDetected() ?? false { continuation.yield(.debugger) }