003-Cruehead-CrackMeV3

ㅤ浮虛千年發表於2023-03-27

第二個需要寫序號產生器
首先檢視檔案,開啟檔案,什麼也沒有,help ->about,彈出下面的彈窗

看來是沒有什麼線索,直接放進OD裡面

這裡有一個函式CreatFileA,這個函式目的是訪問一個檔案,如果檔案不存在返回值為-1
HANDLE CreateFile(
LPCTSTR lpFileName, //指向檔名的指標
DWORD dwDesiredAccess, //訪問模式(寫/讀)
DWORD dwShareMode, //共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全屬性的指標
DWORD dwCreationDisposition, //如何建立
DWORD dwFlagsAndAttributes, //檔案屬性
HANDLE hTemplateFile //用於複製檔案控制程式碼
);
跟下去看,可以看到函式執行完成後會返回一個-1到eax,下一條指令cmp捕獲到後讓ZF位變成0,後面的jnz指令就沒辦法跳轉了

如果沒有這個檔案的話就沒有辦法繼續下去了,所以我們在同目錄下新建一個同名稱檔案(CRACKME3.KEY),而且在裡面寫入字串,重新開始除錯

重新除錯後就不會返回-1了

繼續,接下來又呼叫了一個ReadFile函式把檔案裡面的字串放進暫存器ebx和記憶體空間裡面

而且可以看到,這個函式到這裡只擷取了到r的字元,也就是說前18個擷取到了,後面8個暫時沒有管
繼續往下,有一個陌生的call,由於不清楚這個call的用處,所以f7跟進

前面兩個xor清空暫存器,之後把push進來的引數,也就是18個字元給esi,然後給bl數值41,之後就是一串迴圈

迴圈是根據cl的大小來判斷的,迴圈內部有bl的自加演算法,如果bl裡面的數等於4f就會跳出迴圈,之前給bl的數是41,也就是說這個迴圈會執行4f-41=14次
看一下這個程式碼,首先以位元組的大小把剛才esi裡面傳入的字元給到al,然後將bl裡面的數和al裡面的數進行異或,異或完了之後再將它傳給esi。
我們來看第一次異或後得到的結果,第一次是a的ascall碼和41異或

得到了0x20,然後我們再搜尋0x20的ascall碼的含義

在鍵盤上是space,以字元的形式顯示就是空格
b的ascall碼和0x42(每次迴圈bl自加1)異或得到的結果也是0x20,所以前十四個字元在迴圈過後都顯示為空格。

再看另外一個指令

這個是把前14個字元的ascall碼加到0x4020f9這個地址上,原本地址裡面數字是00,加上14次之後就變成了0x01c0這個十六進位制數

那這個迴圈就沒有什麼其他含義了,往下走

可以看見剛出call後,剛才的4020f9這個地址就和12345678進行了一次異或,異或完了之後這個地址裡面的數變成了123457b8,之後又進了一個call

這個call也是不清楚什麼含義,f7進去看看之後發現是給esi賦值opqr,然後把123457b8(即所有輸入進去字元中的前14個字元的ascall碼的和異或上0x12345678之後得到的數)和opqr進行比較,如果相同就進行跳轉。

而跳轉是跳轉到了破解成功的彈窗上,那麼我們就明白了key檔案裡面的後4位字元和前面的14位字元的關係,後4位字元就是前面14位字元的ascall碼和異或上0x12345678得到的
理清了思路,我們就可以寫序號產生器制作key檔案破解程式了
下面是序號產生器的指令碼

username = input("please input your username:").center(14)

if len(username) > 14:
    print("error,please input number less 14")
    exit(0)

    #先用username和0x41開始異或
tem_ = 0
xor_use = []
sum = 0

for i in range(len(username)):
    tem = ord("A") + i
    xor_use.append(tem ^ ord(username[i]))
    #還有連加異或後得到的結果
    sum += ord(username[i])

key = sum ^ 0x12345678
key_bytes = bytes(key.to_bytes(4,byteorder='little'))
with open('CRACKME3.KEY',"wb+") as f:
    #把前十四個加密後的字元輸入進去,然後把後四位需要進行比較的字元也輸入進去,即可搞定key檔案註冊
    f.write(bytes(xor_use))
    f.write(bytes(key_bytes))


print("it is ok!")

當然,這個程式也能破解,不過破解難度會比較大,有時間的話會更新