0x00 序言
這是第二次破解 crackme 小程序,感覺明顯比第一次熟練。破解過程非常順利,差點兒是分分鐘就能夠找到正確的 serial,可是我們的目標是破解計算過程。以下將具體介紹。
0x01 初次執行
剛開始拿到 crackme 先執行程序。看看有哪些明顯的特征。或者有哪些任務須要完畢:
雙擊程序后彈框,顯然第一個任務就是把這個框框弄掉,我們繼續執行:
這個小程序比上次的要復雜,有兩個 serial ,我們先看看左邊的:
不出意外。猜錯了,有明顯的彈框和失敗字符串作為特征。我們接著看右邊的:
不出意外,再次失敗,依舊是彈框。
0x02 開始調試
1、明白目標
通過上面的執行分析,我們須要干掉第一個彈框,以及興許的兩個 serial 。同一時候我們發現三者的共同特征為彈框。所以首先攔截彈框函數:
右鍵代碼區選擇 “serach for” => “All intermodules calls”:
在新窗體中輸入 messageboxa,右鍵。選擇”Set breakpoint on every call to MessageBoxA”:
這樣我們就給全部調用彈框函數的地方下了斷點,接著回到代碼區執行程序。
2、調用者
按 F9 執行到彈框函數處,我們發現此時的棧頂就是第一次彈框時的字符串的地址,于是我們須要找到那個調用彈框函數的函數。叫做調用者。
這里我們往上看,找到當前這個函數的入口并下斷點:
然后我們 Ctrl + F2 又一次加載程序。F9 執行到剛才下斷點的入口:
此時棧頂就是調用者執行call指令時保存的返回點。我們在代碼區中查找這個地址(42F79C),注意單擊代碼區,按 Ctrl + G 進行查找:
看見了嗎,就是這個函數,僅僅有幾句代碼。以下我們就來消滅它。
3、去掉彈框
調用了函數才會彈框,我們的想法就是讓它不調用函數,那么直接讓函數返回是最簡單的方式。于是我們把函數入口處的第一條指令改成RETN
就可以:
單擊指令,按一下空格鍵能夠改動:
此時我們能夠把改動保存到文件里:
右鍵指令,選擇 “Copy to executable” => “selection”:
在新窗體中右鍵選擇 “Save file”:
然后保存:
執行新的程序發現第一次的彈框成功消失。
4、破解右側serial
接下來我們轉到右邊的 serial,輸入隨意字符串。然后點擊button:
我們發現程序停在了彈框函數的入口:
此時棧頂的值就應該是上級函數的返回地址:
我們繼續在代碼區搜索此地址(42F509):
發現了嗎,有推斷條件。能夠看出是字符串比較函數,我們設置斷點。F9 執行究竟后又一次點擊button:
程序停在了斷點處。看看棧區。發現給函數的參數中的字符串:
破解起來確實非常輕松,字符串是固定的:Hello Dude!
5、破解左側 serial
我們繼續執行,轉到左側。輸入隨意字符串后點擊button:
依據剛才的方式找到調用者返回地址:42FB37
查找代碼區:
發現字符串比較函數并下斷點。此時查看棧區:
再往上看代碼區:
我們能夠猜測出 serial 是 “CW-” + 某個數 + “CRACKED”,中間的數是我們須要找的目標。
6、真實的目標
我們給 serial 生成函數的入口下一個斷點,然后又一次點擊button執行到斷點處 F8 單步走:
中間發現兩段代碼:
EAX = name[0] * 7 + name[1] * 0x10;
EAX = name[3] * 0xB + name[2] * 0xE
繼續向下執行,發現另外一段代碼:
函數入口的以下有一句不起眼的代碼:
兩個結合起來就是:
EAX = name[0] * 0x29 * 2;
后面我們發現調用字符串輸出函數之前 EAX 的值被置為那個內存單元的值:
繼續往下調試結果就非常明顯了,第三段代碼才是我們要的。
0x03 雙重檢測
1、簡單粗暴的 C語言
代碼例如以下:
#include <stdio.h>int main()
{char name[1024];printf("Input your name: ");scanf("%s", name);printf("Serial: CW-%d-CRACKED\n", name[0] * 0x29 * 2);return 0;
}
執行結果:
2、原程序檢驗
0x04 總結
這個小程序左邊的 serial 和 name 的第一個字符有關,而且字符串長度不能小于4.