ios开发逆向安全防抓包

  1. 防止抓包

    • 使用SSL Pinning(证书绑定):在客户端内置服务器证书或公钥,在建立SSL/TLS连接时进行验证,防止中间人攻击。

    • 避免使用明文传输:所有网络请求使用HTTPS,并且确保正确的证书验证。

  2. 代码混淆

    • 使用工具对Objective-C代码进行混淆,增加逆向难度。例如,类名、方法名、属性名使用无意义的字符串替换。
  3. 反调试

    • 使用系统API检测是否被调试,如果被调试则采取相应措施(如退出应用)。
  4. 完整性检查

    • 检查应用是否被重签名或篡改,可以通过比较嵌入的签名或检查文件完整性来实现。
  5. 字符串加密

    • 对敏感字符串进行加密,防止在二进制文件中直接显示。
  6. 使用C代码

    • 将敏感逻辑用C/C++实现,因为C/C++编译后的代码比Objective-C更难逆向。
  7. 动态加载代码

    • 从服务器下载加密的代码,在运行时解密执行,增加静态分析的难度。
  8. 使用安全框架

    • 使用第三方安全框架,如Obfuscator、Themis等。

下面是一些具体的实现示例:

1. SSL Pinning

在iOS中,可以使用NSURLSessionAFNetworking等网络库来实现SSL Pinning。

使用NSURLSession的示例:

  • (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {

if (challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust) {

SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;

// 加载内置的证书

NSString *certPath = \[NSBundle mainBundle pathForResource:@"server" ofType:@"cer"];

NSData *certData = NSData dataWithContentsOfFile:certPath;

SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);

// 设置锚点证书

SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)@(__bridge id)cert);

SecTrustResultType result;

SecTrustEvaluate(serverTrust, &result);

if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {

NSURLCredential *credential = NSURLCredential credentialForTrust:serverTrust;

completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

} else {

completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);

}

CFRelease(cert);

} else {

completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);

}

}

2. 代码混淆

可以使用脚本在编译阶段对类名、方法名进行替换。例如,使用一个宏定义来替换方法名:

// 定义一个混淆宏,在预编译阶段将方法名替换为随机字符串

#define OBFUSCATE(string) NSString stringWithUTF8String:obfuscateCString(string)

// 随机字符串生成函数

const char* obfuscateCString(const char* string) {

// 实现一个简单的混淆算法,例如异或操作

// 注意:这里只是示例,实际使用时需要更复杂的算法

static char obfuscated256;

for (int i = 0; i < strlen(string); i++) {

obfuscatedi = stringi ^ 0x55;

}

obfuscatedstrlen(string) = '\0';

return obfuscated;

}

// 使用示例

NSString *secretKey = OBFUSCATE("mySecretKey");

但是,这种方法需要谨慎使用,因为可能会引起运行时错误。更常见的做法是使用第三方工具,如Obfuscator-iOS。

3. 反调试

通过ptrace系统调用可以防止调试器附加。但是,ptrace是私有API,使用它可能会导致App Store审核被拒。因此,在发布版本中不建议使用。

#import <sys/types.h>

#import <sys/sysctl.h>

#import <unistd.h>

// 检查是否被调试

static int checkDebugger() {

int name4;

struct kinfo_proc info;

size_t info_size = sizeof(info);

name0 = CTL_KERN;

name1 = KERN_PROC;

name2 = KERN_PROC_PID;

name3 = getpid();

if (sysctl(name, 4, &info, &info_size, NULL, 0) == -1) {

NSLog(@"sysctl failed");

return -1;

}

return (info.kp_proc.p_flag & P_TRACED) ? 1 : 0;

}

// 在应用启动时调用

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// 如果检测到调试器,可以采取相应措施,如退出应用

if (checkDebugger()) {

exit(0);

}

return YES;

}

4. 完整性检查

检查签名是否匹配:

  • (BOOL)isValidSignature {

// 获取嵌入的签名

NSString *embeddedSignature = @"your_embedded_signature"; // 从服务器获取或内置

// 计算当前应用的签名(这里简化,实际需要获取代码签名信息)

// 可以使用SecCodeCopySigningInformation等函数

// 比较两个签名是否一致

return embeddedSignature isEqualToString:currentSignature;

}

