在這一章裡頭,我們要來做一個練習,那就是來修改字串HelloWorld。
那這要怎麼做呢?很簡單,讓我們來看一下這支程式。
程式的執行結果如下:
甚至是把所有的 HelloWorld 給全部黑掉,那我應該要怎麼做才好呢?
答案很簡單,我們說記憶體裡頭的機械碼(反組譯碼,或可以說是 PE)主宰著底層的一切。
也因此,只要修改了記憶體裡頭的機械碼不就能夠在不修改原程式碼的情況之下當場讓整隻程式發生變化嗎?
我們現在的思路就是回到Visual Studio裡頭並且看機械碼(PE)的情況。
修改記憶體位址當中的機械碼。
老樣子,讓我們在程式旁加上斷點,之後執行偵錯後立刻到反組譯碼的地方去。
在圖中,真正的重點在於函數
printf("HelloWorld\n");
printf("HelloApple\n");
也就是從記憶體位址 00412CFE 一直到記憶體位址 00412D27 間都是我們要注意的地方。
還記得我們在前面曾經說過的內容嗎?字串是以偏移量的形式給壓進堆疊裡頭去的。
因此,讓我們找出字串的記憶體位址0x00415808,並且在記憶體的地方輸入記憶體位址0x00415808之後按下鍵盤上的Enter:
接著我們搜尋到記憶體以及記憶體當中的機械碼與所對應到的字串,請看 PE 內容:
這部份的機械碼48 65 6c 6c 6f 57 6f 72 6c 64 對應到字串HelloWorld,
所以等一下我要把機械碼48 65 6c 6c 6f 57 6f 72 6c 64給修改掉,讓它對應到HelloApple。
好接下來,讓我們看看HelloApple在記憶體位址中的地方,也就是記憶體位址 0x004157AC:
讓我們注意一個地方:
這部份的機械碼48 65 6c 6c 6f 41 70 70 6c 65對應到字串HelloApple。
我們說既然想要把字串HelloWorld給變成HelloApple的話,那我只要把 HelloApple的機械碼給拿來取代HelloWorld的機械碼之後,再讓程式重新執行,這時程式一定只會出現 HelloApple。//沒意外的話 XD
好,現在就讓我們先記住這段機械碼48 65 6c 6c 6f 41 70 70 6c 65,
讓我們回到記憶體位址0x00415808的地方去:
然後把滑鼠點到機械碼57的地方:
然後從57的地方開始把依序把機械碼41 70 70 6c 65也就是 Apple的部分給填上去:
最後請注意下列這三者之間的關係:
原本的字串HelloWorld在經過對記憶體的機械碼給修改過後,現在已經變成HelloApple!
現在,讓我們按下Visual Studio上的偵錯->繼續
這時候我們已經證明了字串修改的結果!
修改push字串的位址,讓我們回到這張圖:
我們說,字串HelloWorld是位於記憶體位址0x00415808當中,而字串
HelloApple則是位於記憶體位址0x004157A8當中,以及輸出想要的字串時是以「push+字串位址」的方式來執行,因此,我只要修改「push+字串位址」當中的字串位址之後,我就可以把我所想要的字串給調換過來了。
既然我現在打算要把HelloWorld給換成HelloApple的話,那我就看記憶體位址
00412D00的地方(因為這段是push HelloWorld的程式碼):
請注意:
在記憶體位址0x00412D00的地方是機械碼 68 08 58 41 00,這一段機械碼用小端法讀回來之後,內容是這樣子的:
68 08 58 41 00 -> push 記憶體位址00415808
而字串HelloWorld就是位於記憶體位址 0x00415808 當中,因此,我只要把這一段機械碼:
68 08 58 41 00 給修改成 68 A8 57 41 00 的話
那此時的機械碼68 A8 57 41 00 就會對應到 HelloApple,因為HelloApple則是位於記憶體位址0x004157A8當中。
好,既然如此,那我們現在就來修改看看,請把滑鼠移到機械碼08的地方
然後依次修改機械碼如下:
修改後請注意看這裡:
我們已經把原本的字串 HelloWorld給修改成我們要的 HelloApple。
現在,就讓我們來證明這一點,請點選 Visual Studio上的偵錯-> 繼續。
前面的介紹都只是在講調換。
現在,我們在這裡要講的內容是黑掉,也就是無效。
在組合語言當中,無效的機械碼是90,90這個數值非常好用,尤其是在跳過邏輯判斷是上,90可以說是幫我們起到很大的作用,這我們以後再說,我們先看簡單的應用就好。
回到我們的 HelloWorld:
假如我們不想讓這段文字出現的話,那我們該怎麼做?這時候又是從機械碼的地方來下手,我們先進行偵錯後直接進入反組譯碼的部份:
請注意這裡:
這時候我們用機械碼90來把字串HelloWorld給黑掉:
這時候點選偵錯->繼續
當然如果換成00的話那就全部都不見了:
所以,修改 PE 的內容,那麼程式內部的內容也是能跟著修改的。
不過,前提是要花很大的耐心跟時間去解讀檔案裡面的內容…
兩點補充:
1.HelloWorld和HelloApple長度相同,如果不同時如何處理?
如果是HelloAda還容易,把\x00補在\x0a後面即可
如果是HelloAngelaBaby時,怎麼做呢?
2.0x90 的應用
在PC單機遊戲還用密碼防盗版的年代
有些照書本規定寫結構化程式的軟體
會把檢查帳號密碼寫成一段副程式
以致最後產生的 code
會類似像 CALL checkid 這樣
此時只要把 CALL checkid 那段
改成幾個 0x90(NOP)
就可以不用每次輸入帳號密碼玩遊戲了
還有一點小小建議
由於 2017 鐵人賽已經結束
分享文章時
可以考慮使用別的標題/tag 了
(1) 那就看字串長短了 還是能看到 PE 裡面會有脈絡可尋的嘛 =v=+
(2) 嗚嗚我沒實驗過這塊,不過倒是有看過大大試著在 BIOS 前把病毒碼載進去的寫法,聽海綿寶寶大大這樣說,好像也能來破解正式版本的License 驗證部份… (?
跟插在printer port的keypro一樣
這種保護軟體的技術
已經很少人(沒有人)在用了
或者說
現在保障軟體版權的觀念和做法
已經跟以往大為不同了
說到底
連我都知道的技術
不會有人還這麼天真在使用的
可是對岸論壇還是有不少破解文的方式都是用這種方式寫的啦…
像說 sublime …
所以這篇的實作重點可以伸延出,改 PE 然後去改程式執行的結果 XD