iOS 安全之应用完整性校验的解决方案

为何要应用完整性校验

你们可能听过马甲包相似的概念。若是恶意攻击者搞你的App,直接换个App Icon,App名字 以及皮肤直接上架了就很尴尬了。数组

怎么作

从安全攻防角度讲,你了解攻击的方式,更容易知道怎么防,可是也是相对而言,只是不断消磨攻击者的意志,希望他们放弃。安全

方式一:越狱检测

这种方式最简单暴力,咱们能够检测当前设备是否越狱,在关键性业务判断给出提示强制退出以避免形成安全问题,这里的关键性业务多是须要本身定义范围,好比牵扯到用户敏感信息等业务。下面贴出关键性代码:bash

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
}
复制代码

这种方式实际上是很是间接的方式避免了这个话题服务器

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

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

+ (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 是否被修改。ssh

+ (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;

}
复制代码

了解签名的原理有利于防止App被重签名。ide

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

咱们对Plist文件以及App 的icon资源文件作hash值校验。网上一些对_CodeSignature的CodeResources以及App二进制文件的校验作法有问题。由于Xcode打包过程不一样环境形成的hash值不同,经过下图能够看出不一样环境打包过程形成的hash值不同的选项。因此咱们必须过滤掉变化的文件。检测Plist文件以及App Icon资源文件这些东西。工具

关键性代码:ui

//生成资源文件名及对应的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放在了本地校验,可是经过服务器校验比较安全点。加密

总结:

经过下面连接了解:

  • Xcode build 对二进制文件以及_CodeSignature的CodeResources形成变化的原理。

LLVM怎么作Deterministic Build

  • 签名的原理

iOS逆向(五)-ipa包重签名

相关文章
相关标签/搜索