5. 字符串加密

对敏感字符串进行加密,运行时解密:

// 加密字符串(示例:Base64编码,实际可以使用更复杂的加密)

#define ENCRYPT(string) \[string dataUsingEncoding:NSUTF8StringEncoding base64EncodedStringWithOptions:0]

#define DECRYPT(string) \[NSString alloc initWithData:\[NSData alloc initWithBase64EncodedString:string options:0] encoding:NSUTF8StringEncoding]

// 使用

NSString *encrypted = ENCRYPT(@"secret string");

NSString *decrypted = DECRYPT(encrypted);

6. 使用C代码

将敏感算法用C实现,并编译成静态库,增加逆向难度。

7. 动态加载代码

从服务器下载加密的代码(如JavaScript代码,通过JavaScriptCore执行),或者使用动态库(但iOS限制较多)。

8. 使用安全框架

集成第三方安全框架,如Themis(提供安全存储、加密通信等功能)。

请注意,没有任何方法可以完全防止逆向工程,但通过多种措施组合可以增加逆向的难度。同时,要平衡安全性和用户体验,以及避免使用私有API导致审核被拒。

iOS逆向安全防抓包需要从多个层面进行防护,以下是Objective-C实现的关键方案:

一、网络层防护

1. SSL/TLS证书绑定

// SSLPinningManager.h

@interface SSLPinningManager : NSObject

  • (instancetype)sharedManager;
  • (void)setupSSLPinning;

@end

// SSLPinningManager.m

@implementation SSLPinningManager

  • (void)setupSSLPinning {

// 方法1:公钥绑定

self setupPublicKeyPinning;

// 方法2:证书绑定

self setupCertificatePinning;

}

  • (void)setupPublicKeyPinning {

// 使用AFNetworking或原生NSURLSession实现

AFSecurityPolicy *policy = AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey;

policy.allowInvalidCertificates = NO;

policy.validatesDomainName = YES;

// 设置公钥哈希数组

NSArray *pinnedKeys = @[

@"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // 替换为实际公钥哈希

];

policy.pinnedCertificates = NSSet setWithArray:pinnedKeys;

AFHTTPSessionManager manager.securityPolicy = policy;

}

  • (void)setupCertificatePinning {

// 原生NSURLSession实现

NSURLSessionConfiguration *config = NSURLSessionConfiguration defaultSessionConfiguration;

config.TLSMinimumSupportedProtocol = kTLSProtocol12;

// 添加自定义SSL验证

[NSURLSession sessionWithConfiguration:config

delegate:self

delegateQueue:nil];

}

#pragma mark - NSURLSessionDelegate

  • (void)URLSession:(NSURLSession *)session

didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge

completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

if (challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust) {

SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;

// 1. 设置策略

SecPolicyRef policy = SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host);

SecTrustSetPolicies(serverTrust, policy);

// 2. 验证证书链

SecTrustResultType result;

SecTrustEvaluate(serverTrust, &result);

// 3. 自定义验证:检查是否包含预置证书

BOOL isTrusted = self validateCertificate:serverTrust;

if (isTrusted) {

NSURLCredential *credential = NSURLCredential credentialForTrust:serverTrust;

completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

} else {

completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);

}

}

}

  • (BOOL)validateCertificate:(SecTrustRef)trust {

// 获取证书链

CFIndex certificateCount = SecTrustGetCertificateCount(trust);

// 加载预置证书

NSString *certPath = \[NSBundle mainBundle pathForResource:@"your_certificate" ofType:@"der"];

NSData *certData = NSData dataWithContentsOfFile:certPath;

SecCertificateRef embeddedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);

for (CFIndex i = 0; i < certificateCount; i++) {

SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, i);

// 比较证书

if (CFEqual(certificate, embeddedCertificate)) {

CFRelease(embeddedCertificate);

return YES;

}

}

CFRelease(embeddedCertificate);

return NO;

}

@end

2. 双向认证 (mTLS)

// MutualTLSAuthManager.h

