iOS 逆向工程初探

應(yīng)用場景

在了解iOS逆向工程之前须鼎,我們有必要了解它究竟能做什么,在開發(fā)中能夠獲得哪些幫助府蔗?個人覺得有以下四點

  • 促進(jìn)正向開發(fā)晋控,深入理解系統(tǒng)原理
  • 借鑒別人的設(shè)計和實現(xiàn),實現(xiàn)自己的功能
  • 從逆向的角度實現(xiàn)安全保護(hù)
  • 篡改他人的App(不推薦)

以上四點有自己正在學(xué)習(xí)的東西姓赤,也有已經(jīng)有了一些了解的東西赡译,當(dāng)我們知道iOS逆向工程究竟能做什么的時候,下一步就到了應(yīng)該How do的階段不铆,我把How do it蝌焚?根據(jù)不同的目地列出以下幾個步驟裹唆。

  • 解密、導(dǎo)出應(yīng)用程序只洒、導(dǎo)出頭文件许帐,為后續(xù)工作做準(zhǔn)備
  • 從應(yīng)用界面表現(xiàn)入手,獲取當(dāng)前界面布局及控制器
  • hook發(fā)現(xiàn)的一些相關(guān)類毕谴,記錄輸出調(diào)用順序及參數(shù)
  • 找到關(guān)鍵函數(shù)成畦,查看調(diào)用堆棧,hook測試效果
  • 靜態(tài)分析加動態(tài)調(diào)試分析關(guān)鍵函數(shù)的實現(xiàn)邏輯
  • 模擬或篡改函數(shù)調(diào)用邏輯
  • 制作插件并移植到非越獄機器(正在研究)

零涝开、準(zhǔn)備工作

在砸殼之前循帐,需要做很多準(zhǔn)備工作,首先要準(zhǔn)備一臺越獄的設(shè)備舀武,在越獄過程中拄养,會安裝一個叫作Cydia的軟件,相當(dāng)于越獄設(shè)備的AppStore奕剃,可以在上面查找安裝各類軟件包。
有了越獄設(shè)備之后捐腿,接下來就要安裝各種有助于逆向的插件纵朋。
1.SSH:用于遠(yuǎn)程登錄越獄設(shè)備、執(zhí)行命令茄袖,iOS10以前需要在Cydia上安裝openSSH操软,iOS10之后需要安裝dropbear.
2.Filza:方便的查看iOS的文件目錄。
3.Cydia Substrate:一個允許第三方開發(fā)者在越獄系統(tǒng)方法里的加一些運行時補丁和擴(kuò)展方法宪祥,是越獄開發(fā)的基石聂薪。
4.adv-cmds:一個命令行集合工具,提供了很多方便的命令蝗羊。比如后面會用到的ps -e命令藏澳。
5.appsync:直接修改應(yīng)用文件或結(jié)構(gòu)會破壞應(yīng)用的簽名信息,導(dǎo)致修改后的應(yīng)用無法安裝耀找,所以需要appsync補丁讓系統(tǒng)不在驗證應(yīng)用的簽名翔悠。
6.Cycript:使一個允許開發(fā)者使用OC和JS組合語法查看及修改運行時App內(nèi)存信息的工具。

一野芒、解密蓄愁,又稱砸殼

砸殼的工具網(wǎng)絡(luò)上現(xiàn)在主要有兩種Clutchdumpdecrypted

1. Clutch

Clutch是一個開源的工具狞悲,它會生成一個新的進(jìn)程撮抓,然后暫停進(jìn)程并dump內(nèi)存。
使用上很簡單摇锋,只需要從Git倉庫中拉取項目并編譯丹拯,在Build/Clutch文件目錄下會生成一個叫Clutch的命令行工具忧风。

Clutch

接下來用scp命里通過ssh遠(yuǎn)程登錄拷貝Clutch到設(shè)備的/usr/bin目錄下,然后通過chmod命令給它附加可執(zhí)行權(quán)限选调。

