您好,登錄后才能下訂單哦!
接來下的這篇文章會介紹如何完成一個“不可能”的任務——通過改一個數字,破解掉Paw這個收費軟件。
起初是在某位大神的博客里看到了Mac上一款非常好用的App,叫Paw。Paw可以在Mac上模擬各種HTTP請求,可視化的管理HTTP Header、Parameters、Cookies等,還有一點非常出乎意料的功能是通過下載插件可以自動生成Swfit、OC、JS等多種語言的代碼。
然而Paw巨貴(198軟妹幣),而且破解版不好搜。于是尋思著自己動手解決需求,于是倒霉的Paw成了實驗對象。先從這里下載原版app
由于在此之前我毫無逆向工程方面的經驗,在看別人的介紹時各種不懂,深受折磨,所以我盡量用簡單、詳細的語言描述本次從零開始破解app之旅。作為參考,我用了大約七個小時的時間完成了此次破解(大量的時間浪費在找工具以及學習使用工具上,后面可以看到破解這個事情本身并不難)。在文章的最后會給出破解版的下載地址。
由于水平有限,只是介紹了基本的逆向工程知識,算是自己的學習筆記,也希望向更多的和我一樣還只是菜鳥的程序員科普一些逆向工程的基本知識,同時督促自己平時在Coding過程中的注意代碼規范和安全。
想要破解app,首先自己得開發過app,至少了解一些基本的命令行操作,源代碼、匯編代碼和二進制碼的基本定義。如果這些基本要求有某一點不滿足,那么整個過程會是非常痛苦的。
破解Paw用到的工具主要有以下幾個。
homebrew —— 不知道這個的估計都不好意思說自己是用Mac的程序員。
Hopper Disassembler —— 反編譯工具,根據可執行文件反編譯出匯編碼。
Class-dump —— 逆向工程的入門級工具,導出一個App的某些信息。
otx —— 國外某位大神的介紹的一個工具,我也說不出明確的用處。通過brew install --HEAD homebrew/head-only/otx
命令安裝。
Hex friend —— 二進制文件編輯器,要用這個修改二進制文件。
gdb —— 著名的調試器,用lldb也行。通過brew install gdb
命令安裝。
要破解App當然要明白自己為什么要破解它,它哪一點限制了我們,首先運行原版的Paw。可以看到如下界面:
這個Welcome界面非常討厭,由于它的存在,我們不能點擊程序主界面。而想要關掉這個Welcome界面,只有兩個方法,選擇Try Paw按鈕獲得30天試用期或點擊Register License按鈕輸入自己的License。
因此我們的目的以及非常明確了——關閉這個Welcome頁面
既然要破解這個App,免不了要去了解這個App的結構。現在我們手上只有在Applications文件夾下的Paw.app這一個文件。突破口在于Paw.app/Contents/MacOs/Paw這個可執行的二進制文件。我們以后的操作,絕大多數時候是與它打交道。在“應用程序”文件夾下,右鍵Paw,選擇“顯示包內容”就可以看到這個二進制文件了
這時候,第一個工具——class-dump
出場了。由于篇幅所限,我就不介紹這個工具的具體配置方法了。可以參考這篇文章
使用class-dump導出其他應用頭文件
我們先用class-dump
導出Paw的頭文件看看,在終端中執行命令:
class-dump -H /Applications/PawReal.app/Contents/MacOS/Paw -o /Users/你的用戶名/Desktop/classdump
,
換上你的用戶名,等運行結束之后,在桌面上可以看到一個叫classdump
的文件夾。不要被里面密密麻麻的文件嚇到,這就是這個app所有的頭文件了。
接下來怎么找我們需要的信息呢,要想一個一個看過去,即使頭文件里面只有方法和變量的定義,也是不現實的。好在class-dump
還有別的功能。執行命令:
class-dump -f license /Applications/PawReal.app/Contents/MacOS/Paw
可以找到頭文件中所有和license有關的部分。
會什么要找license呢,這個就需要猜了。既然這個軟件需要注冊碼,并且Welcome界面有一個Register License按鈕,一定會有一部分代碼是用來管理證書(License)相關的。讓我們站在開發者的角度上想,如果要遵守命名規范,那么頭文件中也許會有License關鍵字的身影。
當然,這只是猜想,如果針對License關鍵字的查找結果不理想的話,我們還可以換一些關鍵字,比如Register、Validate等。
不過好在我們通過class-dump
發現了一些線索,如圖所示:
在圖中,我們發現了一個比較有價值的類:LMWelcomeViewController
發現LMWelcomeViewController
這個用來管理Welcome頁面的類之后,我們打開頭文件看看里面的函數。很“巧”地,里面有一組函數,都是以showWelcomeWindow
開頭。直覺告訴我們,這個用來顯示Welcome頁面的方法,很有可能就是解決問題的關鍵。
故技重施,再看一看showWelcomeWindow
這個函數的信息。運行:
class-dump -f showWelcome /Applications/PawCrack.app/Contents/MacOS/Paw
可以看到這樣的結果:
這就基本上印證了之前的猜想:LMApplicationDelegate.m
中的代碼在程序啟動時執行,通過某種方式判斷用戶是否已注冊,如果沒有的話,就調用showWelcomeWindow
這個函數,同時把LMWelcomeViewController
類的實例對象作為參數,這個對象再執行自己的showWelcomeWindow
方法,展示Welcome頁面
當然,這樣的分析很可能是錯的。因為判斷是否注冊這個邏輯并不一定在LMApplicationDelegate
中進行,也可以放在LMWelcomeViewController
里。但無論如何,注意到黑體字部分連起來也是一段話,整個過程其實是一個“如果……,就……”的邏輯。
記住這個邏輯,一會兒我們會根據這個邏輯做一些修改!
我們已經知道LMWelcomeViewController
的showWelcomeWindow
方法可能是解決問題的關鍵,接下來我們就來看看這個方法到底是怎么實現的。
打開Hopper Disassembler,把MacOS文件夾下的Paw二進制文件拖入其中,開始分析。Hopper Disassembler可以根據二進制文件反匯編成匯編代碼。剛打開的時候,這個軟件是這個樣子:
在這個軟件中看到的東西往往非常奇葩,和任何一種高級編程語言都不同。這種匯編語言給新手的閱讀造成了極大的障礙,好在有一些注釋,也可以生成偽代碼,輔助我們閱讀。我幾乎不太能看懂匯編語言,所以盡量避免過多的研究他們。
在左邊的Labels標簽下搜索我們感興趣的內容,比如剛剛說的showWelcomeWindow
方法。
可以分別看到在LMWelcomeViewController
和LMApplicationDelegate
中showWelcomeWindow
方法的實現:
LMApplicationDelegate
中的showWelcomeWindow
方法非常簡單,根據綠色部分的注釋可以猜到調用了參數的showWelcomeWindow
方法。或者我們可以選中這段匯編代碼,點右上角的圖標生成偽代碼。
LMWelcomeViewController
中的showWelcomeWindow
方法比較復雜。
之前的圖片上可以看到兩個匯編指令分別是:je
和ret
je
是“jump euqal”的縮寫,表示如果相等,則跳轉到某個地址。所以我們可以在je
的上面一行看到cmp
指令。與je
相對應的就是jne
,表示“jump not euqal”
ret
顧名思義就是return的縮寫了,表示函數在這里返回。
其實在這里我們已經可以大概了解這個中的showWelcomeWindow
方法的實現了。進行了一個判斷,如果城里就返回,否則就進行下面一段操作,而根據右側綠色提示,我們看到了“可怕”的showWindow
方法,這個方法沒有在頭文件里面看到,估計就是一個 私有方法了。
如果不放心的話還可以生成偽代碼看看:
之前分析了整個Welcome頁面出現的邏輯其實是一個“如果……,就……”的判斷,那么要想破解,也很容易。方法有兩個,要么判斷條件不成立,要么改變執行語句。顯然,對于不熟悉匯編和逆向工程的新手而言,讓判斷條件不容易更加簡單一些。注意到je
指令之前有一個數字:00000001000cdfaf,它表示的是這條指令在虛擬內存空間中的地址。那么這個地址有什么用呢?
確實乍一看,獲取指令的地址并沒有用處。而且從開始到現在,一直在接觸完全沒接觸過的東西,已經有點暈乎了。
梳理一下到目前為止的思路,我們從license關鍵字樹藤摸瓜,找到了showWelcomeWindow
方法。分析出其中的關鍵一步是je
指令,最后還知道了這條指令在虛擬內存中的地址。
其實我們的目的非常簡單,就是把je
指令換成jne
指令。到目前為止,只剩三步。
算出je
指令的二進制碼。
算出jne
指令的二進制碼。
在二進制文件中,把算出je
指令的二進制碼換成算出jne
指令的二進制碼。
幸好,gdb調試器能夠為我們做前兩步。免去了我們完全不熟悉的從匯編到二進制碼轉換的過程。gdb調試器有一個x/x
命令,可以讀取給定內存地址中的數據。
我們知道,程序運行的過程,簡單來說其實就是二進制碼從硬盤加載進內存,然后從程序入口開始運行的過程。我們不是匯編器,不善于做靜態的、從匯編碼到二進制碼的轉換工作。但是gdb調試器允許我們動態地、逆向的從內存中找到二進制碼。
所以,距離成功還差最后一步!
所以,執行:
x/x 0x00000001000cdfaf
可以得到如下的結果:
0x1000cdfaf <_mh_execute_header+843695>: 0x83480774
這里的0x83480774就是16進制格式的程序二進制碼。接下來就可以打開Hex friend軟件對二進制碼進行修改了。Hex friend把應用程序以16進制的形式展現出了,支持查找、替換功能。
按下Command + F
進行查找。
特別需要注意點是字節序問題(Byte Order),Intel處理器一般是以小端(Little endian)進行存儲,而在硬盤上的二進制碼,則是以大端(Big endian)存儲。所謂的大端,就是把數字的最高位放在最前面,小端則是把最高位放在最后面。
也就是說0x83480774作為一個小端數,它的大端形式應該是74074883,點擊Replace & Find按鈕之后,很不幸的事情出現了:這個數字不止出現了一次。
解決方案很簡單,用同樣的方法,看看下一條指令的的二進制碼就可以了。執行:
0x1000cdfb1 <_mh_execute_header+843695>: 0x83480774
得到:
0x1000cdfaf <_mh_execute_header+843695>: 0x08c48348
用大端表示就是4883c408,這個數字的前四位和之前的數字的后四位剛好是相同的。這個不是巧合,因為不同的指令,二進制碼長度不同。而gdb的x/x
指令總是讀取相同長度的內存中的數據。
這一點并不影響破解Paw,但是如果想了解的非常透徹的話,可以用otx
命令查看:
可以看到其實eq
指令的實際二進制碼是7407。
現在終于確定了要被替換的數字式74074883c408,這里面包含了eq
指令的二進制碼和接下來一些指令的二進制碼。這些多余信息是為了唯一確定這組數的位置的。
“7407”由“74”和“07”兩部分組成,查閱相關資料或者多找幾個其他的eq
指令和enq
指令可以知道,eq
指令的二進制碼是“74”而eq
指令的二進制碼是“75”。
所以用來替換的數應該就是“75074883c408”。在Hex friend中填寫好相關數據后選擇Replace并保存。如圖所示:
至此,整個破解的過程就完成了。其實細想一下,我們只是把一個4換成了5而已!
用修改過后的二進制文件替換原來文件后,打開程序總是會立刻報錯。如果在命令行中運行,還可以看到killed 9的提示。
這是因為蘋果為了保證軟件的安全加入了代碼簽名(CodeSignature)機制。在Contents文件夾下可以找到_CodeSignature文件夾和其中的CodeResources文件。任何對二進制文件的修改,都無法通過代碼簽名的檢查。
關于代碼簽名的具體解釋,和操作過程,可以看這篇文章:
《How to re-sign Apple’s applications once they’ve been modified》
文章把每一步都描述得非常透徹,我就不重述了。按照文章所描述的,建立好自己的簽名證書后,只要執行這條命令:
codesign -f -s 證書名 /Applications/PawCrack.app/Contents/MacOS/Paw
其中證書名寫自己創建的證書的名字,一切順利的話,會得到這樣的提示: /Applications/PawCrack.app/Contents/MacOS/Paw: replacing existing signature
代碼重簽名完成之后,就可以成功打開破解之后的App了。
打開App之后我們可以發現,煩人的Welcome頁不見了。因為反轉了判斷邏輯,所以不執行showWelcomeWindow
方法了。
破解版的app可以在這里找到:Paw破解版
首先回顧一下整個破解過程。準備好工具之后,我們先從頭文件里面搜索可以的方法名,再用反編譯工具查看具體方法的匯編代碼實現。結合基本的匯編語法和偽代碼,了解整個方法的工作原理。最后修改if語句的邏輯從而完成破解。
其實由于大部分針對功能的限制,都是基于if else
語句進行判斷的,也就是說對于相當多的軟件,只要我們分析出它的邏輯,只需要把一個4改成5即可破解。
整個破解過程,除了鞏固了操作系統的基礎知識之外,我覺得對于iOS engineer來說還有一些其他的收獲:
嚴格遵守“迪米特法則”,把不必要對外提供的在.m文件里定義、實現。這樣不僅防止被class-dump掃描到,也能減輕與你合作的同事開發時的負擔。
發布版本gcc編譯時去掉-g
參數。我猜測,正是由于Paw這么做了,導致我無法用gdb調試器加斷點。因為找不到函數的符號名。
對于極為核心的部分,可以做適當的代碼混淆。
做到以上幾點非常輕松,但是足以防止數量廣大,但又技術一般的tinkerer(比如作者本人)的搗鼓了。
《Giving gdb permission to control other processes》
《I Can Crack Your App With Just A Shell》
《How to re-sign Apple’s applications once they’ve been modified》
Beginning Mac Hacking
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。