@interface MutualTLSAuthManager : NSObject

  • (void)setupClientCertificate;

@end

// MutualTLSAuthManager.m

@implementation MutualTLSAuthManager {

NSData *_clientCertificate;

SecIdentityRef _identity;

}

  • (void)setupClientCertificate {

// 从Keychain或加密存储中加载客户端证书

NSString *encryptedCertPath = \[NSBundle mainBundle pathForResource:@"client_cert_encrypted" ofType:@"p12"];

NSData *encryptedData = NSData dataWithContentsOfFile:encryptedCertPath;

// 解密证书

NSData *decryptedData = self decryptData:encryptedData;

// 导入证书到Keychain

self importPKCS12Data:decryptedData;

}

  • (void)importPKCS12Data:(NSData *)pkcs12Data {

CFArrayRef items = NULL;

NSDictionary *options = @{

(__bridge id)kSecImportExportPassphrase: self getDecryptionKey

};

OSStatus status = SecPKCS12Import((__bridge CFDataRef)pkcs12Data,

(__bridge CFDictionaryRef)options,

&items);

if (status == errSecSuccess) {

CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);

_identity = (SecIdentityRef)CFDictionaryGetValue(identityDict,

kSecImportItemIdentity);

CFRetain(_identity);

}

if (items) CFRelease(items);

}

// 在NSURLSessionDelegate中使用

  • (void)URLSession:(NSURLSession *)session

didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge

completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

if (challenge.previousFailureCount == 0 && _identity) {

SecCertificateRef certificate = NULL;

SecIdentityCopyCertificate(_identity, &certificate);

NSArray *certs = @(__bridge id)certificate;

NSURLCredential *credential = [NSURLCredential credentialWithIdentity:_identity

certificates:certs

persistence:NSURLCredentialPersistenceForSession];

completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

if (certificate) CFRelease(certificate);

} else {

completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);

}

}

二、防代理检测

// ProxyDetectionManager.h

@interface ProxyDetectionManager : NSObject

  • (BOOL)isProxyEnabled;

  • (BOOL)isVPNConnected;

@end

// ProxyDetectionManager.m

#import <SystemConfiguration/SystemConfiguration.h>

@implementation ProxyDetectionManager

  • (BOOL)isProxyEnabled {

CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings();

NSDictionary *settings = (__bridge NSDictionary *)proxySettings;

BOOL enabled = NO;

// 检查HTTP代理

NSString *httpProxy = settings(NSString \*)kCFNetworkProxiesHTTPProxy;

NSString *httpsProxy = settings(NSString \*)kCFNetworkProxiesHTTPSProxy;

if (httpProxy || httpsProxy) {

enabled = YES;

}

// 检查PAC代理

NSString *pacURL = settings(NSString \*)kCFNetworkProxiesProxyAutoConfigURLString;

if (pacURL) {

enabled = YES;

}

CFRelease(proxySettings);

// 额外检查:Charles等工具常用端口

if (enabled) {

enabled = self checkSpecificProxyPorts;

}

return enabled;

}

  • (BOOL)checkSpecificProxyPorts {

// 常见抓包工具端口检测

NSArray *commonProxyPorts = @@8888, @8889, @8080, @8081, @9999;

for (NSNumber *port in commonProxyPorts) {

int socketFD = socket(AF_INET, SOCK_STREAM, 0);

if (socketFD == -1) continue;

struct sockaddr_in addr;

memset(&addr, 0, sizeof(addr));

addr.sin_len = sizeof(addr);

addr.sin_family = AF_INET;

addr.sin_port = htons(port intValue);

addr.sin_addr.s_addr = inet_addr("127.0.0.1");

if (connect(socketFD, (struct sockaddr *)&addr, sizeof(addr)) == 0) {

close(socketFD);

return YES;

}

close(socketFD);

}

return NO;

}

  • (BOOL)isVPNConnected {

// 检查VPN连接状态

CFDictionaryRef cfDict = CFNetworkCopySystemProxySettings();

NSDictionary *dict = (__bridge NSDictionary *)cfDict;

NSArray *keys = dict\[@"__SCOPED__" allKeys];

for (NSString *key in keys) {

if (key containsString:@"tap" ||

key containsString:@"tun" ||

key containsString:@"ppp" ||

key containsString:@"ipsec") {

CFRelease(cfDict);

return YES;

}

}

CFRelease(cfDict);

return NO;

}

