Skip to content

Commit 55d1eb8

Browse files
Choura, Yessineychoura
authored andcommitted
1: add threat detection source code and set min target to 13
1 parent 46788e3 commit 55d1eb8

File tree

5 files changed

+223
-1
lines changed

5 files changed

+223
-1
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import PackageDescription
55
let package = Package(
66
name: "SecurityToolkit",
77
platforms: [
8-
.iOS(.v12),
8+
.iOS(.v13),
99
],
1010
products: [
1111
.library(

Sources/HooksDetection.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import Foundation
2+
import MachO
3+
4+
// MARK: - Internal
5+
internal final class HooksDetection {
6+
7+
static func threatDetected() -> Bool {
8+
hasDynamicLibrariesLoaded() || hasSuspiciousFiles() || hasOpenPorts()
9+
}
10+
}
11+
12+
// MARK: - Private
13+
fileprivate extension HooksDetection {
14+
15+
/// Check has loaded dynamic libraries
16+
private static func hasDynamicLibrariesLoaded() -> Bool {
17+
let suspiciousLibraries: Set<String> = [
18+
"frida",
19+
"cynject",
20+
"libcycript"
21+
]
22+
23+
for index in 0..<_dyld_image_count() {
24+
let imageName = String(cString: _dyld_get_image_name(index))
25+
for library in suspiciousLibraries where imageName.lowercased().contains(library) {
26+
return true
27+
}
28+
}
29+
30+
return false
31+
}
32+
33+
/// Check has suspicious files
34+
private static func hasSuspiciousFiles() -> Bool {
35+
let suspiciousFiles = [
36+
"/usr/sbin/frida-server"
37+
]
38+
return suspiciousFiles.contains(where: FileManager.default.fileExists(atPath:))
39+
}
40+
41+
/// Check has open ports
42+
private static func hasOpenPorts() -> Bool {
43+
let ports = [
44+
27042, // Frida
45+
4444, // Needle
46+
22, // OpenSSH
47+
44 // checkrain
48+
]
49+
return ports.contains(where: canOpenLocalConnection(port:))
50+
}
51+
52+
/// Check if it can open local connection
53+
private static func canOpenLocalConnection(port: Int) -> Bool {
54+
var serverAddress = sockaddr_in()
55+
serverAddress.sin_family = sa_family_t(AF_INET)
56+
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1")
57+
serverAddress.sin_port = Int(OSHostByteOrder()) == OSLittleEndian
58+
? _OSSwapInt16(in_port_t(port))
59+
: in_port_t(port)
60+
let sock = socket(AF_INET, SOCK_STREAM, 0)
61+
62+
let result = withUnsafePointer(to: &serverAddress) {
63+
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
64+
connect(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.stride))
65+
}
66+
}
67+
defer {
68+
close(sock)
69+
}
70+
return result != -1
71+
}
72+
}

Sources/JailbreakDetection.swift

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import Foundation
2+
import UIKit
3+
4+
// MARK: - Internal
5+
internal final class JailbreakDetection {
6+
7+
static func threatDetected() -> Bool {
8+
hasSuspiciousFiles() || hasUnexpectedFilePermissions() || canOpenSuspiciousLinks()
9+
}
10+
}
11+
12+
// MARK: - Private
13+
fileprivate extension JailbreakDetection {
14+
15+
/// Check for suspicious files
16+
static func hasSuspiciousFiles() -> Bool {
17+
let suspiciousFiles = [
18+
"/Applications/Cydia.app",
19+
"/Applications/FakeCarrier.app",
20+
"/Applications/Icy.app",
21+
"/Applications/IntelliScreen.app",
22+
"/Applications/MxTube.app",
23+
"/Applications/RockApp.app",
24+
"/Applications/SBSettings.app",
25+
"/Applications/WinterBoard.app",
26+
"/Applications/blackra1n.app",
27+
"/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist",
28+
"/Library/MobileSubstrate/DynamicLibraries/Veency.plist",
29+
"/Library/MobileSubstrate/MobileSubstrate.dylib",
30+
"/System/Library/LaunchDaemons/com.ikey.bbot.plist",
31+
"/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
32+
"/private/var/lib/apt",
33+
"/private/var/lib/cydia",
34+
"/private/var/mobile/Library/SBSettings/Themes",
35+
"/private/var/stash",
36+
"/private/var/tmp/cydia.log",
37+
"/var/tmp/cydia.log",
38+
"/var/cache/apt",
39+
"/var/lib/apt",
40+
"/var/lib/cydia",
41+
"/usr/sbin/frida-server",
42+
"/usr/bin/cycript",
43+
"/usr/local/bin/cycript",
44+
"/usr/lib/libcycript.dylib",
45+
"/var/log/syslog",
46+
// manually checked list for rootless palera1n jb
47+
"/var/jb",
48+
"/var/jb/.installed_dopamine",
49+
"/var/jb/Applications/Sileo.app",
50+
]
51+
52+
return suspiciousFiles.contains(where: FileManager.default.fileExists(atPath:))
53+
}
54+
55+
/// Will try to create and remove a file in a path which should be not allowed without root access
56+
private static func hasUnexpectedFilePermissions() -> Bool {
57+
let files = ["/private/jailbreak.txt", "/var/jb/jailbreak.txt", "/private/var/jb/jailbreak.txt"]
58+
for file in files {
59+
do {
60+
try "Test".write(toFile: file, atomically: true, encoding: String.Encoding.utf8)
61+
try FileManager.default.removeItem(atPath: file)
62+
return true
63+
} catch {
64+
// We actually want an error to be thrown, which means we were unable to create/delete the file which makes sense
65+
}
66+
}
67+
return false
68+
}
69+
70+
private static func canOpenSuspiciousLinks() -> Bool {
71+
let urls = [
72+
URL(string: "cydia://url/https://cydia.saurik.com/api/share#?source=https://beta.autotouch.net/")!,
73+
URL(string: "installer://add/repo=https://beta.autotouch.net/")!,
74+
URL(string: "sileo://source/https://beta.autotouch.net/")!,
75+
URL(string: "zbra://sources/add/https://beta.autotouch.net/")!
76+
]
77+
return urls.contains(where: UIApplication.shared.canOpenURL)
78+
}
79+
}

Sources/SimulatorDetection.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import Foundation
2+
3+
// MARK: - Internal
4+
internal final class SimulatorDetection {
5+
6+
static func threatDetected() -> Bool {
7+
runsInSimulator()
8+
}
9+
}
10+
11+
// MARK: - Private
12+
fileprivate extension SimulatorDetection {
13+
14+
/// Check if the app is running in a simulator
15+
static func runsInSimulator() -> Bool {
16+
#if targetEnvironment(simulator)
17+
return true
18+
#else
19+
if ProcessInfo.processInfo.environment["SIMULATOR_UDID"] != nil {
20+
return true
21+
}
22+
return false
23+
#endif
24+
}
25+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import Foundation
2+
3+
public final class ThreatDetectionCenter {
4+
5+
public static var areRootPrivilegesDetected: Bool {
6+
JailbreakDetection.threatDetected()
7+
}
8+
9+
public static var areHooksDetected: Bool {
10+
HooksDetection.threatDetected()
11+
}
12+
13+
public static var isSimulatorDetected: Bool {
14+
SimulatorDetection.threatDetected()
15+
}
16+
17+
18+
// MARK: - Async Threat Detection
19+
20+
/// Defines all possible threats, that can be reported via the stream
21+
public enum Threat: String {
22+
case rootPrivileges
23+
case hooks
24+
case simulator
25+
}
26+
27+
/// Stream that contains possible threats that could be detected
28+
public static var threats: AsyncStream<Threat> {
29+
AsyncStream<Threat> { continuation in
30+
31+
if JailbreakDetection.threatDetected() {
32+
continuation.yield(.rootPrivileges)
33+
}
34+
35+
if HooksDetection.threatDetected() {
36+
continuation.yield(.hooks)
37+
}
38+
39+
if SimulatorDetection.threatDetected() {
40+
continuation.yield(.simulator)
41+
}
42+
43+
continuation.finish()
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)