美文网首页
iOS 应用完整性校验

iOS 应用完整性校验

作者: Phant | 来源:发表于2022-07-19 17:28 被阅读0次

    目录

    -为什么要做完整性校验?
    -检测文件是否被篡改的三种方法?
    -测试是否添加成功?(iOS重签名)

    为什么要做完整性校验?

    检测应用是否被篡改。
    恶意攻击者可以在越狱的环境下任意修改文件程序,修改后客户端仍可以正常运行。当设备越狱后,恶意攻击者就可以通过修改客户端文件,在客户端中插入恶意脚本,窃取用户信息。甚至能改变app的执行逻辑,比如修改方法的返回值来绕过指纹、手势密码的验证等。
    

    检测文件是否被篡改的三种方法?

    方式一:越狱检测

    检测当前设备是否越狱
    在关键性业务判断给出提示强制退出以免造成安全问题,这里的关键性业务可能是需要自己定义范围,比如牵扯到用户敏感信息等业务。
    检测是否越狱-代码:

    const char* jailbreak_tool_pathes[] = {
           "/Applications/Cydia.app",
           "/Library/MobileSubstrate/MobileSubstrate.dylib",
           "/bin/bash",
           "/usr/sbin/sshd",
           "/etc/apt"
    };
    #define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
    + (BOOL)isJailBroken
    {
        if ([self isSimulator] == YES)
        {
            return NO;
        }
        
        for (int i=0; i<ARRAY_SIZE(jailbreak_tool_pathes); i++) {
           if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithUTF8String:jailbreak_tool_pathes[i]]]) {
               NSLog(@"The device is jail broken!");
               return YES;
            }
        }
          NSLog(@"The device is NOT jail broken!");
          return NO;
    }
    
    + (BOOL)isSimulator {
    #if TARGET_OS_SIMULATOR
        return YES;
    #else
        return NO;
    #endif
    }
    

    应用强制退出方法-代码:

    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
    UIWindow *window = app.window;
    [UIView animateWithDuration:1.0f animations:^{
          window.alpha = 0;
       } completion:^(BOOL finished) {
            exit(0);
     }];
    

    该方法只是检测设备是否进行了越狱,并不能检测应用的完整性。

    方式二:判断Mach-O文件否被篡改

    通过检测SignerIdentity判断是Mach-O文件否被篡改。
    原理是:SignerIdentity的值在info.plist中是不存在的,开发者不会加上去,苹果也不会,只是当ipa包被反编译后篡改文件再次打包,需要伪造SignerIdentity。所以只要被攻击篡改东西如果重新运行到手机上就会出现这个东西。

    + (BOOL)checkMach_O
    {
        NSBundle *bundle = [NSBundle mainBundle];
        NSDictionary *info = [bundle infoDictionary];
        if ([info objectForKey: @"SignerIdentity"] != nil){
            //存在这个key,则说明被二次打包了
            return YES;
        }
        return NO;
    }
    

    方式三:重签名检测

    由于要篡改App必然重签名,至于为什么重签名,是因为苹果做了校验改动了任何东西校验失败是直接闪退的,其实原理也是校验文件的hash值。签名打包过程会出现这个embedded.mobileprovision文件,这个文件有teamID的一个东西我们可以校验是否是我们自己的团队的teamID来判断。或者判断BundleID 是否被修改。

    + (BOOL)checkCodeSignWithProvisionID:(NSString *)provisionID
    {
         // 描述文件路径
            NSString *embeddedPath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];
            if ([[NSFileManager defaultManager] fileExistsAtPath:embeddedPath]) {
                
                // 读取application-identifier
                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 objectAtIndex:i] rangeOfString:@"application-identifier"].location != NSNotFound) {
                        
                        NSInteger fromPosition = [[embeddedProvisioningLines objectAtIndex:i+1] rangeOfString:@"<string>"].location+8;
                        
                        NSInteger toPosition = [[embeddedProvisioningLines objectAtIndex:i+1] rangeOfString:@"</string>"].location;
                        
                        NSRange range;
                        range.location = fromPosition;
                        range.length = toPosition - fromPosition;
                        
                        NSString *fullIdentifier = [[embeddedProvisioningLines objectAtIndex:i+1] substringWithRange:range];
                        
        //                NSLog(@"%@", fullIdentifier);
                        
                        NSArray *identifierComponents = [fullIdentifier componentsSeparatedByString:@"."];
                        NSString *appIdentifier = [identifierComponents firstObject];
                        // 对比签名ID
                        if (![appIdentifier isEqual:provisionID])
                        {
                            return NO;
                        }
                        else
                        {
                            return YES;
                        }
                    }
                }
            }
        return YES;
    }
    

    方式四:关键资源hash值检测

    我们对Plist文件以及App 的icon资源文件做hash值校验。网上一些对_CodeSignature的CodeResources以及App二进制文件的校验做法有问题。因为Xcode打包过程不同环境造成的hash值不一样,所以我们必须过滤掉变化的文件。检测Plist文件以及App Icon资源文件这些东西。

    //生成资源文件名及对应的hash的字典
    +(NSDictionary *)getBundleFileHash{
        NSMutableDictionary * dicHash = [NSMutableDictionary dictionary];
        NSArray * fileArr = [self allFilesAtPath:[[NSBundle mainBundle]resourcePath]];
        for (NSString * fileName in fileArr) {
            //对应的文件生成hash
            NSString * HashString = [FileHash md5HashOfFileAtPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName]];
            if (HashString != nil) {
                [dicHash setObject:HashString forKey:fileName];
            }
        }
     //所有资源文件的hash就保存在这数组里
      return dicHash;
    }
    

    有些加密工具为了放进加固SDK放在了本地校验,但是通过服务器校验比较安全点。

    测试是否添加成功?(iOS重签名)

    iOS ipa包重签名

    通过学习很多小伙伴的文章以及不断摸索,完成了应用完整性的校验以及自测(iOS重签名),以此记录调试过程中不明确的地方,不足之处欢迎指出。

    参考文章:
    IOS 验证App完整性探究
    iOS 安全之应用完整性校验的解决方案(转)
    Xcode build 对二进制文件以及_CodeSignature的CodeResources造成变化的原理。
    LLVM怎么做Deterministic Build

    相关文章

      网友评论

          本文标题:iOS 应用完整性校验

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