@end

三、请求保护

1. 参数签名

// RequestSigner.h

@interface RequestSigner : NSObject

  • (NSString *)signRequestWithParams:(NSDictionary *)params

timestamp:(NSTimeInterval)timestamp;

  • (NSDictionary *)signedHeadersForRequest:(NSURLRequest *)request;

@end

// RequestSigner.m

#import <CommonCrypto/CommonHMAC.h>

@implementation RequestSigner

  • (NSString *)signRequestWithParams:(NSDictionary *)params

timestamp:(NSTimeInterval)timestamp {

// 1. 参数排序并拼接

NSArray *sortedKeys = \[params allKeys sortedArrayUsingSelector:@selector(compare:)];

NSMutableString *signString = NSMutableString string;

for (NSString *key in sortedKeys) {

signString appendFormat:@"%@=%@\&", key, params\[key];

}

// 2. 添加时间戳和随机数

NSString *nonce = self generateNonce;

signString appendFormat:@"timestamp=%f\&nonce=%@", timestamp, nonce;

// 3. 添加动态密钥(定期更新)

NSString *dynamicKey = self getDynamicKey;

signString appendFormat:@"\&dynamic_key=%@", dynamicKey;

// 4. HMAC签名

NSString *signature = [self hmacSHA256:signString

secret:self getAppSecret];

return signature;

}

  • (NSString *)generateNonce {

// 生成随机字符串

NSString *uuid = \[NSUUID UUID UUIDString];

return \[uuid stringByReplacingOccurrencesOfString:@"-" withString:@""

substringToIndex:16];

}

  • (NSString *)getDynamicKey {

// 从服务器获取或本地生成的动态密钥

// 可以定期更新,增加破解难度

NSTimeInterval interval = \[NSDate date timeIntervalSince1970];

NSInteger hour = (NSInteger)(interval / 3600);

// 基于时间的动态密钥

NSString *baseKey = @"base_secret_key";

NSString *timeKey = NSString stringWithFormat:@"%ld", (long)hour;

return self hmacSHA256:timeKey secret:baseKey;

}

  • (NSString *)hmacSHA256:(NSString *)data secret:(NSString *)secret {

const char *cData = data cStringUsingEncoding:NSUTF8StringEncoding;

const char *cSecret = secret cStringUsingEncoding:NSUTF8StringEncoding;

unsigned char cHMACCC_SHA256_DIGEST_LENGTH;

CCHmac(kCCHmacAlgSHA256, cSecret, strlen(cSecret), cData, strlen(cData), cHMAC);

NSData *hmacData = \[NSData alloc initWithBytes:cHMAC length:sizeof(cHMAC)];

return hmacData base64EncodedStringWithOptions:0;

}

  • (NSDictionary *)signedHeadersForRequest:(NSURLRequest *)request {

NSTimeInterval timestamp = \[NSDate date timeIntervalSince1970];

NSString *nonce = self generateNonce;

// 获取请求体

NSData *bodyData = request.HTTPBody;

NSString *bodyString = \[NSString alloc initWithData:bodyData encoding:NSUTF8StringEncoding];

// 生成签名

NSString *signature = [self signRequestWithBody:bodyString

timestamp:timestamp

nonce:nonce];

return @{

@"X-Timestamp": @(timestamp).stringValue,

@"X-Nonce": nonce,

@"X-Signature": signature,

@"X-App-Version": \[NSBundle mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"],

@"X-Device-ID": self getDeviceUniqueID

};

}

@end

2. 请求加密

// RequestEncryptor.h

@interface RequestEncryptor : NSObject

  • (NSData *)encryptRequestData:(NSDictionary *)params;

  • (NSDictionary *)decryptResponseData:(NSData *)data;

@end

// RequestEncryptor.m

#import <CommonCrypto/CommonCryptor.h>

@implementation RequestEncryptor

  • (NSData *)encryptRequestData:(NSDictionary *)params {

// 1. JSON序列化

NSError *error;

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params

options:0

error:&error];

// 2. AES加密

NSData *encryptedData = self aes256Encrypt:jsonData;

// 3. Base64编码

NSString *base64String = encryptedData base64EncodedStringWithOptions:0;

// 4. 添加混淆(可选)

base64String = self obfuscateString:base64String;

return base64String dataUsingEncoding:NSUTF8StringEncoding;

}

  • (NSData *)aes256Encrypt:(NSData *)data {

char keyPtrkCCKeySizeAES256 + 1;

bzero(keyPtr, sizeof(keyPtr));

// 动态密钥生成

NSString *dynamicKey = self generateDynamicKey;

dynamicKey getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding;

NSUInteger dataLength = data length;

size_t bufferSize = dataLength + kCCBlockSizeAES128;

void *buffer = malloc(bufferSize);

size_t numBytesEncrypted = 0;

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,

kCCOptionPKCS7Padding,

keyPtr, kCCKeySizeAES256,

NULL,

data bytes, dataLength,

buffer, bufferSize,

&numBytesEncrypted);

