iOS字符串硬編碼混淆

前提

眾所周知iOS應(yīng)用在越獄設(shè)備上比較容易被逆向分析泥从,而靜態(tài)字符串的硬編碼比較容易成為逆向者的突破口恍涂。因此有必要做一些字符串硬編碼的混淆右蕊,如加密的對(duì)稱加密key砰奕,md5的key,域名燎含,接口名等宾濒。

混淆前

混淆前代碼

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *string = @"hello world";
    NSLog(@"%@",string);
}

@end

直接在源代碼里面編寫字符串,使用hopper可直接找到該串


混淆方案

這里采用的是直接修改源代碼的方式做混淆屏箍。首先對(duì)需要混淆的字符串用宏打上標(biāo)記绘梦,然后使用腳本過濾所有源代碼,生成混淆過的代碼铣除。因?yàn)榛煜^的代碼可讀性極差,不利于維護(hù)鹦付,所以就需要解混淆代碼尚粘,用于把混淆過的代碼做還原。

混淆腳本
#!/usr/bin/env python
# encoding=utf8
# -*- coding: utf-8 -*-
# 本腳本用于對(duì)源代碼中的字符串進(jìn)行加密
# 替換所有字符串常量為加密的char數(shù)組敲长,形式((char[]){1, 2, 3, 0})

import importlib
import os
import re
import sys


# 替換字符串為((char[]){1, 2, 3, 0})的形式郎嫁,同時(shí)讓每個(gè)字節(jié)與0xAA異或進(jìn)行加密
def replace(match):
    string = match.group(2) + '\x00'
    replaced_string = '((char []) {' + ', '.join(["%i" % ((ord(c) ^ 0xAA) if c != '\0' else 0) for c in list(string)]) + '})'
    return match.group(1) + replaced_string + match.group(3)


# 修改源代碼秉继,加入字符串加密的函數(shù)
def obfuscate(file):
    with open(file, 'r') as f:
        code = f.read()
        f.close()
        code = re.sub(r'(confusion_NSSTRING\(|confusion_CSTRING\()"(.*?)"(\))', replace, code)
        code = re.sub(r'//#define ggh_confusion', '#define ggh_confusion', code)
        with open(file, 'w') as f:
            f.write(code)
            f.close()


#讀取源碼路徑下的所有.h和.m 文件
def openSrcFile(path):    
    print("開始處理路徑: "+ path +"  下的所有.h和.m文件")
    # this folder is custom
    for parent,dirnames,filenames in os.walk(path):
        #case 1:
#        for dirname in dirnames:
#            print((" parent folder is:" + parent).encode('utf-8'))
#            print((" dirname is:" + dirname).encode('utf-8'))
        #case 2
        for filename in filenames:
            extendedName = os.path.splitext(os.path.join(parent,filename))
            if (extendedName[1] == '.h' or extendedName[1] == '.m'):
                print("處理源代碼文件: "+ os.path.join(parent,filename))
                obfuscate(os.path.join(parent,filename))


#源碼路徑
srcPath = '../hello String'

if __name__ == '__main__':
    print("本腳本用于對(duì)源代碼中被標(biāo)記的字符串進(jìn)行加密")

    if len(srcPath) > 0:
        openSrcFile(srcPath)
    else:
        print("請(qǐng)輸入正確的源代碼路徑")
        sys.exit()

運(yùn)行該腳本 $ python3 confusion.py 把標(biāo)記過的代碼混淆。

生成混淆代碼
/*
 *  字符串混淆解密函數(shù)泽铛,將char[] 形式字符數(shù)組和 aa異或運(yùn)算揭秘
 *  如果沒有經(jīng)過混淆尚辑,請(qǐng)關(guān)閉宏開關(guān)
 */
extern char* decryptConstString(char* string)
{
    char* origin_string = string;
    while(*string) {
        *string ^= 0xAA;
        string++;
    }
    return origin_string;
}


//字符串混淆加密 和 解密的宏開關(guān)
#define ggh_confusion
#ifdef ggh_confusion
    #define confusion_NSSTRING(string) [NSString stringWithUTF8String:decryptConstString(string)]
    #define confusion_CSTRING(string) decryptConstString(string)
#else
    #define confusion_NSSTRING(string) @string
    #define confusion_CSTRING(string) string
#endif



@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *string = confusion_NSSTRING(((char []) {194, 207, 198, 198, 197, 138, 221, 197, 216, 198, 206, 0}));
    NSLog(@"%@",string);
}

@end

混淆后的代碼已經(jīng)看不到硬編碼了。在內(nèi)聯(lián)函數(shù)中做異或運(yùn)算盔腔。

解混淆腳本

解混淆腳本用于還原代碼杠茬,增加代碼可讀性。

#!/usr/bin/env python
# encoding=utf8
# -*- coding: utf-8 -*-
# 本腳本用于對(duì)源代碼中的字符串進(jìn)行解密
# 替換所有加密的char數(shù)組為字符串常量弛随,""

import importlib
import os
import re
import sys


