美文网首页
iOS逆向1025-安全终章

iOS逆向1025-安全终章

作者: lukyy | 来源:发表于2018-06-29 11:52 被阅读116次

    001--代码混淆

    代码混淆的作用:防止别人通过类名、方法名猜出其功能。
    一般去混淆关键的信息功能!不能全工程代码混淆,效率会严重降低!

    创建 PrefixHeader_pch 文件,用宏代替: 方法名、类名

    //------------------------ PrefixHeader_pch ----------------
    //  PrefixHeader.pch
    //  001--UserInfoDemo
    #ifndef PrefixHeader_pch
    #define PrefixHeader_pch
    
    #define UserInfoClass       CHDKSALI458
    #define isVipWithAccount    KDKSLQWIP45
    
    #endif /* PrefixHeader_pch */
    
    
    //------------------------ ViewController ----------------
    #import "ViewController.h"
    #import "UserInfo.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    }
    //测试
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        if ([[[UserInfoClass alloc] init] isVipWithAccount:@"hank123"]) {
            NSLog(@"是VIP");
        }else{
            NSLog(@"不是VIP");
        }
    }
    @end
    
    
    //------------------------ UserInfo --> UserInfoClass ----------
    #import <Foundation/Foundation.h>
    
    @interface UserInfoClass : NSObject
    
    -(BOOL)isVipWithAccount:(NSString *)account;
    
    @end
    
    
    
    #import "UserInfo.h"
    
    @implementation UserInfoClass
    
    -(BOOL)isVipWithAccount:(NSString *)account{
        
        if ([account isEqualToString:@"hank"]) {
            return YES;
        }
        return NO;
    }
    
    @end
    
    

    查看MacO文件,方法名和类名 已经替换

    image.png

    002--字符串加密

    //NSString * const AES_KEY = @"IUKDSIEKD#";
    //NSString * const AES_KEY = @"IUIDISTP#";
    //👆对上面字符串的防护

    • //2.1、一次防护:包装成数组


    虽然现在很难找到可以,但是查看MacO文件,找到后:字符串还是能看到!

    image.png
    • //2.2、二次防护:包装成数组:采用^(异或)运算直接换算成结果.不会进入字符串常量区(理解为:字符串加密)
    #define STRING_ENCRYPT_KEY 0xAC
    static NSString * AES_KEY(){
        unsigned char key[] = {
            (STRING_ENCRYPT_KEY ^ 'I'),
            (STRING_ENCRYPT_KEY ^ 'U'),
            (STRING_ENCRYPT_KEY ^ 'I'),
            (STRING_ENCRYPT_KEY ^ 'D'),
            (STRING_ENCRYPT_KEY ^ 'I'),
            (STRING_ENCRYPT_KEY ^ 'S'),
            (STRING_ENCRYPT_KEY ^ 'T'),
            (STRING_ENCRYPT_KEY ^ 'P'),
            (STRING_ENCRYPT_KEY ^ '#'),
            (STRING_ENCRYPT_KEY ^ '\0')
        };
        unsigned char * p = key;
        while (((*p) ^=  STRING_ENCRYPT_KEY) != '\0') p++;
        
       return [NSString stringWithUTF8String:(const char *)key];
    }
    
    

    查看MacO文件,很难找到字符串,即使找到key,也看不到明文原字符串!

    image.png

    003--隐藏CCCrypt

    符号断点防不住
    image.list
    libcommonCrypto,dylib
    //到动态库 找CCCrypt_p这个函数
    dlsym(handle, "CCCrypt");

    - (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
        
        // 设置秘钥
        NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
        uint8_t cKey[self.keySize];
        bzero(cKey, sizeof(cKey));
        [keyData getBytes:cKey length:self.keySize];
        
        // 设置iv
        uint8_t cIv[self.blockSize];
        bzero(cIv, self.blockSize);
        int option = 0;
        if (iv) {
            [iv getBytes:cIv length:self.blockSize];
            option = kCCOptionPKCS7Padding;
        } else {
            option = kCCOptionPKCS7Padding | kCCOptionECBMode;
        }
        
        // 设置输出缓冲区
        NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
        size_t bufferSize = [data length] + self.blockSize;
        void *buffer = malloc(bufferSize);
        
        // 开始加密
        size_t encryptedSize = 0;
        //加密解密都是它 -- CCCrypt
        //隐藏CCCrypt函数
        unsigned char str[] = {
            ('a' ^ 'C'),
            ('a' ^ 'C'),
            ('a' ^ 'C'),
            ('a' ^ 'r'),
            ('a' ^ 'y'),
            ('a' ^ 'p'),
            ('a' ^ 't'),
            ('a' ^ '\0')
        };
        unsigned char * p = str;
        while (((*p) ^= 'a') != '\0') p++;
        
        //通过句柄 拿到动态库 
        void * handle = dlopen("/usr/lib/system/libcommonCrypto.dylib",RTLD_LAZY);
    //    //到动态库 找CCCrypt_p这个函数
    //    dlsym(handle, "CCCrypt");
        
        CCCryptorStatus (* CCCrypt_p)(
                                CCOperation op,         /* kCCEncrypt, etc. */
                                CCAlgorithm alg,        /* kCCAlgorithmAES128, etc. */
                                CCOptions options,      /* kCCOptionPKCS7Padding, etc. */
                                const void *key,
                                size_t keyLength,
                                const void *iv,         /* optional initialization vector */
                                const void *dataIn,     /* optional per op and alg */
                                size_t dataInLength,
                                void *dataOut,          /* data RETURNED here */
                                size_t dataOutAvailable,
                                size_t *dataOutMoved)
        __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)  = dlsym(handle, (const char *)str);
        //拿到函数指针才去调用
        if (!CCCrypt_p) {
            return nil;
        }
        
        CCCryptorStatus cryptStatus = CCCrypt_p(kCCEncrypt,
                                              self.algorithm,
                                              option,
                                              cKey,
                                              self.keySize,
                                              cIv,
                                              [data bytes],
                                              [data length],
                                              buffer,
                                              bufferSize,
                                              &encryptedSize);
        
        NSData *result = nil;
        if (cryptStatus == kCCSuccess) {
            result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
        } else {    
            free(buffer);
            NSLog(@"[错误] 加密失败|状态编码: %d", cryptStatus);
        }
        
        return [result base64EncodedStringWithOptions:0];
    } 
    
    

    004--使用汇编进行系统调用

    • 上节回顾
    #import "antiDebugCode.h"
    #import "MyPtraceHeader.h"
    
    @implementation antiDebugCode
    
    +(void)load {
        //运行就奔溃:但是防不住断点调试,能找到奔溃原因
        ptrace(PT_DENY_ATTACH, 0, 0, 0);
    }
    
    @end
    
    4.1、跳过断点调试
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 支付宝 exit!
        // 架构的判断  DYLD 源码!!
        // 我更本就不调用你的ptrace!! exit!! 无法用ptrace断点 找到原因,因为根本不会进入断点
        
        //直接上汇编代码!! 通过中断 触发
    //    asm(
    //        "mov X0,#31\n"//31  PT_DENY_ATTACH
    //        "mov X1,#0\n"
    //        "mov X2,#0\n"
    //        "mov X3,#0\n"
    //        "mov w16,#26\n"//这个26代表着ptrace
    //        "svc #0x80"//触发中断
    //    );    
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        
        //点击屏幕就退出
        asm(
            "mov X0,#0\n"
            "mov w16,#1\n"  //这个26代表着ptrace,  #define SYS_exit 1
            "svc #0x80"
        );
        
    }
    
    
    4.2、点击屏幕不会进入断点
    image.png

    005--重签名防护

    课程回顾
    // 会用到的终端命令
    cd /Users/zhangmeng/Library/MobileDevice/Provisioning\ Profiles // 目录到 此文件夹:存放一些描述文件 ls // 查看此文件夹
    open . // 打开此文件夹 //查看 描述文件信息: 内容是签名加密的一个xml,苹果设备要信任此app security cms -D -i + 描述文件路径(齿轮配置文件, mobileprovision)
    security cms -D -i embedded.mobileprovision //这个已经cd到当前目录 //查看 APP的签名信息 codesign -vv -d +APP路径
    $ codesign -vv -d WeChat.app

    $ security cms -D -i + 描述文件路径(齿轮配置文件, mobileprovision)//查看一个对应app的 描述文件信息:

    查看描述文件信息g

    //找到 签名字符: 5KN6964MFR

    判断是否被重签名了,是就直接退出程序
    #import "NSObject+Codesign.h"
    
    @implementation NSObject (Codesign)
    
    
    void  checkCodesign(NSString *id){
        // 描述文件路径
        NSString *embeddedPath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];
    //    NSLog(@"Path:%@",embeddedPath);
        // 读取application-identifier  注意描述文件的编码要使用:NSASCIIStringEncoding
        NSString *embeddedProvisioning = [NSString stringWithContentsOfFile:embeddedPath encoding:NSASCIIStringEncoding error:nil];
        NSArray *embeddedProvisioningLines = [embeddedProvisioning componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
        
        for (int i = 0; i < embeddedProvisioningLines.count; i++) {
            if ([embeddedProvisioningLines[i] rangeOfString:@"application-identifier"].location != NSNotFound) {
                
                NSInteger fromPosition = [embeddedProvisioningLines[i+1] rangeOfString:@"<string>"].location+8;
                
                NSInteger toPosition = [embeddedProvisioningLines[i+1] rangeOfString:@"</string>"].location;
                
                NSRange range;
                range.location = fromPosition;
                range.length = toPosition - fromPosition;
                
                NSString *fullIdentifier = [embeddedProvisioningLines[i+1] substringWithRange:range];
                // NSLog(@"%@", fullIdentifier);
                NSArray *identifierComponents = [fullIdentifier componentsSeparatedByString:@"."];
                NSString *appIdentifier = [identifierComponents firstObject];
                // NSLog(@"%@", appIdentifier);
                // 对比签名ID
                if ([appIdentifier isEqual:id]) {
                    NSUserDefaults *defaults  = [NSUserDefaults standardUserDefaults];
                    [defaults setObject:appIdentifier forKey:@"key"];
                    [defaults synchronize];
                }else{
                    //exit
                    asm(
                        "mov X0,#0\n"
                        "mov w16,#1\n"
                        "svc #0x80"
                        );
                }
                break;
            }
        }
    }
    @end
    
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        checkCodesign(@"5KN6964MFR");
        
    }
    
    

    /*以上防护的破解方案:
    对于反重签名防护,hook checkCodesign函数
    /

    总结:防护的一些方法

    1、重签名防护
    2、ptrace防护(用汇编)
    3、反hook防护(动态库提前调用)
    4、混淆关键代码
    5、防护class dump

    001--代码混淆

    代码混淆的作用:防止别人通过类名、方法名猜出其功能。
    一般去混淆关键的信息功能!不能全工程代码混淆,效率会严重降低!
    创建 PrefixHeader_pch 文件,用宏代替: 方法名、类名

    002--字符串加密

    字符串包装成数组:采用^(异或)运算直接换算成结果.不会进入字符串常量区(理解为:字符串加密

    003--隐藏CCCrypt
    004--使用汇编进行系统调用
    005--重签名防护

    相关文章

      网友评论

          本文标题:iOS逆向1025-安全终章

          本文链接:https://www.haomeiwen.com/subject/nuxayftx.html