Cast-128 加密演算法和 MyPassWord 的破解

看雪資料發表於2004-11-22

Cast-128 加密演算法和 MyPassWord 的破解


1. Cast-128 加密演算法概述

    Cast-128 加密演算法是一種類似於DES的置換組合網路(Substitution-Permutation Network,SPN)加密系統,對於微分密碼分析、線性密碼分析、密碼相關分析具有較好的抵抗力。這種加密還有其他的幾個理想的特點,包括雪崩、嚴格的雪崩標準(SAC)、位獨立標準(BIC)、沒有互補屬性也不存在軟弱或者半軟弱的金鑰。因此對於整個Internet社群――要求密碼強壯、容易獲取的加密演算法――而言,這是一種能夠滿足一般應用的很好的選擇。

    整個加密過程分為金鑰預處理和資訊加密兩個過程。金鑰預處理過程是根據輸入的 128 位金鑰,透過一系列的S-盒置換生成 16 對子金鑰。資訊加密是把輸入的 64 位資訊分為左右兩半 L0 和 R0,透過一系列的迴圈變換生成 L16 和 R16,然後連線 L16 和 R16 就是輸出的密文。對 Cast-128 演算法解密也要分為金鑰預處理和資訊解密兩個過程。金鑰預處理和加密的時候完全相同,輸入的金鑰表也一樣。而資訊解密是把加密時的一系列迴圈變換倒過來,按相反的順序從 L16 和 R16 計算出 L0 和 R0。(Cast-128 演算法的具體描述請參考 RFC2144)

    所以要想破解採用 Cast128 演算法的軟體,關鍵是找到金鑰預處理時用到的金鑰表,有了金鑰表就可以根據密文解密出明文,一般而言也就是我們要找的註冊碼。而且要寫一個序號產生器也不是難事。