# 替換((char[]){1, 2, 3, 0})的形式為字符串瓢喉,同時(shí)讓每個(gè)數(shù)組值與0xAA異或進(jìn)行解密
def replace(match):
    string = match.group(2)
    decodeConfusion_string = ""
    for numberStr in list(string.split(',')):
        if int(numberStr) != 0:
            decodeConfusion_string = decodeConfusion_string + "%c" % (int(numberStr) ^ 0xAA)

    # replaced_string = '\"' + "".join(["%c" % ((int(c) ^ 0xAA) if int(c) != 0 else '\0') for c in string.split(',')]) + '\"'
    replaced_string = '\"' + decodeConfusion_string + '\"'
    print("replaced_string = " + replaced_string)

    return match.group(1) + replaced_string + match.group(3)


# 修改源代碼,加入字符串加密的函數(shù)
def obfuscate(file):
    with open(file, 'r') as f:
        code = f.read()
        f.close()
        code = re.sub(r'(confusion_NSSTRING\(|confusion_CSTRING\()\(\(char \[\]\) \{(.*?)\}\)(\))', replace, code)
        code = re.sub(r'[/]*#define ggh_confusion', '//#define ggh_confusion', code)
        with open(file, 'w') as f:
            f.write(code)
            f.close()


#讀取源碼路徑下的所有.h和.m 文件
def openSrcFile(path):  
    print("開始處理路徑: "+ path +"  下的所有.h和.m文件") 
    # this folder is custom
    for parent,dirnames,filenames in os.walk(path):
        #case 1:
#        for dirname in dirnames:
#            print((" parent folder is:" + parent).encode('utf-8'))
#            print((" dirname is:" + dirname).encode('utf-8'))
        #case 2
        for filename in filenames:
            extendedName = os.path.splitext(os.path.join(parent,filename))
            #讀取所有.h和.m 的源文件
            if (extendedName[1] == '.h' or extendedName[1] == '.m'):
                print("處理代碼文件:"+ os.path.join(parent,filename))
                obfuscate(os.path.join(parent,filename))


#源碼路徑
srcPath = '../hello String'
if __name__ == '__main__':
    print("字符串解混淆腳本舀透,將被標(biāo)記過的char數(shù)組轉(zhuǎn)為字符串栓票,并和0xAA異或。還原代碼")
    if len(srcPath) > 0:
        openSrcFile(srcPath)
    else:
        print("請(qǐng)輸入正確的源代碼路徑愕够!")
        sys.exit()

混淆原理

因?yàn)橛簿幋a的字符串是在可執(zhí)行文件 Mach-O 全局的數(shù)據(jù)區(qū)走贪,在符號(hào)表中很容易被搜索到,而字符串?dāng)?shù)組則不會(huì)惑芭。

總結(jié)

混淆方案多種多樣坠狡,個(gè)有優(yōu)缺點(diǎn)。個(gè)人認(rèn)為最好的方式是依據(jù)Clang 抽象語(yǔ)法樹AST强衡,做全局混淆擦秽。另外,該方法還可以做方法名漩勤,類名感挥,屬性名等的混淆,只是全局混淆不能對(duì)所有名稱做混淆越败,如一些系統(tǒng)控件的代理方法等触幼。

本文代碼demo

之前代碼沒有上傳成功,各位兄弟抱歉了究飞,hello String -> confusion 目錄下為相關(guān)編碼解碼的腳本置谦。另,歡迎兄弟們大賞啊~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末亿傅,一起剝皮案震驚了整個(gè)濱河市媒峡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌葵擎,老刑警劉巖谅阿,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡签餐,警方通過查閱死者的電腦和手機(jī)寓涨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氯檐,“玉大人戒良,你說我怎么就攤上這事」谏悖” “怎么了糯崎?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)耗拓。 經(jīng)常有香客問我拇颅,道長(zhǎng),這世上最難降的妖魔是什么乔询? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任樟插,我火速辦了婚禮,結(jié)果婚禮上竿刁,老公的妹妹穿的比我還像新娘黄锤。我一直安慰自己,他們只是感情好食拜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布鸵熟。 她就那樣靜靜地躺著,像睡著了一般负甸。 火紅的嫁衣襯著肌膚如雪流强。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天呻待,我揣著相機(jī)與錄音打月,去河邊找鬼。 笑死蚕捉,一個(gè)胖子當(dāng)著我的面吹牛奏篙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播迫淹,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼秘通,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了敛熬?” 一聲冷哼從身側(cè)響起肺稀,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎应民,沒想到半個(gè)月后话原,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炸茧,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年稿静,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辕狰。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡改备,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔓倍,到底是詐尸還是另有隱情悬钳,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布偶翅,位于F島的核電站默勾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏聚谁。R本人自食惡果不足惜母剥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望形导。 院中可真熱鬧环疼,春花似錦、人聲如沸朵耕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)阎曹。三九已至伪阶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間处嫌,已是汗流浹背栅贴。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锰霜,地道東北人筹误。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像癣缅,于是被迫代替她去往敵國(guó)和親厨剪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評(píng)論 25 707
  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,237評(píng)論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理友存,服務(wù)發(fā)現(xiàn)祷膳,斷路器,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • 徠卡SL搭載的440萬點(diǎn)電子取景器是來自于愛普生?自徠卡SL發(fā)布以來,其搭載的440萬點(diǎn)EVF是誰生產(chǎn)的就一直被大...
    相機(jī)Beta閱讀 160評(píng)論 0 0
  • Photo by Dean Johns on Unsplash 坐在車?yán)锝?jīng)過回國(guó)道的時(shí)候勇皇,像一次神秘而難得的走向往...
    克拉吉島風(fēng)閱讀 253評(píng)論 0 2