iOS app完整性校验的解决方案

为什么要应用完整性校验

大家可能听过马甲包类似的概念。如果恶意攻击者搞你的App,直接换个App Icon,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)    {returnNO;    }for(int i=0; i

这种方式其实是非常间接的方式避免了这个话题

方式二:判断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,则说明被二次打包了returnYES;    }returnNO;}复制代码

方式三:重签名检测

由于要篡改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:@""].location+8;                                        NSInteger toPosition = [[embeddedProvisioningLines objectAtIndex:i+1] rangeOfString:@""].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];                                        // 对比签名IDif(![appIdentifier isEqual:provisionID])                    {returnNO;                    }else{returnYES;                    }                }            }        }returnYES;}复制代码

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

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

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

关键性代码:

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

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

总结:

Xcode build 对二进制文件以及_CodeSignature的CodeResources造成变化的原理:LLVM怎么做Deterministic Build

签名的原理:iOS逆向(五)-ipa包重签名

原文链接:https://juejin.cn/post/6844904051092504589

你可能感兴趣的:(iOS app完整性校验的解决方案)