scp ./Build/Clutch root@10.20.10.197:/usr/bin
//鏈接設(shè)備
ssh root@10.20.10.197
chmod +x /usr/bing/Clutch

這個時候就能通過Clutch破解手機安裝的應(yīng)用了

Clutch -i//顯示手機安裝的應(yīng)用
Clutch -d 應(yīng)用id//通過-d命令對指定應(yīng)用執(zhí)行dump操作暖释,命令執(zhí)行完會沙盒目錄下出現(xiàn)ipa包
完整的Clutch解密過程

接下來同樣用scp命令把對應(yīng)的破解的ipa包拷到手機上,為下一步做準(zhǔn)備剑刑。

2.dumpdecrypted

dumpdecrypted也是一個開源的工具媳纬,與Clutch不同的是它會注入可執(zhí)行文件,動態(tài)地從內(nèi)存中dump出解密后的內(nèi)容(一個完整的ipa包)施掏,相比Clutch它的操作略顯繁瑣钮惠,但成功率很高,Clutch在破解體積較大的App時往往會使手機卡死直至重啟七芭,對不完美越獄來說又得重新越獄一次素挽。
首先也要從Git倉庫拉取項目并編譯,編譯完會生成一個dumpdecrypted.dylib文件狸驳。
接下來需要定位要解密的可執(zhí)行文件预明,把dumpdecrypted.dylib放到App的沙盒目錄Documents下,然后通過DYLD_INSERT_LIBRARIES系統(tǒng)的環(huán)境變量把其注入到應(yīng)用中并開始解密耙箍,最后解密的包會生成在App的應(yīng)用目錄下撰糠。

獲取App應(yīng)用目錄和沙盒目錄

3.class-dump

class-dump也是個開源的工具,可以從可執(zhí)行文件中獲取類辩昆、方法和屬性信息到工具阅酪,通過頭文件可以快速尋找到想要的方法和屬性。
使用上很簡單汁针,class-dump -H targetApp -o ./Header就可以术辐,-o后跟的是放頭文件的路徑

class-dump分析出的頭文件

其中一個頭文件

上面的頭文件可以清楚的看到所有的屬性方法,對分析App很有幫助施无。
4.IDA與Hopper
IDA與Hopper能從解密的應(yīng)用中分析出實現(xiàn)文件(.m文件)進(jìn)行反編譯辉词,兩者的功能類似,但是IDA更強大猾骡,反編譯后的代碼比Hopper容易理解的多较屿,使用上只需要把解密后的文件拖入兩個軟件之中就會自動分析。


IDA的偽代碼
Hop的偽代碼

兩者相比之下卓练,明顯IDA的更容易讀懂隘蝎。

二、從應(yīng)用界面尋找突入點

這里得提到另一個可以極大提高開發(fā)效率的神器--Reveal襟企,Xcode從7.0開始已經(jīng)集成了Reveal的一部分功能嘱么,但是只能再開發(fā)自己的應(yīng)用時使用。
想要使用Reveal查看手機上的任意應(yīng)用顽悼,首先要在Cydia中安裝Reveal2Loader插件曼振,接著把Reveal程序用自帶的RevealServer.framework導(dǎo)入到越獄設(shè)備的/Library/Framework中几迄,并在設(shè)置中開啟想要查看的應(yīng)用即可。如下圖:

Translate Me的應(yīng)用界面

下面我們就Translate Me是如何實現(xiàn)自動識別多語言語音的功能展開接下來的探索冰评。

三映胁、找到關(guān)鍵函數(shù)

在上圖我們可以看到語音識別按鈕Memory Address,通過此地址我們能通過Cycript進(jìn)一步定位到按鈕的方法甲雅,上文已經(jīng)說過Cycript可以通過OC語法查看App運行時信息解孙,就像下面我們干的一樣。

通過Cycript獲取的按鈕方法

定位到按鈕調(diào)用的方法為onMicButton:抛人。

四弛姜、分析函數(shù)的實現(xiàn)邏輯