if (cryptStatus == kCCSuccess) {

return NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted;

}

free(buffer);

return nil;

}

  • (NSString *)generateDynamicKey {

// 基于设备指纹和应用状态的动态密钥

NSString *deviceID = self getDeviceID;

NSString *appVersion = \[NSBundle mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];

NSTimeInterval time = floor(\[NSDate date timeIntervalSince1970] / 3600);

NSString *baseString = [NSString stringWithFormat:@"%@|%@|%.0f",

deviceID, appVersion, time];

// SHA256哈希作为密钥

const char *cStr = baseString UTF8String;

unsigned char resultCC_SHA256_DIGEST_LENGTH;

CC_SHA256(cStr, (CC_LONG)strlen(cStr), result);

NSData *hashData = NSData dataWithBytes:result length:CC_SHA256_DIGEST_LENGTH;

return hashData base64EncodedStringWithOptions:0;

}

  • (NSString *)obfuscateString:(NSString *)string {

// 简单混淆:交换字符位置

NSMutableString *obfuscated = NSMutableString stringWithString:string;

NSInteger length = obfuscated.length;

for (int i = 0; i < length / 2; i++) {

unichar temp = obfuscated characterAtIndex:i;

[obfuscated replaceCharactersInRange:NSMakeRange(i, 1)

withString:[NSString stringWithFormat:@"%c",

obfuscated characterAtIndex:length - i - 1]];

[obfuscated replaceCharactersInRange:NSMakeRange(length - i - 1, 1)

withString:NSString stringWithFormat:@"%c", temp];

}

return obfuscated;

}

@end

四、代码混淆与保护

1. 字符串加密

// StringObfuscator.h

@interface StringObfuscator : NSObject

  • (NSString *)decryptString:(const unsigned char *)encryptedData

length:(size_t)length;

@end

// StringObfuscator.m

@implementation StringObfuscator

// 加密字符串的宏(在编译前执行)

#define OBFUSCATE(key) StringObfuscator decryptString:obf_##key length:sizeof(obf_##key)

// 加密后的字符串数据(示例)

static const unsigned char obf_api_key\[\] = {0xAA, 0xBB, 0xCC, ...};

static const unsigned char obf_secret\[\] = {0xDD, 0xEE, 0xFF, ...};

  • (NSString *)decryptString:(const unsigned char *)encryptedData

length:(size_t)length {

// XOR解密

unsigned char *decrypted = malloc(length + 1);

for (int i = 0; i < length; i++) {

decryptedi = encryptedDatai ^ 0x55; // 简单XOR,可以使用更复杂算法

}

decryptedlength = '\0';

NSString *result = NSString stringWithUTF8String:(const char \*)decrypted;

free(decrypted);

return result;

}

// 使用示例

  • (void)makeRequest {

NSString *apiKey = OBFUSCATE(api_key);

NSString *secret = OBFUSCATE(secret);

// 使用解密后的字符串

}

@end

2. 防Hook检测

// HookDetectionManager.h

@interface HookDetectionManager : NSObject

  • (BOOL)isMethodHooked:(Class)className selector:(SEL)selector;

  • (void)addAntiHookProtection;

@end

// HookDetectionManager.m

#import <objc/runtime.h>

#import <mach-o/dyld.h>

@implementation HookDetectionManager

  • (BOOL)isMethodHooked:(Class)className selector:(SEL)selector {

Method originalMethod = class_getInstanceMethod(className, selector);

// 获取方法实现地址

IMP originalIMP = method_getImplementation(originalMethod);

// 检查IMP是否指向预期代码段

Dl_info info;

if (dladdr((void *)originalIMP, &info)) {

// 检查是否在系统库中

const char *imageName = info.dli_fname;

NSString *imagePath = NSString stringWithUTF8String:imageName;

// 如果不在主程序镜像中,可能被Hook

if (!imagePath containsString:\[\[NSBundle mainBundle bundlePath]]) {

return YES;

}

}

return NO;

}

  • (void)addAntiHookProtection {

// 1. 检查关键方法是否被Hook

self checkCriticalMethods;

// 2. 添加反Hook代码

self installTrampolines;

// 3. 检测Cydia Substrate等框架

self detectInjectionFrameworks;

}

  • (void)checkCriticalMethods {

NSArray *criticalSelectors = @[

@"encryptData:",

@"decryptData:",

@"signRequest:",

@"getApiKey"

];

for (NSString *selectorName in criticalSelectors) {

SEL selector = NSSelectorFromString(selectorName);

if (self isMethodHooked:\[self class selector:selector]) {

self takeProtectiveAction;

}

}

}

  • (void)installTrampolines {

// 使用汇编保护关键函数

attribute((always_inline)) void protectedFunction() {

// 内联汇编保护

#ifdef arm64

asm volatile(

"mov x0, #0\n"

"ret\n"

);

#endif

}

}

  • (void)detectInjectionFrameworks {

// 检查动态库注入

uint32_t count = _dyld_image_count();

for (uint32_t i = 0; i < count; i++) {

const char *imageName = _dyld_get_image_name(i);

NSString *imagePath = NSString stringWithUTF8String:imageName;

// 检测常见注入框架

NSArray *injectionKeywords = @[

@"MobileSubstrate",

@"CydiaSubstrate",

@"cynject",

@"libhooker",

@"ElleKit",

@"Substitute"

];

for (NSString *keyword in injectionKeywords) {

if (imagePath containsString:keyword) {

self takeProtectiveAction;

break;

}

}

}

}

  • (void)takeProtectiveAction {

// 触发保护机制

self clearSensitiveData;

self crashRandomly; // 或执行其他混淆行为

exit(0); // 最后退出

}

@end

五、综合防护方案

// SecurityManager.h

@interface SecurityManager : NSObject

  • (void)initializeSecurity;

  • (BOOL)isEnvironmentSafe;

@end

// SecurityManager.m

@implementation SecurityManager

  • (void)initializeSecurity {

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

// 1. 检查运行环境

if (!self isEnvironmentSafe) {

self handleUnsafeEnvironment;

return;

}

// 2. 设置网络防护

\[SSLPinningManager sharedManager setupSSLPinning];

\[MutualTLSAuthManager sharedManager setupClientCertificate];

// 3. 检测代理

if (ProxyDetectionManager isProxyEnabled ||

ProxyDetectionManager isVPNConnected) {

self handleProxyDetected;

}

// 4. 防Hook保护

HookDetectionManager addAntiHookProtection;

// 5. 定时检查

self scheduleSecurityChecks;

});

}

  • (BOOL)isEnvironmentSafe {

// 越狱检测

if (self isJailbroken) return NO;

// 调试器检测

if (self isDebuggerAttached) return NO;

// 重签名检测

if (self isResigned) return NO;

// 模拟器检测

#if TARGET_IPHONE_SIMULATOR

return NO;

#endif

return YES;

}

  • (BOOL)isJailbroken {

// 常见越狱文件检测

NSArray *jailbreakPaths = @[

@"/Applications/Cydia.app",

@"/Library/MobileSubstrate/MobileSubstrate.dylib",

@"/bin/bash",

@"/usr/sbin/sshd",

@"/etc/apt"

];

for (NSString *path in jailbreakPaths) {

if (\[NSFileManager defaultManager fileExistsAtPath:path]) {

return YES;

}

}

// 尝试写入系统目录

NSString *testPath = @"/private/test.txt";

NSError *error;

@"test" writeToFile:testPath atomically:YES encoding:NSUTF8StringEncoding error:\&error;

\[NSFileManager defaultManager removeItemAtPath:testPath error:nil];

return (error == nil);

}

  • (BOOL)isDebuggerAttached {

// ptrace反调试

#ifndef PT_DENY_ATTACH

#define PT_DENY_ATTACH 31

#endif

// 方法1:ptrace

typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);

ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(RTLD_DEFAULT, "ptrace");

