iOS vs Android:检测机制对比
系统架构差异
iOS系统特点:
- 沙盒机制:应用运行在严格的沙盒环境中
- 系统API限制:网络配置API相对封闭
- 证书管理:系统级证书固定和验证
- 越狱检测:多重越狱状态检测机制
Android系统特点:
- 开放生态:更多系统级API可访问
- 权限模型:基于权限的网络访问控制
- Root检测:相对简单的Root状态检测
- 系统属性:可直接访问系统配置
检测点对比表
| 检测维度 |
iOS检测方法 |
Android检测方法 |
绕过难度 |
| 系统代理 |
CFNetwork代理设置、NSURLSession配置 |
ConnectivityManager、Proxy.getDefaultHost() |
iOS更难 |
| VPN检测 |
NWPathMonitor、Network.framework |
NetworkCapabilities.TRANSPORT_VPN |
iOS更难 |
| 证书检测 |
SecTrustEvaluate、SSL Pinning |
X509TrustManager、Certificate Pinning |
相当 |
| 网络接口 |
getifaddrs、ifconfig |
NetworkInterface、ifconfig |
iOS更难 |
| 抓包检测 |
证书链验证、SNI检测 |
证书验证、代理头检测 |
iOS更难 |
| 越狱检测 |
文件系统、API调用、沙盒检查 |
Root文件、su命令、系统属性 |
iOS更难 |
iOS代理检测原理深度解析
1. 系统代理检测
CFNetwork代理检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import Foundation import Network
class ProxyDetector { func detectSystemProxy() -> Bool { let proxySettings = CFNetworkCopySystemProxySettings() let proxyDict = proxySettings?.takeRetainedValue() as? [String: Any] if let httpProxy = proxyDict?["HTTPProxy"] as? String, !httpProxy.isEmpty { print("检测到HTTP代理: \(httpProxy)") return true } if let httpsProxy = proxyDict?["HTTPSProxy"] as? String, !httpsProxy.isEmpty { print("检测到HTTPS代理: \(httpsProxy)") return true } return false } func detectSOCKSProxy() -> Bool { let proxySettings = CFNetworkCopySystemProxySettings() let proxyDict = proxySettings?.takeRetainedValue() as? [String: Any] if let socksProxy = proxyDict?["SOCKSProxy"] as? String, !socksProxy.isEmpty { print("检测到SOCKS代理: \(socksProxy)") return true } return false } }
|
NSURLSession代理检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class URLSessionProxyDetector { func detectProxyInURLSession() -> Bool { let config = URLSessionConfiguration.default if let proxyDict = config.connectionProxyDictionary { print("检测到URLSession代理配置: \(proxyDict)") return true } if config.httpProxy != nil || config.httpsProxy != nil { print("检测到HTTP/HTTPS代理") return true } return false } }
|
2. VPN和隧道检测
Network.framework检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import Network
class VPNDetector { private let monitor = NWPathMonitor() func detectVPN() -> Bool { var isVPNConnected = false monitor.pathUpdateHandler = { path in for interface in path.availableInterfaces { if interface.type == .wifi || interface.type == .cellular { if self.hasVPNInterface() { isVPNConnected = true print("检测到VPN连接") } } } } let queue = DispatchQueue(label: "VPNMonitor") monitor.start(queue: queue) return isVPNConnected } private func hasVPNInterface() -> Bool { var ifaddr: UnsafeMutablePointer<ifaddrs>? guard getifaddrs(&ifaddr) == 0 else { return false } var current = ifaddr while current != nil { let interface = current!.pointee let name = String(cString: interface.ifa_name) if name.hasPrefix("utun") || name.hasPrefix("ipsec") || name.hasPrefix("ppp") || name.hasPrefix("tun") { freeifaddrs(ifaddr) return true } current = interface.ifa_next } freeifaddrs(ifaddr) return false } }
|
3. 证书和抓包检测
SSL Pinning检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import Security
class CertificateDetector { func detectCertificatePinning() -> Bool { let session = URLSession(configuration: .default) let mirror = Mirror(reflecting: session) for child in mirror.children { if child.label == "delegate" && child.value != nil { print("检测到自定义URLSessionDelegate,可能存在证书固定") return true } } return false } func detectCertificateChainAnomaly() -> Bool { return false } }
|
SNI检测
1 2 3 4 5 6 7
| class SNIDetector { func detectSNIManipulation() -> Bool { return false } }
|
4. 网络接口检测
网络接口分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import Foundation
class NetworkInterfaceDetector { func analyzeNetworkInterfaces() -> [String: Any] { var interfaces: [String: Any] = [:] var ifaddr: UnsafeMutablePointer<ifaddrs>? guard getifaddrs(&ifaddr) == 0 else { return interfaces } var current = ifaddr while current != nil { let interface = current!.pointee let name = String(cString: interface.ifa_name) if interface.ifa_addr != nil { let family = interface.ifa_addr.pointee.sa_family if family == UInt8(AF_INET) || family == UInt8(AF_INET6) { var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) let address = String(cString: hostname) interfaces[name] = [ "address": address, "family": family, "flags": interface.ifa_flags ] } } current = interface.ifa_next } freeifaddrs(ifaddr) return interfaces } }
|
Frida Hook绕过技术
1. Hook CFNetwork代理检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| function hookCFNetworkProxy() { var CFNetworkCopySystemProxySettings = Module.findExportByName("CFNetwork", "CFNetworkCopySystemProxySettings"); if (CFNetworkCopySystemProxySettings) { Interceptor.attach(CFNetworkCopySystemProxySettings, { onEnter: function(args) { console.log("[+] CFNetworkCopySystemProxySettings called"); }, onLeave: function(retval) { console.log("[+] Returning empty proxy settings"); retval.replace(ptr(0)); } }); } var CFNetworkCopyProxiesForURL = Module.findExportByName("CFNetwork", "CFNetworkCopyProxiesForURL"); if (CFNetworkCopyProxiesForURL) { Interceptor.attach(CFNetworkCopyProxiesForURL, { onEnter: function(args) { console.log("[+] CFNetworkCopyProxiesForURL called"); }, onLeave: function(retval) { console.log("[+] Returning empty proxy array"); retval.replace(ptr(0)); } }); } }
|
2. Hook Network.framework
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function hookNWPathMonitor() { var NWPathMonitor = ObjC.classes.NWPathMonitor; if (NWPathMonitor) { var originalSetPathUpdateHandler = NWPathMonitor['- setPathUpdateHandler:']; Interceptor.attach(originalSetPathUpdateHandler.implementation, { onEnter: function(args) { console.log("[+] NWPathMonitor setPathUpdateHandler called"); }, onLeave: function(retval) { } }); } }
|
3. Hook证书验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function hookSecTrustEvaluate() { var SecTrustEvaluate = Module.findExportByName("Security", "SecTrustEvaluate"); if (SecTrustEvaluate) { Interceptor.attach(SecTrustEvaluate, { onEnter: function(args) { console.log("[+] SecTrustEvaluate called"); }, onLeave: function(retval) { console.log("[+] Forcing SecTrustEvaluate to return success"); retval.replace(ptr(0)); } }); } var SecTrustEvaluateWithError = Module.findExportByName("Security", "SecTrustEvaluateWithError"); if (SecTrustEvaluateWithError) { Interceptor.attach(SecTrustEvaluateWithError, { onEnter: function(args) { console.log("[+] SecTrustEvaluateWithError called"); }, onLeave: function(retval) { console.log("[+] Forcing SecTrustEvaluateWithError to return true"); retval.replace(ptr(1)); } }); } }
|
4. Hook网络接口检测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function hookGetifaddrs() { var getifaddrs = Module.findExportByName("libc", "getifaddrs"); if (getifaddrs) { Interceptor.attach(getifaddrs, { onEnter: function(args) { console.log("[+] getifaddrs called"); }, onLeave: function(retval) { console.log("[+] getifaddrs returned: " + retval); } }); } }
|
越狱环境下的高级绕过
1. 使用Substrate Hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| %hook NSURLSessionConfiguration
- (NSDictionary *)connectionProxyDictionary { NSLog(@"[+] NSURLSessionConfiguration connectionProxyDictionary called"); return @{}; }
%end
%hook NSURLSession
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler { NSLog(@"[+] NSURLSession dataTaskWithRequest called"); return %orig; }
%end
|
2. 使用Theos开发Tweak
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| %hook NSURLSessionConfiguration
- (NSDictionary *)connectionProxyDictionary { return nil; }
%end
%hook NWPathMonitor
- (void)setPathUpdateHandler:(void (^)(NWPath *path))handler { %orig; }
%end
|
3. 系统级修改
1 2 3 4 5 6 7 8
|
plutil -p /var/preferences/SystemConfiguration/preferences.plist
rm -f /var/preferences/SystemConfiguration/preferences.plist
|
非越狱环境下的绕过策略
1. 使用Shadowrocket等工具
Shadowrocket配置:
1 2 3 4 5 6 7 8 9 10 11
| [General]
enhanced-mode = true
hide-vpn-icon = true
use-system-proxy = true
[Rule]
DOMAIN-SUFFIX,example.com,DIRECT
|
2. 使用Quantumult X
Quantumult X配置:
1 2 3 4 5 6 7 8 9
| [general]
enhanced-mode = true
hide-vpn-icon = true
[policy]
static=bypass, direct, img-url=https://example.com/icon.png
|
3. 使用Surge
Surge配置:
1 2 3 4 5 6 7 8 9
| [General] # 启用增强模式 enhanced-mode = true # 隐藏VPN标识 hide-vpn-icon = true
[Rule] # 绕过检测 DOMAIN-SUFFIX,example.com,DIRECT
|
结语
iOS代理检测与绕过技术相比Android更加复杂,需要更深入的系统知识和更高级的技术手段。理解检测原理,掌握绕过技术,是移动安全研究的重要技能。
本文关键点:
- 系统差异:iOS的封闭生态使得检测更加隐蔽,绕过更加困难
- 技术演进:从简单Hook到系统级修改,技术手段不断升级