摘要:return dicHash。我們對Plist文件以及App 的icon資源文件做hash值校驗。

爲什麼要應用完整性校驗

大家可能聽過馬甲包類似的概念。如果惡意攻擊者搞你的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資源文件這些東西。

關鍵性代碼:

//生成資源文件名及對應的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包重簽名

如果感覺這篇文章不錯可以點擊在看:point_down:

相關文章