if (ptrace_ptr) {

ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);

}

// 方法2:syscall

syscall(26, 31, 0, 0, 0);

// 方法3:检测父进程

struct kinfo_proc info;

size_t size = sizeof(info);

int name4;

name0 = CTL_KERN;

name1 = KERN_PROC;

name2 = KERN_PROC_PID;

name3 = getppid();

if (sysctl(name, 4, &info, &size, NULL, 0) != -1) {

if (strcmp(info.kp_proc.p_comm, "debugserver") == 0 ||

strcmp(info.kp_proc.p_comm, "lldb") == 0) {

return YES;

}

}

return NO;

}

  • (void)scheduleSecurityChecks {

// 定时执行安全检查

dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));

dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);

dispatch_source_set_event_handler(timer, ^{

if (!self isEnvironmentSafe) {

self handleUnsafeEnvironment;

}

if (ProxyDetectionManager isProxyEnabled) {

self handleProxyDetected;

}

});

dispatch_resume(timer);

}

  • (void)handleUnsafeEnvironment {

// 清理敏感数据

self clearSensitiveData;

// 上报安全事件

self reportSecurityEvent:@"unsafe_environment";

// 混淆行为或优雅退出

dispatch_async(dispatch_get_main_queue(), ^{

UIAlertController *alert = [UIAlertController

alertControllerWithTitle:@"安全警告"

message:@"检测到不安全环境,应用即将退出"

preferredStyle:UIAlertControllerStyleAlert];

\[UIApplication sharedApplication.keyWindow.rootViewController

presentViewController:alert animated:YES completion:^{

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),

dispatch_get_main_queue(), ^{

exit(0);

});

}];

});

}

@end

六、使用建议

  1. 分层防护:不要依赖单一防护措施

  2. 动态更新:定期更新加密算法和密钥

  3. 服务端配合:与服务端协同实现完整防护

  4. 性能平衡:在安全和性能间取得平衡

  5. 持续更新:跟踪最新的逆向技术并更新防护

七、注意事项

  1. 审核风险:部分技术可能违反App Store审核条款

  2. 用户体验:避免过度防护影响正常使用

  3. 维护成本:安全方案需要持续维护和更新

  4. 法律合规:确保符合相关法律法规

相关推荐
DaLi Yao4 小时前
【无标题】
人工智能·安全
Alsn865 小时前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker
网络研究院5 小时前
2026年网络安全
网络·安全·法律·法规·趋势·发展
treesforest5 小时前
AI安全系统如何识别异常访问?IP风险识别正在成为关键能力
网络·人工智能·tcp/ip·安全·web安全
零零信安6 小时前
零零信安荣登数世咨询《新质·数字安全专精百强(2026)》暗网情报领域,彰显专业实力与创新引领
安全·网络安全·数据泄露·暗网·零零信安
开发小能手-roy6 小时前
StringBuilder vs StringBuffer:2024年还需要线程安全字符串吗?
开发语言·python·安全
_阿伟_7 小时前
JWT介绍
安全
初级代码游戏9 小时前
easy Photo Clean公测版:快速清理iPhone照片 邀请公测
ios·iphone
zhengfei6119 小时前
小白级手册——全面剖析红队信息收集思考
网络·安全·web安全
库奇噜啦呼9 小时前
【iOS】RunLoop学习
学习·ios