通過查看IDA的onMicButton:的偽函數(shù),可以看到另一個至關(guān)重要的類SDCSpeechViewControllerviewModel妖枚,打開頭文件發(fā)現(xiàn)其屬于另一個類廷臼,順藤摸瓜的一路找到了核心類SDCRecognizer!绝页!

SDCRecognizer

當(dāng)看到SFSpeechRecognitionTask荠商、SFSpeechAudioBufferRecognitionRequestSFSpeechRecognizer這幾個類的時候续誉,我就知道自動識別多語言語音的秘密就在此處莱没,因為這幾個類都是屬于iOS SpeechKit中的核心類,負(fù)責(zé)語音識別的功能屈芜。
這個類肯定通過兩個SFSpeechAudioBufferRecognitionRequest實例保存了不同語言的語音的緩存郊愧,這是我以前實驗過卻沒有成功的地方朴译,然后通過SFSpeechRecognizerSFSpeechRecognitionTask轉(zhuǎn)換語音對應(yīng)兩種不同語言的文本井佑,根據(jù)processPrimaryResult:startBackingRecognition這兩個方法名,可以猜測前者識別主語言的語音眠寿,或者識別第二種語言的語音躬翁,并且兩者都調(diào)用了averageConfidence方法,通過averageConfidence這個方法名我有理由去相信其獲取的是語音對應(yīng)不同語言的置信度盯拱。
IDA中processPrimaryResult的偽函數(shù)

接下來只要印證它就OK了盒发。

動態(tài)調(diào)試-準(zhǔn)備工作

這里我們可以通過打斷點的方式論證我們的猜想,理清SFSpeechRecognizer的主要函數(shù)的調(diào)用順序狡逢,在iOS開發(fā)中Xcode的斷點調(diào)試是一大利器--LLDB宁舰,當(dāng)Xcode調(diào)試手機App時,Xcode會將debugserver文件復(fù)制到手機中奢浑,以便在手機上啟動一個服務(wù)蛮艰,等待Xcode進(jìn)行遠(yuǎn)程調(diào)試,這里通過修改debugserver文件達(dá)到調(diào)試別人App的目的雀彼。

1.用命令行或者iTools工具把Developer/usr/bin下的debugserver文件拷貝到電腦上壤蚜。
2.用Xcode新建一個entitlements.plist文件即寡,加入以下四個鍵值對

<dict>
    <key>com.apple.springboard.debugapplications</key>
    <true/>
    <key>run-unsigned-code</key>
    <true/>
    <key>get-task-allow</key>
    <true/>
    <key>task_for_pid-allow</key>
    <true/>
</dict>

3.通過命令codesign -s - --eentitlements eentitlements.plist -f debugserver給** debugserver**重新簽名
4.把文件拷貝回設(shè)備原目錄并賦予可執(zhí)行權(quán)限

開始調(diào)試

啟動App,鏈接設(shè)備袜刷,通過以下命令即可對目標(biāo)App進(jìn)行調(diào)試

LLDB調(diào)試

lldb需要獲取App的方法在內(nèi)存中的地址才能夠打斷點聪富,在lldb中可以通過image list -o -f "processName"來獲得App運行的基地址,加上IDA中反編譯的內(nèi)存偏移量著蟹,就能得到App運行時方法的真正地址墩蔓。
加了斷點的方法

通過lldb打斷點

接著在lldb輸入c并enter繼續(xù)運行程序,點擊App的語音識別按鈕
翻譯App
斷點執(zhí)行順序1
斷點執(zhí)行順序2

斷點執(zhí)行順序3

可以明顯看到執(zhí)行順序為start->setup->processPrimaryResult->stopRecording-> processPrimaryResult->averageConfidence->startBackingRecognition-> averageConfidence草则,可以看出與我們的猜想基本一致钢拧,并且這個App是識別完一種語言之后在識別另一種語言,這也解釋了為什么App使用時只有說完話才能識別哪種語言的現(xiàn)象炕横,最后我依照SFSpeechRecognizer的邏輯寫了自己的函數(shù)源内,如下:

- (void) configAudioEngine:(void (^)(SFSpeechRecognitionResult *, NSError *, BOOL))resultHandler language:(NSString *) languageCode {
    //切換AVAudioSession
    AVAudioSession * audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryRecord mode:AVAudioSessionModeDefault options:AVAudioSessionCategoryOptionDuckOthers | AVAudioSessionCategoryOptionAllowBluetooth error:nil];
    [audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
    
    //設(shè)置語言
    NSLocale * locale = [NSLocale localeWithLocaleIdentifier:languageCode];
    self.speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
    self.speechRecognizer.defaultTaskHint = 1;
    
    NSLocale * targetLocale = [NSLocale localeWithLocaleIdentifier:self.translatedLanguageCode];
    self.targetSpeechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:targetLocale];
    self.targetSpeechRecognizer.defaultTaskHint = 1;
    
    if (self.recognitionRequest) {
        [self.recognitionRequest endAudio];
        self.recognitionRequest = nil;
    }
    
    if (self.targetRecognitionRequest) {
        [self.targetRecognitionRequest endAudio];
        self.targetRecognitionRequest = nil;
    }
    
    self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
    self.recognitionRequest.shouldReportPartialResults = YES;
    
    self.targetRecognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
    self.targetRecognitionRequest.shouldReportPartialResults = YES;
    
    MJWeakSelf
    self.recognitionTask = [self.speechRecognizer recognitionTaskWithRequest:self.recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
        if (result.final) {
            NSLog(@"source result === %@", result.bestTranscription.formattedString);
            weakSelf.sourceSpeechResult = result;
            weakSelf.sourceLanguageConfidence = [weakSelf averageConfidence:result];
            [weakSelf recogniTargetLanguage:resultHandler];
        }
    }];
    
    AVAudioFormat * recordingFormat = [[self.audioEngine inputNode] outputFormatForBus:0];

    self.audioEngine = [[AVAudioEngine alloc] init];
    [[self.audioEngine inputNode] installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
        [self.recognitionRequest appendAudioPCMBuffer:buffer];
        [self.targetRecognitionRequest appendAudioPCMBuffer:buffer];
    }];
    [self.audioEngine prepare];
    [self.audioEngine startAndReturnError:nil];
}

- (void) closeAudioEngine {
    
    if (self.audioEngine.isRunning) {
        [[self.audioEngine inputNode] removeTapOnBus:0];
        [self.audioEngine stop];
    }
    
    [self.recognitionRequest endAudio];
    self.recognitionRequest = nil;
}

- (void) recogniTargetLanguage:(void (^)(SFSpeechRecognitionResult *, NSError *, BOOL source))resultHandler{
    
    MJWeakSelf
    self.targetRecognitionTask = [self.targetSpeechRecognizer recognitionTaskWithRequest:self.targetRecognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
        NSLog(@"target result === %@", result.bestTranscription.formattedString);
        if (result.final) {
            float targetConfidence = [weakSelf averageConfidence:result];
            if (targetConfidence < weakSelf.sourceLanguageConfidence) {
                resultHandler(weakSelf.sourceSpeechResult, nil, YES);
            } else {
                resultHandler(result, nil, NO);
            }
        }
        if (error) {
            NSLog(@"target Recogni error === %@", error);
        }
    }];
    
    [self.targetRecognitionRequest endAudio];
    self.targetRecognitionRequest = nil;
}

- (float) averageConfidence:(SFSpeechRecognitionResult *) result{
    
    NSMutableArray * array = [NSMutableArray array];
    NSArray * resultArray = result.bestTranscription.segments;
    for (SFTranscriptionSegment * segment in resultArray) {
        [array addObject:[NSNumber numberWithFloat:segment.confidence]];
    }
    
    float avgConfidence = [[array valueForKeyPath:@"@avg.self"] floatValue];
    NSLog(@"result === %@\nConfidence === %f", result.bestTranscription.formattedString, avgConfidence);
    
    return avgConfidence;
}

