iOS开发安全 - 防重签名、越狱、调试检测

文章目录

一、判断Mach-O文件否被篡改

二次签名会篡改信息文件

复制代码
public static func isSecondIPA() -> Bool {
        let bundle = Bundle.main
        let info = bundle.infoDictionary
        if info?["SignerIdentity"] != nil {
            return true
        }
        return false
    }

二、重签名检测

检测包签名是否和已知自己签名一致

复制代码
public static func checkCodeSign(_ provisionID: String) -> Bool {
        // 描述文件路径
        let embededPath = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision")
        guard let embededPath = embededPath,
              FileManager.default.fileExists(atPath: embededPath) == true
        else {
            return true
        }
        // 读取application-identifier
        guard let embeddedProvisioning = try? String.init(contentsOfFile: embededPath, encoding: .ascii) else {
            return true
        }
        let embeddedProvisioningLines = embeddedProvisioning.components(separatedBy: CharacterSet.newlines)
        for i in 0..<embeddedProvisioningLines.count {
            let emStr = embeddedProvisioningLines[i]
            guard let index = emStr.range(of: "application-identifier")?.lowerBound,
                  index.hashValue != NSNotFound
            else {
                continue
            }
            let positionStr = embeddedProvisioningLines[i + 1]
            let fromPosition = positionStr.range(of: "<string>")?.upperBound ?? positionStr.startIndex
            let toPosition = positionStr.range(of: "</string>")?.lowerBound ?? positionStr.endIndex
            
            let range = Range(uncheckedBounds: (fromPosition, toPosition))
            
            let fullIdentifier = positionStr[range]
            let identifierComponents = fullIdentifier.components(separatedBy: ".")
            let appIdentifier = identifierComponents.first
            // 对比签名ID
            if appIdentifier == provisionID {
                return false
            } else {
                return true
            }
            
        }
        return false
    }

三、是否越狱

复制代码
public static func isJailbreak() -> Bool {
        guard TARGET_OS_SIMULATOR == 0 else {
            return false
        }
        // 越狱检查
        // CanOpenURL检查
        let fakeURL = URL(string: "cydia://package/com.fake.package")
        if UIApplication.shared.canOpenURL(fakeURL!) == true {
            return true
        }
        
        // Cydia应用检查
        var stat_info: stat
        // 使用stat系列函数检测Cydia等工具
        if stat("/Applications/Cydia.app", &stat_info) == 0 {
            return true
        }
        
        // fork函数检查
//        if fork()>=0 {
//            return true
//        }
        
        // 注入动态库检查
        if let env = getenv("DYLD_INSERT_LIBRARIES") {
            return true
        }
        
        // 无法访问文件检查
        let files = ["/Applications/Cydia.app",
                     "/Applications/limera1n.app",
                     "/Applications/greenpois0n.app",
                     "/Applications/blackra1n.app",
                     "/Applications/blacksn0w.app",
                     "/Applications/redsn0w.app",
                     "/Applications/Absinthe.app",
                     "/Library/MobileSubstrate/MobileSubstrate.dylib",
                     "/bin/bash",
                     "/usr/sbin/sshd",
                     "/etc/apt",
                     "/private/var/lib/apt/"]
        for fileName in files {
            if FileManager.default.fileExists(atPath: fileName) {
                return true
            }
        }
        return false
    }

四、防止抓包

发起请求之前判断是否存在代理,存在代理就直接返回,请求失败

复制代码
+ (BOOL)getProxyStatus {
    NSDictionary *proxySettings =  (__bridge NSDictionary *)(CFNetworkCopySystemProxySettings());
    NSArray *proxies = (__bridge NSArray *)(CFNetworkCopyProxiesForURL((__bridge CFURLRef _Nonnull)([NSURL URLWithString:@"http://www.baidu.com"]), (__bridge CFDictionaryRef _Nonnull)(proxySettings)));
    NSDictionary *settings = [proxies objectAtIndex:0];
    
    NSLog(@"host=%@", [settings objectForKey:(NSString *)kCFProxyHostNameKey]);
    NSLog(@"port=%@", [settings objectForKey:(NSString *)kCFProxyPortNumberKey]);
    NSLog(@"type=%@", [settings objectForKey:(NSString *)kCFProxyTypeKey]);
    
    if ([[settings objectForKey:(NSString *)kCFProxyTypeKey] isEqualToString:@"kCFProxyTypeNone"]){
        //没有设置代理
        return NO;
    }else{
        //设置代理了
        return YES;
    }
}

五、防调试

复制代码
+ (void)antiDebug {
    
    gx_disable_gdb();

    gx_AntiDebugASM();

    gx_AntiDebug_isatty();
    
}

/// ptrace反调试,阻止GDB依附
typedef int (*ptrace_ptr_t)(int _request, pid_t pid, caddr_t _addr, int _data);
#if !defined(PT_DENT_ATTACH)
#define PT_DENT_ATTACH 31
#endif
void gx_disable_gdb() {
    void * handle = dlopen(0, RTLD_GLOBAL|RTLD_NOW);
    ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
    ptrace_ptr(PT_DENT_ATTACH, 0, 0, 0);
    dlclose(handle);
}


/// 内联 svc + ptrace 实现和内联 svc + syscall + ptrace 实现
// 使用inline方式将函数在调用处强制展开,防止被hook和追踪符号
__attribute__((always_inline)) void gx_AntiDebugASM() {
#ifdef __arm__
    asm volatile(
                 "mov r0,#31\n"
                 "mov r1,#0\n"
                 "mov r2,#0\n"
                 "mov r12,#26\n"
                 "svc #80\n"
                 );
#endif
#ifdef __arm64__
    asm volatile(
                 "mov x0,#26\n"
                 "mov x1,#31\n"
                 "mov x2,#0\n"
                 "mov x3,#0\n"
                 "mov x16,#0\n"
                 "svc #128\n"
                 );
#endif
}

/// isatty检测是否正在被调试
//需要头文件#include <unistd.h>
void gx_AntiDebug_isatty() {
    if (isatty(1)) {
        _exit(1);
    } else {
    }
}
相关推荐
我是谁的程序员11 小时前
Mac 上生成 AppStoreInfo.plist 文件,App Store 上架
后端·ios
sweet丶11 小时前
微信Matrix 卡顿监控原理梳理与图解
ios
上海云盾-小余12 小时前
网站恶意爬虫拦截策略:智能识别与封禁实操方案
网络·爬虫·安全·web安全
2301_7807896613 小时前
手游遇到攻击为什么要用SDK游戏盾手游遇到攻击为什么要用 SDK 游戏盾?
安全·web安全·游戏·架构·kubernetes·ddos
黎阳之光14 小时前
黎阳之光:视频孪生重构新能源智慧工地,打造大型风光基地数智化建设标杆
大数据·人工智能·物联网·安全·数字孪生
2501_9160074714 小时前
iOS开发中抓取HTTPS请求的完整解决方法与步骤详解
android·网络协议·ios·小程序·https·uni-app·iphone
Agent手记14 小时前
安全生产巡检全流程自动化与隐患预警方案:2026工业Agent落地实战指南
数据库·人工智能·安全·ai·自动化
效能革命笔记15 小时前
Gitee DevSecOps 智能版本管理:军工软件工厂的依赖治理与供应链安全方案
网络·安全·gitee
未若君雅裁15 小时前
Spring Bean 作用域、线程安全与生命周期
java·安全·spring
企服AI产品测评局16 小时前
实测2026安全培训管理新范式:如何以“视觉大模型”破解AI内容生成与跨系统自动化难题?
人工智能·安全·ai·chatgpt·自动化