2. 例項分析:MyPassWord 的破解

    MyPassWord 是一款私人密碼管理軟體,可以幫助大家管理各種各樣的密碼,在《黑防》2004 年 1 月刊中有介紹。軟體管理帳戶資訊應該是採用了 MD5 演算法進行驗證,如果跳過帳戶驗證開啟別人的密碼檔案得到的只是一些看不懂的亂碼。軟體沒註冊會在每次開啟的時候提示使用了多少次,提醒大家註冊。

    先用 PEiD 檢視一下加了殼沒有,加了殼就先脫殼,沒加殼就看看採用了什麼加密演算法。檢測一下發現 ASPack 2.12 -> Alexey Solodovnikov,既然是 ASPack 的殼那就不客氣了,利用 stripper v2.07 脫殼機很方便的就可以把殼脫掉。脫殼後再次用 PEiD 檢測一下,發現軟體是用 Delphi6.0 編寫的,採用了 Cast 和 MD5 加密演算法。

    這裡要說一句,每次拿到一個軟體先用 PEiD 和 FileInfo 等工具探測一番不失為一個好的習慣,可以節省時間對症下藥(什麼殼要脫,什麼語言用什麼工具對付,什麼演算法要不要複習看看書)。好,知道了是 Delphi 編寫的軟體,當然是先用 DeDe 反彙編尋找關鍵的程式碼。反彙編後找到“註冊”對話方塊中的“註冊”按紐的單擊響應程式碼位置在 0x004F0B60,“註冊”對話方塊的初始化程式碼在 0x004F0D18 處。

    DeDe 的工作做完後再開啟 Ida Pro 反彙編,這個工具不單是靜態反彙編之王,現在加入了動態除錯的功能更是讓人愛不釋手。不但可以把變數改成容易理解的名字,還可以把分析過的程式碼寫上註釋,碰到一個過程可以先進去看看再決定是需要跟進還是直接帶過,關鍵的過程可以知道被幾個地方呼叫了,識別出了大部分的庫函式使得程式碼更容易理解和更容易除錯(不需要跟進該函式就能知道函式實現的功能),不過反彙編的時間有一點點長。

    反彙編結束後,在 0x004F0B60 處按 F2 下斷點,按 F9 執行軟體。在“註冊”對話方塊中會發現“序列號”欄已經填寫了一些字元,現在先不管它,在“註冊碼”欄輸入 123456789 然後按“註冊”按紐。程式中斷在 0x004F0B60 處,跟蹤一下發現輸入的長度有要求,在“註冊碼”欄重新輸入 1234567890abcdef 然後按“註冊”按紐。中斷後跟蹤一下會來到如下程式碼處:

    CODE:004F0BBB mov     eax, [ebp+var_10]             ;[eax]="1234567890abcdef"
    CODE:004F0BBE lea     ecx, [ebp+var_C]
    CODE:004F0BC1 mov     edxds:dword_55E6D8
    CODE:004F0BC7 call    sub_54B2F8
    CODE:004F0BCC mov     eax, [ebp+var_C]              ;[eax]==0D4h,15h,6Dh,0D8h,3Ch,0B7h,0F8h
    CODE:004F0BCF mov     edxds:dword_55E4C4
    CODE:004F0BD5 mov     edx, [edx]                    ;[edx]=="49988800"
    CODE:004F0BD7 call    @@LStrCmp                     ;比較 eax 和 edx 所指向的內容是否相同
    CODE:004F0BDC jz      short loc_4F0BEF              ;如果更改這個跳轉會發現彈出訊息框說註冊成功

    所以 call sub_54B2F8 肯定是關鍵的過程,跟進。又是經過一番細細的跟蹤來到如下程式碼處:

    CODE:0054B39C lea     ecx, [ebp+var_20]
    CODE:0054B39F mov     edxedi
    CODE:0054B3A1 mov     eax, [ebp+var_10]             ;[eax]="1234567890abcdef"
    CODE:0054B3A4 call    sub_54B1B0
    CODE:0054B3A9 mov     edx, [ebp+var_20]             ;[edx]==0D4h,15h,6Dh,0D8h,3Ch,0B7h,0F8h

    跟進 call sub_54B1B0,馬上就會看到這樣一個過程 CODE:0054B1F3 call sub_4BD5A8。如果先進去看看會發現很像 Cast-128 演算法的金鑰預處理過程,首先是在程式碼的註釋(這個是 Ida Pro 自動產生的)中居然看到如下字元:

    CODE:004BD5C4 mov     ecx, offset aCast128KeyMust     ; "Cast128: Key must be between 1 and 16 b"...
    CODE:004BD5C9 mov     dl, 1
    CODE:004BD5CB mov     eaxds:dword_40881C
    CODE:004BD5D0 call    CreateExcept

    看到沒,Cast128: Key must ... ,就是它,明明白白的指出了這是 Cast-128 的金鑰預處理過程。我記得上次跟蹤資料收藏大師 v3.73時也看到一樣的字元,看來它們都採用了同一個人寫的 Cast-128 演算法模組。初步斷定了這是 Cast-128 的金鑰預處理過程,但也不能排除軟體作者迷惑我們的可能性。繼續往下看:

    CODE:004BD61E cmp     edi, 0Ah
    CODE:004BD621 jg      short loc_4BD62F
    CODE:004BD623 mov     dword ptr [ebx+90h], 0Ch
    CODE:004BD62D jmp     short loc_4BD639
    CODE:004BD62F ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    CODE:004BD62F 
    CODE:004BD62F loc_4BD62F:                             ; CODE XREF: sub_4BD5A8+79j
    CODE:004BD62F mov     dword ptr [ebx+90h], 10h

    上面這段程式碼就是根據金鑰表的長度設定資訊加密時是採用 12 迴圈還是 16 迴圈。

    CODE:004BD713 mov     edx, [esi+0Ch]
    CODE:004BD716 mov     ecxedx
    CODE:004BD718 shr     ecx, 10h
    CODE:004BD71B and     ecx, 0FFh
    CODE:004BD721 mov     ecxds:sbox5[ecx*4]
    CODE:004BD728 xor     ecx, [esi]
    CODE:004BD72A mov     ediedx
    CODE:004BD72C and     edi, 0FFh
    CODE:004BD732 xor     ecxds:sbox6[edi*4]
    CODE:004BD739 mov     ediedx
    CODE:004BD73B shr     edi, 18h
    CODE:004BD73E xor     ecxds:sbox7[edi*4]
    CODE:004BD745 shr     edx, 8
    CODE:004BD748 and     edx, 0FFh
    CODE:004BD74E xor     ecxds:sbox8[edx*4]
    CODE:004BD755 mov     edx, [esi+8]
    CODE:004BD758 shr     edx, 18h
    CODE:004BD75B xor     ecxds:sbox7[edx*4]
    CODE:004BD762 mov     [ebp+var_34], ecx
    ......

    上面的程式碼(省略了大部分)就是用來計運算元金鑰的。知道了 sub_54B1B0 就是 Cast-128 的金鑰預處理過程,把 sub_54B1B0 改名為 Cast128_InitKey 方便後面跟蹤。現在就是找出金鑰預處理過程用到的金鑰表:

    CODE:0054B1E6 lea     eax, [ebp+TCastData]          ;[eax]=TCastData
    CODE:0054B1EC mov     ecx, 10h                      ;ecx=金鑰長度
    CODE:0054B1F1 mov     edxebx                      ;[edx]=金鑰
    CODE:0054B1F3 call    Cast128_InitKey

    來到上面的程式碼處就可以從 edx 中得到金鑰的位置找出金鑰 01h,23h,27h,67h,12h,74h,42h,78h,23h,52h,57h,35h,34h,56h,78h,9Ah 。把金鑰記為 key2,我們寫序號產生器的時候要用到。金鑰預處理完後就是資訊加密,繼續跟蹤程式來到下面的程式碼處:

    CODE:0054B25E lea     ecx, [ebp+var_18]
    CODE:0054B261 lea     edx, [ebp+var_10]             ;[edx]=12h,34h,56h,78h,90h,0ABh,0CDh,0EFh 也就是明文
    CODE:0054B264 lea     eax, [ebp+TCastData]
    CODE:0054B26A call    sub_4BE41C
    CODE:0054B26F lea     eax, [ebp+var_1C]
    CODE:0054B272 call    @@LStrClr
    CODE:0054B277 mov     ebx, 8
    CODE:0054B27C lea     esi, [ebp+var_18]             ;[esi]=0D4h,15h,6Dh,0D8h,3Ch,0B7h,0F8h 也就是密文

    可以看出 sub_4BE41C 過程就是把 edx 中的明文變換成 esi 中的密文,不過 sub_4BE41C 是對應 Cast-128 中的資訊加密過程還是資訊解密過程呢,我們需要繼續分析。跟進 sub_4BE41C 會在開頭的一段程式碼中發現如下的程式碼:

    CODE:004BE4BB cmp     dword ptr [ebx+90h], 0Ch
    CODE:004BE4C2 jle     loc_4BE5F0

    這裡是測試迴圈的次數是 12 次還是 16 次,如果在開頭部分發現這段程式碼,那麼就是資訊解密過程,如果是在過程結尾部分發現這段程式碼,那麼就是資訊加密過程。因為加密程式碼和解密程式碼很相似,只不過是迴圈的順序不一樣,不容易區分。另外也可以自己寫段程式測試一下,看看是加密過程輸出的結果與解密過程輸出的結果哪一個和跟蹤程式時得出的結果一樣。

    知道了 sub_4BE41C 過程就是 Cast-128 演算法的解密過程,可以把 sub_4BE41C 改名為 Cast128_Decode。到這裡我們可以知道,軟體在註冊時把我們輸入的註冊碼透過 Cast-128 解密,然後再把解密後的位元組串與 49988800 作比較。如果一樣,則是合法的註冊碼,註冊成功。如果不一樣,註冊失敗。那麼 49988800 又是如何得出來的呢?我們需要繼續跟蹤分析程式。在兩處呼叫 Cast128_InitKey 的地方下斷點,重新執行程式,會中斷在如下程式碼處:

    CODE:0054B459 lea     eax, [ebp+TCastData]          ;[eax]=TCastData
    CODE:0054B45F mov     ecx, 10h                      ;ecx=金鑰長度
    CODE:0054B464 mov     edxebx                      ;[edx]=金鑰
    CODE:0054B466 call    Cast128_InitKey

    這裡的金鑰和上面的金鑰不同,記為 key1:01h,23h,28h,67h,12h,78h,56h,78h,23h,50h,67h,89h,34h,56h,78h,9Ah。繼續執行,會來到如下程式碼處:

    CODE:0054B54E lea     ecx, [ebp+var_18]
    CODE:0054B551 lea     edx, [ebp+var_18]             ;[edx]=0B4h,46h,6Bh,62h,0E4h,0FCh,53h,13h 也就是序列號
    CODE:0054B554 lea     eax, [ebp+TCastData]
    CODE:0054B55A call    Cast128_Decode
    CODE:0054B55F lea     eax, [ebp+var_20]
    CODE:0054B562 call    @@LStrClr
    CODE:0054B567 mov     ebx, 8
    CODE:0054B56C lea     esi, [ebp+var_18]             ;[esi]="49988800"

    上面這段程式碼把序列號解密得到 49988800。現在我們就可以知道如何註冊:利用 key1 預處理金鑰,然後解密序列號,得到中間變數,再用 key2 預處理金鑰,然後加密中間變數就可以得到註冊碼。序號產生器關鍵程式碼如下:

    invoke  cast_setkey, addr key, addr key1, 16
    invoke  RtlZeroMemory, addr tmp, sizeof tmp
    invoke  cast_decrypt, addr key, addr buf, addr tmp
    invoke  cast_setkey, addr key, addr key2, 16
    invoke  RtlZeroMemory, addr buf, sizeof buf
    invoke  cast_encrypt, addr key, addr tmp, addr buf

    因為在下是一個標準的小菜鳥,錯誤多多還請大家包涵。最後,希望大家的破解水平越來越高。

附件:Keygen.zip

相關文章