淺析iOS應用程序的脫殼實(shí)現原理

2019-03-18 10:45:37分類(lèi):IOS應用設計7111

  應用程序加載過(guò)程

  對于諸多逆向愛(ài)好者來(lái)說(shuō),給一個(gè)app脫殼是一項必做的事情?;诎踩缘目紤],蘋(píng)果對上架到appstore的應用都會(huì )進(jìn)行加密處理,所以如果直接逆向一個(gè)從appstore下載的應用程序時(shí),所能看到的“源代碼”將非常的晦澀難懂。為了能看懂應用程序的“源代碼”,就必須對應用程序進(jìn)行解密,也就是所謂的脫殼。脫殼后的目的是可以分析應用程序的一些技術(shù)實(shí)現原理,或者利用一些漏洞進(jìn)行攻擊和測試。

  這篇文章不是一篇介紹如何利用工具去進(jìn)行脫殼的教程,而只是簡(jiǎn)單的分析這些常用脫殼工具的實(shí)現原理。要想了解脫殼原理,就要先去了解一個(gè)被加密的應用程序是如何被運行的。下面一張圖片簡(jiǎn)單的介紹了一個(gè)被加殼后的應用程序被加載和運行的過(guò)程:
 

iOS應用程序
 

  脫殼原理以及常見(jiàn)的工具

  要對一個(gè)殼應用進(jìn)行脫殼處理,無(wú)非就是采用靜態(tài)脫殼和動(dòng)態(tài)脫殼兩種方法:靜態(tài)脫殼就是在已經(jīng)掌握和了解到了殼應用的加密算法和邏輯后在不運行殼應用程序的前提下將殼應用程序進(jìn)行解密處理。靜態(tài)脫殼的方法難度大,而且加密方發(fā)現應用被破解后就可能會(huì )改用更加高級和復雜的加密技術(shù);動(dòng)態(tài)脫殼就是從運行在進(jìn)程內存空間中的可執行程序映像(image)入手,來(lái)將內存中的內容進(jìn)行轉儲(dump)處理來(lái)實(shí)現脫殼處理。這種方法實(shí)現起來(lái)相對簡(jiǎn)單,且不必關(guān)心使用的是何種加密技術(shù)。從上面的殼應用程序運行的過(guò)程就可以看出無(wú)論殼程序如何被加密處理,最終運行后在進(jìn)程中的代碼映像(image)始終是被解密后的原始程序二進(jìn)制。所以只要一個(gè)進(jìn)程內存空間中的代碼映像(image)能被讀取和訪(fǎng)問(wèn)就可以實(shí)現動(dòng)態(tài)脫殼。下面要介紹的兩個(gè)工具就是巧妙的運用了兩種不同的訪(fǎng)問(wèn)技巧來(lái)實(shí)現動(dòng)態(tài)脫殼的。

  一、利用動(dòng)態(tài)庫注入來(lái)實(shí)現脫殼的dumpdecrypted/frida-ios-dump

  dumpdecrypted和frida-ios-dump都是在github上開(kāi)源的項目,下載地址分別為:https://github.com/stefanesser/dumpdecrypted和https://github.com/AloneMonkey/frida-ios-dump。關(guān)于使用這兩個(gè)工具來(lái)進(jìn)行脫殼的文檔非常之多。我們知道一個(gè)應用除了有一個(gè)可執行程序外,還會(huì )鏈接非常多的動(dòng)態(tài)庫。動(dòng)態(tài)庫加載后和可執行程序共享相同的進(jìn)程內存空間,而且動(dòng)態(tài)庫中的代碼是可以訪(fǎng)問(wèn)整個(gè)進(jìn)程內存空間中的有權限的區域的,包括可執行程序的image被加載到進(jìn)程中的內存區域。因此只要想辦法讓?xiě)贸绦蚣虞d某個(gè)特定的第三方動(dòng)態(tài)庫,也就是讓這個(gè)第三方動(dòng)態(tài)庫注入到應用程序的進(jìn)程中去就可以實(shí)現將被解密過(guò)后的可執行程序在進(jìn)程內存中的image信息轉儲到文件中去從而實(shí)現脫殼處理。對于一個(gè)越獄后的設備來(lái)說(shuō)主要可以通過(guò)兩種方法來(lái)實(shí)現第三方動(dòng)態(tài)庫的注入:

  設置環(huán)境變量DYLD_INSERT_LIBRARIES的值指向這個(gè)第三方動(dòng)態(tài)庫的路徑。然后運行要脫殼的應用程序即可。 DYLD_INSERT_LIBRARIES環(huán)境變量的設置是一個(gè)操作系統提供的特性,所有運行的程序都會(huì )加載這個(gè)環(huán)境變量中所指向的動(dòng)態(tài)庫文件。

  將第三方動(dòng)態(tài)庫文件保存在越獄設備的/Library/MobileSubstrate/DynamicLibraries/目錄下并編寫(xiě)對應的庫的同名plist文件,所有plist中指定的可執行程序一旦運行就會(huì )加載對應的動(dòng)態(tài)庫(此目錄即Tweak插件所在的目錄)。

  還有一種直接修改對應mach-o格式的可執行文件內容來(lái)實(shí)現動(dòng)態(tài)庫注入。

  動(dòng)態(tài)庫加載的問(wèn)題解決后就需要解決動(dòng)態(tài)庫中代碼運行的時(shí)機問(wèn)題了。要想讓一個(gè)被加載的動(dòng)態(tài)庫在加載后自動(dòng)運行某一段代碼可以有四種方法:

  建立一個(gè)C++全局對象,并在對象所屬類(lèi)的構造函數中添加特定代碼。

  建立一個(gè)OC類(lèi),并在OC類(lèi)的+load方法中添加特定的代碼。

  生成動(dòng)態(tài)庫時(shí)指定一個(gè)初始化init入口函數,并在入口函數中添加特定的代碼。

  在動(dòng)態(tài)庫中定義一個(gè)帶有_attribute_((constructor))聲明的函數,并在函數內添加特定的代碼。

  如果你想更進(jìn)一步的了解上述那些方法的加載的原理,請參考我的文章:深入解構iOS系統下的全局對象和初始化函數

  dumpdecrypted這個(gè)工具就是通過(guò)建立一個(gè)名為dumpdecrypted.dylib的動(dòng)態(tài)庫并在庫內部定義了一個(gè)

  函數來(lái)實(shí)現脫殼的。這個(gè)函數的大體實(shí)現會(huì )在后面繼續介紹。
 

