美文网首页
IOS 验证App完整性探究

IOS 验证App完整性探究

作者: Devil_Chen | 来源:发表于2020-05-26 17:34 被阅读0次

    时间紧迫,直接开始

    首先查看Mach-O文件,看能否找到能判断的信息。

    • 看到有个UUID字段,验证一下是否能拿来判断。


      image.png
    /**
     获取指令中的uuid
    
     @return uuid
     */
    NSString *executableUUID()
    {
    
        const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1);
        for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) {
            if (((const struct load_command *)command)->cmd == LC_UUID) {
                command += sizeof(struct load_command);
                return [NSString stringWithFormat:@"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
                        command[0], command[1], command[2], command[3],
                        command[4], command[5],
                        command[6], command[7],
                        command[8], command[9],
                        command[10], command[11], command[12], command[13], command[14], command[15]];
            } else {
                command += ((const struct load_command *)command)->cmdsize;
            }
        }
        return nil;
    }
    

    结论:由于验证时忘了截图,就不贴验证过程了,直接写结论吧。LC_UUID会在每次修改代码重新编译运行时,LC_UUID的值都会改变,但是直接对app进行重签名和篡改之后,发现是不会改变LC_UUID的值。

    • 另外有个猜想但没验证,可以利用Load Commands中的代码签名数据偏移找到代码签名数据的地址,但是这签名数据的结构比较复杂,有兴趣的可以研究一下。
    image.png
    image.png

    直接从Mach-O文件着手,验证Mach-O文件。

    • 研究如何能在运行时获取Mach-O文件
    /**
     App Mach-O文件路径
     
     @return Mach-O文件路径
     */
    -(NSString *) machOPath {
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        
        NSString *excutableName = [[NSBundle mainBundle] infoDictionary][@"CFBundleExecutable"];
        
        NSString *tmpPath = [documentsDirectory stringByDeletingLastPathComponent];
        NSString *appPath = [[tmpPath stringByAppendingPathComponent:excutableName]
                             stringByAppendingPathExtension:@"app"];
        NSString *machOPath = [appPath stringByAppendingPathComponent:excutableName];
        
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
            NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
            machOPath = [bundlePath stringByAppendingPathComponent:excutableName];
        }
        return machOPath;
    }
    
    • 用SHA256执行摘要
    /**
     数据SHA256
    
     @param keyData 需要hash的数据
     @return hash后的数据
     */
    + (NSString *)SHA256:(NSData *)keyData {
        //    const char *s = [self cStringUsingEncoding:NSASCIIStringEncoding];
        //    NSData *keyData = [NSData dataWithBytes:s length:strlen(s)];
        
        uint8_t digest[CC_SHA256_DIGEST_LENGTH] = {0};
        CC_SHA256(keyData.bytes, (CC_LONG)keyData.length, digest);
        NSData *out = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
        NSString *hash = [out description];
        hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""];
        hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""];
        hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""];
        return hash;
    }
    
    /**
     * MachO使用SHA256执行摘要
     */
    -(void) sha256MachO
    {
        //加密
        NSString *encryptResult = [ViewController SHA256:[NSData dataWithContentsOfFile:[ViewController binaryPath]]];
        if (encryptResult) {
            NSLog(@"\nSHA256 成功-->%@",encryptResult);
        }else{
            NSLog(@"\nSHA256 失败");
        }
    }
    
    • 验证修改代码SHA256的值是否改变(修改输出语句)


      修改输出语句前
      修改输出语句后
      重新修改输出语句为开始的语句

    结论:修改代码摘要会改变,即使重新写回原来的代码,也无法变回原来的SHA256的值。

    • 重点来了,验证重签名和篡改后SHA256的值。
    未重签名前: image.png
    重签名之后: image.png

    结论:重签名和篡改后SHA256的值会改变。

    最终结论:可以对Mach-O执行hash运算或者签名验签等等操作来验证App是否完整。

    PS:此次研究没有考虑手机越狱的情况,越狱的话可以直接使用Tweak以动态库插入,可能SHA256的值就不会改变,因为Mach-O数据没有改变,不过这只是猜想,并没有验证。

    相关文章

      网友评论

          本文标题:IOS 验证App完整性探究

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