語音自動識別語言

我把每一次識別的結(jié)果進(jìn)行回調(diào),當(dāng)說完“今天天氣不錯”這句話時中文語言的置信度為0.924333份殿,英文語言的置信度為0.743899膜钓,明顯中文的置信度更高,至此已初步體會到逆向工程給予我們的幫助----借鑒別人的設(shè)計和實現(xiàn)卿嘲,實現(xiàn)自己的功能颂斜,完結(jié)撒花~
當(dāng)然逆向工程還有更多有用的東西我沒有分享,比如模擬或篡改函數(shù)調(diào)用邏輯拾枣、制作插件等沃疮。
希望下次有機會能給大家在做更深一步的分享~

PS:極力推薦 劉培慶 所著《iOS應(yīng)用逆向與安全》,是我找到市面上最新講解iOS逆向工程相關(guān)的書籍梅肤,本文章可以說是此書前幾章的概括

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末司蔬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子姨蝴,更是在濱河造成了極大的恐慌俊啼,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件左医,死亡現(xiàn)場離奇詭異授帕,居然都是意外死亡,警方通過查閱死者的電腦和手機浮梢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門跛十,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秕硝,你說我怎么就攤上這事芥映。” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵屏轰,是天一觀的道長颊郎。 經(jīng)常有香客問我,道長霎苗,這世上最難降的妖魔是什么姆吭? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮唁盏,結(jié)果婚禮上内狸,老公的妹妹穿的比我還像新娘。我一直安慰自己厘擂,他們只是感情好昆淡,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著刽严,像睡著了一般昂灵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舞萄,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天眨补,我揣著相機與錄音,去河邊找鬼倒脓。 笑死撑螺,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的崎弃。 我是一名探鬼主播甘晤,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饲做!你這毒婦竟也來了线婚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤艇炎,失蹤者是張志新(化名)和其女友劉穎酌伊,沒想到半個月后腾窝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缀踪,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年虹脯,在試婚紗的時候發(fā)現(xiàn)自己被綠了驴娃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡循集,死狀恐怖唇敞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤疆柔,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布咒精,位于F島的核電站,受9級特大地震影響旷档,放射性物質(zhì)發(fā)生泄漏模叙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一鞋屈、第九天 我趴在偏房一處隱蔽的房頂上張望范咨。 院中可真熱鬧,春花似錦厂庇、人聲如沸渠啊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽替蛉。三九已至,卻和暖如春拄氯,著一層夾襖步出監(jiān)牢的瞬間灭返,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工坤邪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留熙含,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓艇纺,卻偏偏與公主長得像怎静,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子黔衡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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

  • 1. 為什么要逆向工程 iOS 逆向工程主要有兩個作用:1蚓聘,分析目標(biāo)程序,拿到關(guān)鍵信息,可以歸類于安全相關(guān)的逆向...
    弦暮閱讀 1,229評論 2 4
  • ios 逆向工程 剛進(jìn)一個新公司,公司的大牛直接分給一個課題研究任務(wù)盟劫,直接懵逼了夜牡,/(ㄒoㄒ)/~~ 想哭,世界就...
    天下林子閱讀 29,596評論 39 120
  • 逆向工程的目的 1)分析競品的最新研究或者產(chǎn)品原型(包括所用的技術(shù)侣签,所使用的框架) 2)學(xué)術(shù)/學(xué)習(xí)目的塘装。 3)破解...
    零度_不結(jié)冰閱讀 688評論 0 2
  • 即使花完一個珍貴的半天假,用于在家煲卷福劇影所,我還是忍不住腦中爆炸的“bored!bored!” 連我自己都不能看到...
    土羊齋閱讀 500評論 0 0
  • 【“工匠汾酒”系列之十七·勾調(diào)篇】 勾調(diào)猴娩,是個高端技術(shù)活 2018年元旦剛過阴幌,三晉大地上的杏花村勺阐,被一股寒流襲擊,...
    滄桑正道閱讀 89,576評論 0 0