31

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

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzI0MTcwNDcyMw%3D%3D&%3Bmid=2247484294&%3Bidx=1&%3Bsn=684049ed5f7976c088ff1dbda87c07f5
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

为什么要应用完整性校验

大家可能听过马甲包类似的概念。如果恶意攻击者搞你的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)

{

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。所以只要被攻击篡改东西如果重新运行到手机上就会出现这个东西。


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


}


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

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

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

I32eaez.jpg!web

关键性代码:

//生成资源文件名及对应的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包重签名

Fn6j6re.gif如果感觉这篇文章不错可以点击在看:point_down:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK