對於iOS來說,由於系統是封閉的,APP上架需要通過App Store,安全性來說相當高。但是對於大廠和知名APP而言,別人給的安全保障永遠沒有自己做的來得踏實。所以對於大廠、少部分企業級和金融支付類應用來說加固是相當重要的。
下面是目前幾個專業加固大廠提供的加固策略
2.第二板斧是防動態調試、反調試和通信安全(數據加密);
本文將針對以上幾點進行實現,對於一些不太容易實現的將會做方向性討論
對字符串加密的方式目前我所了解到掌握到的最可靠方式就是用腳本將代碼中的所有標記需要加密的字符串進行異或轉換,這樣代碼中就不存在明文字符串了。當然第三方的字符串加密不可能這麼簡單,具體怎麼做的我也不太清楚。不過為了增加字符串加密的難度複雜性,我們可以先將字符串用加密工具轉換(例如AES、base64等)後的把加字符串放在工程中,並且把解密的鑰匙放在工程中,用異或轉換,把解密鑰匙和加密後的字符串轉換,這樣就有2層保障,增加了複雜度。
/* 加密NSString字符串 */ NSString *str = @&34;; NSLog(@&34;,str); /* 加密char*字符串 */ char* cStr = &34;; NSLog(@&34;,cStr);
你會發現,你的字符串內容暴露在了彙編模式中,這會導致別人在逆向分析你的工程時能看見你的字符串內容,我們一般接口、域名、加解密鑰匙串、AppKey、AppId等比較重要的東西會放在客戶端用作字符串,這就很容易暴露出來。
/* 字符串混淆解密函數,將char[] 形式字符數組和 aa異或運算揭秘 */extern char* decryptConfusionCS(char* string){ char* origin_string = string; while(*string) { *string ^= 0xAA; string++; } return origin_string;}/* 解密函數,返回的是NSString類型的 */extern NSString* decryptConstString(char* string){ /* 先執行decryptConfusionString函數解密字符串 */ char* str = decryptConfusionCS(string); /* 獲取字符串的長度 */ unsigned long len = strlen(str); NSUInteger length = [[NSString stringWithFormat:@&34;,len] integerValue]; NSString *resultString = [[NSString alloc]initWithBytes:str length:length encoding:NSUTF8StringEncoding]; return resultString;}/* * 使用heyujia_confusion宏控制加密解密 * 當heyujia_confusion宏被定義的時候,執行加密腳本,對字符串進行加密 * 當heyujia_confusion宏被刪除或為定義時,執行解密腳本,對字符串解密 */ifdef heyujia_confusion/* heyujia_confusion 宏被定義,那麼就進行執行解密腳本 *//* confusion_NSSTRING宏的返回結果是NSString 類型的 */define confusion_CSTRING(string) decryptConfusionCS(string)define confusion_NSSTRING(string) @string/* 加密char *類型的 */endif@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. /* 使用confusion_NSSTRING宏包含需要加密的NSString字符串 */ NSString *str = confusion_NSSTRING(&34;); NSLog(@&34;,str); /* 使用confusion_NSSTRING宏包含需要加密的char*字符串 */ char* cStr = confusion_CSTRING(&34;); NSLog(@&34;,cStr); }
encoding=utf8 author by heyujia 替換所有字符串常量為加密的char數組,形式((char[]){1, 2, 3, 0})import importlibimport osimport reimport sys 當然可以不使用0xAA 使用其他的十六進位也行 例如0XBB、0X22、0X11def replace(match): string = match.group(2) + &39; replaced_string = &39; + &39;.join([&34; % ((ord(c) ^ 0xAA) if c != &39; else 0) for c in list(string)]) + &39; return match.group(1) + replaced_string + match.group(3) 使用replace函數對字符串進行異或轉換def obfuscate(file): with open(file, &39;) as f: code = f.read() f.close() code = re.sub(r&34;(.*?)&39;, replace, code) code = re.sub(r&define ggh_confusion&39;39;, code) with open(file, &39;) as f: f.write(code) f.close() 對每個文件執行obfuscate函數def openSrcFile(path): print(&34;+ path) case 1: print((&34; + parent).encode(&39;)) 34; dirname is:&39;utf-8&case 2 for filename in filenames: extendedName = os.path.splitext(os.path.join(parent,filename)) if (extendedName[1] == &39; or extendedName[1] == &39;): print(&34;+ os.path.join(parent,filename)) obfuscate(os.path.join(parent,filename))39;../daimahunxiao&39;__main__&34;本腳本用於對原始碼中被標記的字符串進行加密&34;請輸入正確的原始碼路徑&!/usr/bin/env python -*- coding: utf-8 -*- 解密腳本34;& 替換((char[]){1, 2, 3, 0})的形式為字符串,同時讓每個數組值與0xAA異或進行解密def replace(match): string = match.group(2) decodeConfusion_string = &34; for numberStr in list(string.split(&39;)): if int(numberStr) != 0: decodeConfusion_string = decodeConfusion_string + &34; % (int(numberStr) ^ 0xAA) replaced_string = &34;&39;\&39; print(&34; + replaced_string) return match.group(1) + replaced_string + match.group(3)39;r&39;(confusion_NSSTRING\(|confusion_CSTRING\()\(\(char \[\]\) \{(.*?)\}\)(\))&39;[/]*39;, &define ggh_confusion&39;w&讀取源碼路徑下的所有.h和.m 文件def openSrcFile(path): print(&34;+ path) case 1: print((&34; + parent).encode(&39;)) 34; dirname is:&39;utf-8&case 2 for filename in filenames: extendedName = os.path.splitext(os.path.join(parent,filename)) 39;.h&39;.m&34;已解密文件:&源碼路徑srcPath = &39;if __name__ == &39;: print(&34;) if len(srcPath) > 0: openSrcFile(srcPath) else: print(&34;) sys.exit()
encoding=utf8!/bin/sh 代碼混淆腳本 heyujia 2018.03.15識別含有多字節編碼字符時遇到的解析衝突問題export LC_CTYPE=Cexport LANG=C項目路徑,會混淆該路徑下的文件ProjectPath=&34;34;_&34;/Users/xieyujia/Desktop/ios/學習項目/tihuan&34;_&第一個參數為項目路徑if [[ $1 ]]thenif [[ $1 != &34; ]]; thenProjectPath=$1fifi34;_&查找文本中所有要求混淆的屬性\方法\類,只會替換文本中ob_開頭和_fus結尾的字符串(區分大小寫,例如oB_就不會做混淆),如果注釋內容有該類型的字符串,也會進行替換。對於使用 _下劃線訪問的變量屬性,不會有影響,一樣會替換成對應_的混淆內容。resultfiles=`grep &39; -rl $ProjectPath`34;項目沒有需要混淆的代碼&34;開始混淆代碼...&39;BEGIN{srand();k=0;}隨機字符串生成函數function random_string(len) {result=&34;k;alpbetnum=split(&34;, alpbet, &34;);for (i=0; i<len; i++) {result = result&34;alpbet[ random_int(1, alpbetnum) ];}return result;}/ob_[A-Za-z0-9_]*_fus/{x = $0;34;ob_[A-Za-z0-9_]*_fus&判斷是否有之前已經找過的重複字符串for ( i = 0; i < k; i++ ){if (strarr[i] == tempstr){break;}}if(i<k){不是重複字符串,添加到替換數組strarr[k++]=tempstr;}randomstr=random_string(20);printf(&34;, tempstr,randomstr);39; $resultfiles )34;|&34;:&34;原項:&34;:&34;加密項:&替換文件夾中所有文件的內容(支持正則)39;&34;s/${record1}/${record2}/g&34;第&34;項混淆代碼處理完畢&34;recordnum = $recordnum + 1&查找需要混淆的文件名並替換filerecordnum=1while [[ 1 == 1 ]]; dofilerecord=`echo $x|cut -d &34; -f$filerecordnum`if [[ -z $filerecord ]]thenbreakfifilerecord1=`echo $filerecord|cut -d &34; -f1`34;原項:&34;:&echo &34;$filerecord234;*&39;BEGIN{frecord1=&39;&34;&34;;frecord2=&39;&34;&34;;finish=1}{filestr=$0;gsub(frecord1,frecord2,filestr);print &34; $0 &34; filestr&34;finish&34;;finish++;}&34;filerecordnum = $filerecordnum + 1&!/bin/sh 代碼還原腳本 RyoHo 2018.03.15識別含有多字節編碼字符時遇到的解析衝突問題export LC_CTYPE=Cexport LANG=C已經混淆的項目路徑ProjectPath=&34;34;/Users/xieyujia/Desktop/ios/學習項目/tihuan20180315_1456&第一個參數為項目路徑if [[ $1 ]]thenif [[ $1 != &34; ]]; thenProjectPath=$1fifi34;_&內容還原x=`cat $SecretFile`recordnum=1while [[ 1 == 1 ]]; dorecord=`echo $x|cut -d &34; -f$recordnum`if [[ -z $record ]]thenbreakfirecord1=`echo $record|cut -d &34; -f1`echo &34;$record1record2=`echo $record|cut -d &34; -f2`echo &34;$record234;指定的密鑰文件不能還原&替換文件夾中所有文件的內容(支持正則)39;&34;s/${record2}/${record1}/g&34;第&34;項混淆代碼還原完畢&34;recordnum = $recordnum + 1&文件還原filerecordnum=1while [[ 1 == 1 ]]; dofilerecord=`echo $x|cut -d &34; -f$filerecordnum`if [[ -z $filerecord ]]thenbreakfifilerecord1=`echo $filerecord|cut -d &34; -f1`34;原項:&34;:&echo &34;$filerecord234;*&39;BEGIN{frecord1=&39;&34;&34;;frecord2=&39;&34;&34;;finish=1;}{filestr=$0;gsub(frecord2,frecord1,filestr);print &34; $0 &34;filestr &34;finish&34;finish++;}&34;filerecordnum = $filerecordnum + 1"done
應大家需要把腳本源碼:https://github.com/xkftkffz/DMHXDemo 地址 放出來
建議大家看看腳本內容,有利於學習理解。該腳本是有針對性的混淆內容,可以自己修改腳本中的正則表達式來確定混淆的內容。腳本中只會替換文本中ob_開頭和_fus結尾的字符串(區分大小寫,例如oB_就不會做混淆),如果注釋內容有該類型的字符串,也會進行替換。對於使用 _下劃線訪問的變量屬性,不會有影響,一樣會替換成對應_的混淆內容。