iOS應用程序
 

  二、利用父子進(jìn)程關(guān)系來(lái)實(shí)現脫殼的Clutch

  Clutch也是一個(gè)在github上開(kāi)源的項目,下載地址為:

  https://github.com/KJCracks/Clutch。關(guān)于這個(gè)工具的使用教程也非常之多。我們知道在unix系列的操作系統中父進(jìn)程可以通過(guò)fork或者posix_spawnp兩個(gè)函數來(lái)運行或者建立一個(gè)子進(jìn)程的,這兩個(gè)函數都會(huì )返回對應的子進(jìn)程ID(PID)。iOS系統則可以通過(guò)task_for_pid函數來(lái)從進(jìn)程ID獲取進(jìn)程在mach內核子系統中的mach port標識。得到mach port 標識后,就可以借助mach_vm_read_overwrite函數來(lái)讀取指定進(jìn)程空間中的任意虛擬內存區域中所存儲的內容。因此Clutch內部的實(shí)現就是Clutch這個(gè)程序對將要進(jìn)行脫殼的程序文件路徑調用posix_spawnp函數來(lái)運行從而成為其子進(jìn)程,然后借助task_for_pid以及mach_vm_read_overwrite函數來(lái)讀取脫殼程序子進(jìn)程在內存中已經(jīng)被解密后的可執行程序的image所映射的內存空間來(lái)達到脫殼的目的的。

  一個(gè)思考:可能在實(shí)際中并不一定要求是父子進(jìn)程關(guān)系,是否只要某個(gè)具有特權的程序或者運行在root用戶(hù)上的程序只要拿到了對應進(jìn)程的PID就可以通過(guò)mach子系統提供的API來(lái)讀取其他進(jìn)程內存空間中的信息呢?

  上述的兩種方法中不管是dumpdecrypted還是Clutch最終都是將被解密后的可執行程序的image在內存中的映射寫(xiě)入到一個(gè)文件中去來(lái)保存脫殼后的內容。參考dumpdecrypted中的dumptofile函數實(shí)現以及Clutch中的Dumpers目錄下的實(shí)現代碼就可以看出:一個(gè)可執行程序image在內存中映射的內容的結構和mach-o格式的可執行文件結構基本上是保持一致的。都是有一個(gè)mach_header結構體頭還有諸多的load_command結構體組成。因此所謂的dump處理就是將內存中的這些結構和數據原封不動(dòng)的寫(xiě)入到文件中去即完成了脫殼中的最核心的部分。如果想仔細的閱讀這部分代碼的實(shí)現,建議先了解一下mach-o文件格式的組成。

  后記

  當你了解了這些內部實(shí)現后,也許你會(huì )發(fā)覺(jué)其實(shí)它的原理很簡(jiǎn)單。而且有可能你也能很快的去實(shí)現??蓡?wèn)題的關(guān)鍵是為什么這些方法總是別人能想到,而我們卻想不到呢?這是否和國人的思維以及解決問(wèn)題的方式相關(guān)呢?在我們的教育和實(shí)踐體系中更多的是拿來(lái)主義和實(shí)用主義,往往很少人會(huì )對問(wèn)題進(jìn)行深入的探索研究以及進(jìn)行問(wèn)題的關(guān)聯(lián)性思考。但愿這種情況在未來(lái)能夠得到改進(jìn),尤其作為一個(gè)程序員,更加應該秉持探索求知的強烈意愿而不是簡(jiǎn)單復制和應用就滿(mǎn)足了。

上一篇:下一篇: