ePublisher Gold v1.4 (9千字)

看雪資料發表於2001-01-15

URL: search in http://www.google.com

首先找到判斷註冊碼的地方,如下。檔案Reg.dat顯然是用來存放註冊碼的。
//---------------------------------------------------------------------------
* Possible StringData Ref from Code Obj ->"Reg.dat"
                                  |
:0045EB77 BA84EC4500              mov edx, 0045EC84
:0045EB7C E83F50FAFF              call 00403BC0
:0045EB81 8B952CFEFFFF            mov edx, dword ptr [ebp+FFFFFE2C]
:0045EB87 8D8530FEFFFF            lea eax, dword ptr [ebp+FFFFFE30]
:0045EB8D E8F06BFAFF              call 00405782
:0045EB92 8D8530FEFFFF            lea eax, dword ptr [ebp+FFFFFE30]
:0045EB98 E8116EFAFF              call 004059AE
:0045EB9D E8DA3BFAFF              call 0040277C
:0045EBA2 8B55FC                  mov edx, dword ptr [ebp-04]
:0045EBA5 8D8530FEFFFF            lea eax, dword ptr [ebp+FFFFFE30]
:0045EBAB E84053FAFF              call 00403EF0
:0045EBB0 E8486CFAFF              call 004057FD
:0045EBB5 E8C23BFAFF              call 0040277C
:0045EBBA 8D8530FEFFFF            lea eax, dword ptr [ebp+FFFFFE30]
:0045EBC0 E85F6CFAFF              call 00405824
:0045EBC5 E8B23BFAFF              call 0040277C
:0045EBCA E8C1FBFFFF              call 0045E790
:0045EBCF 84C0                    test al, al
:0045EBD1 745B                    je 0045EC2E

* Possible StringData Ref from Code Obj ->"Thank you for registering "
                                  |
:0045EBD3 BA8CEC4500              mov edx, 0045EC8C
:0045EBD8 8D8528FDFFFF            lea eax, dword ptr [ebp+FFFFFD28]
:0045EBDE E8513DFAFF              call 00402934
:0045EBE3 8D8528FCFFFF            lea eax, dword ptr [ebp+FFFFFC28]
:0045EBE9 50                      push eax

* Reference To: epgname.ShellExecuteA, Ord:0001h
                                  |
:0045EBEA E829EBFFFF              Call 0045D718
:0045EBEF 8D9528FCFFFF            lea edx, dword ptr [ebp+FFFFFC28]
:0045EBF5 8D8528FDFFFF            lea eax, dword ptr [ebp+FFFFFD28]
:0045EBFB E80C3DFAFF              call 0040290C
:0045EC00 BAA8EC4500              mov edx, 0045ECA8
:0045EC05 8D8528FDFFFF            lea eax, dword ptr [ebp+FFFFFD28]
:0045EC0B E8FC3CFAFF              call 0040290C
:0045EC10 8D9528FDFFFF            lea edx, dword ptr [ebp+FFFFFD28]
:0045EC16 8D852CFEFFFF            lea eax, dword ptr [ebp+FFFFFE2C]
:0045EC1C E83B4FFAFF              call 00403B5C
:0045EC21 8B852CFEFFFF            mov eax, dword ptr [ebp+FFFFFE2C]
:0045EC27 E82CEDFEFF              call 0044D958
:0045EC2C EB0A                    jmp 0045EC38

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045EBD1(C)
|

* Possible StringData Ref from Code Obj ->"You entered an incorrect registration "
                                        ->"key.  Please try again."
                                  |
:0045EC2E B8B4EC4500              mov eax, 0045ECB4
:0045EC33 E820EDFEFF              call 0044D958
//-----------------------------------------------------------------------------------------------
跟進上面的call 0045E790(IDA告訴我們上述程式碼是TOrderForm的成員函式OkButtonClick( )的一部分)。這裡
它兩次呼叫LStrPos( )函式檢查同一個位元組串中是否同時包含字串“v:1.0”和“m:g”,如果是的話則返回1,
表明註冊碼正確。
//------------------------------------------------------------------------------------------------
sub_45E790    proc near        ; CODE XREF: _TOrderForm_OkButtonClick+166
                    ; sub_45F098+1F ...

var_4        = dword    ptr -4

        push    ebp
        mov    ebp, esp
        push    0
        push    ebx
        xor    eax, eax
        push    ebp
        push    offset loc_45E7EA
        push    dword ptr fs:[eax]
        mov    fs:[eax], esp
        lea    eax, [ebp+var_4]
        call    sub_45E51C
        mov    edx, [ebp+var_4]
        mov    eax, offset _str_v_1_0.Text
        call    @System@@LStrPos$qqrv ;    System __linkproc__ LStrPos(void)
        test    eax, eax
        jle    short loc_45E7CE
        mov    edx, [ebp+var_4]
        mov    eax, offset _str_m_g.Text
        call    @System@@LStrPos$qqrv ;    System __linkproc__ LStrPos(void)
        test    eax, eax
        jg    short loc_45E7D2

loc_45E7CE:
        xor    ebx, ebx            //返回0
        jmp    short loc_45E7D4
loc_45E7D2:
        mov    bl, 1                //返回1

loc_45E7D4:
        xor    eax, eax
        pop    edx
        pop    ecx
        pop    ecx
        mov    fs:[eax], edx
        push    offset loc_45E7F1

loc_45E7E1:
        lea    eax, [ebp+var_4]
        call    @System@@LStrClr$qqrr17System@AnsiString
        retn

loc_45E7EA:
        jmp    @System@@HandleFinally$qqrv
loc_45E7F1:
        mov    eax, ebx
        pop    ebx
        pop    ecx
        pop    ebp
        retn
sub_45E790    endp

        align 4
_str_v_1_0    dd 0FFFFFFFFh        ; _top ; DATA XREF: sub_45E790+1F
        dd 5            ; Len
        db 'v:1.0',0            ; Text
        align 4
_str_m_g    dd 0FFFFFFFFh        ; _top ; DATA XREF: sub_45E790+30
        dd 3            ; Len
        db 'm:g',0              ; Text
//-----------------------------------------------------------------------------------------------
對上面所檢查的那個位元組串設一個“BPM xxxxxxxx W”斷點,看一下該位元組串是如何來的。最終會發現它是
根據我們輸入的假註冊碼變換得來的。這說明我們的假註冊碼經過變換之後應包含字串“v:1.0”和“m:g”。

下面要做的就是把這個變換搞清楚。經過跟蹤,發現它先是把我們輸入的註冊碼作為密文,用blowfish演算法
對其進行解密,然後再將解密所得到的明文與一個固定的位元組串(DB, 35, 25, 0A, 90, E8, 3C, 9D,...,
該串是blowfish演算法產生的中間值)逐位元組進行異或,異或的結果中應包含字串“v:1.0”和“m:g”。
所以註冊碼應有很多個。

識別blowfish演算法的一種方法就是靠它的那些常數表格,只要在記憶體中看到這些常數,基本上就可以確定
是blowfish演算法(當然最終要分析演算法本身才能確定)。例如blowfish的P-陣列是18個32-bit的子金鑰:
static const unsigned long P[16 + 2] =
{
        0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L,
        0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L,
        0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL,
        0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L,
        0x9216D5D9L, 0x8979FB1BL
};
其4個S-盒則包含共1024個32-bit的數。實際上該程式的反彙編列表中包含“Blowfish: Invalid key size - %d”、
“Blowfish: Not initialized”、“TDCP_blowfish”等含義明顯的串,隱約也可以猜到。

識別出是blowfish演算法之後,只需要知道下面幾個東西就可以將其解開:
1、金鑰。
2、使用的是加密演算法還是解密演算法。
3、演算法的輸入或輸出值所要滿足的條件。
因為數學家已經告訴了我們blowfish演算法的加密和解密演算法,我們並不需要去發明其逆演算法(即使想破腦袋也想不出來的)。

如何找到第1個條件(即金鑰)呢?因為該演算法在初始化的時候要將P-陣列和金鑰進行迴圈異或,所以只要對最初的
P[0](值為0x243F6A88L)設個BPM斷點,就可以看見異或的地方,從而找到16位元組的金鑰:
Key = { 0x00, 0x37, 0x25, 0x5E, 0x76, 0x6B, 0x44, 0x30,0x7B, 0x5C, 0x7E, 0x73, 0x63, 0x26, 0x4D, 0x40};
//----------------------------------------------------------------------------------------------------
:0045C4AC 33FF                    xor edi, edi
:0045C4AE 33DB                    xor ebx, ebx

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045C505(C)
|
:0045C4B0 8D4703                  lea eax, dword ptr [edi+03]
:0045C4B3 99                      cdq
:0045C4B4 F77DFC                  idiv [ebp-04]
:0045C4B7 8B45F8                  mov eax, dword ptr [ebp-08]
:0045C4BA 33C9                    xor ecx, ecx
:0045C4BC 8A0C10                  mov cl, byte ptr [eax+edx]          //金鑰
:0045C4BF 8D4702                  lea eax, dword ptr [edi+02]
:0045C4C2 99                      cdq
:0045C4C3 F77DFC                  idiv [ebp-04]
:0045C4C6 8B45F8                  mov eax, dword ptr [ebp-08]
:0045C4C9 0FB60410                movzx eax, byte ptr [eax+edx]      //金鑰
:0045C4CD C1E008                  shl eax, 08
:0045C4D0 03C8                    add ecx, eax
:0045C4D2 8D4701                  lea eax, dword ptr [edi+01]
:0045C4D5 99                      cdq
:0045C4D6 F77DFC                  idiv [ebp-04]
:0045C4D9 8B45F8                  mov eax, dword ptr [ebp-08]
:0045C4DC 0FB60410                movzx eax, byte ptr [eax+edx]        //金鑰
:0045C4E0 C1E010                  shl eax, 10
:0045C4E3 03C8                    add ecx, eax
:0045C4E5 8B45F8                  mov eax, dword ptr [ebp-08]
:0045C4E8 0FB60438                movzx eax, byte ptr [eax+edi]        //金鑰
:0045C4EC C1E018                  shl eax, 18
:0045C4EF 03C8                    add ecx, eax
:0045C4F1 318C9E50100000          xor dword ptr [esi+4*ebx+00001050], ecx //與P-陣列異或
:0045C4F8 8D4704                  lea eax, dword ptr [edi+04]
:0045C4FB 99                      cdq
:0045C4FC F77DFC                  idiv [ebp-04]
:0045C4FF 8BFA                    mov edi, edx
:0045C501 43                      inc ebx
:0045C502 83FB12                  cmp ebx, 00000012                      //P-陣列有18個數
:0045C505 75A9                    jne 0045C4B0
//--------------------------------------------------------------------------------------------
至於第2個條件,根本不用分析其演算法,只需要自己寫個程式把加密和解密演算法都呼叫一下,並將輸出和
該軟體的演算法輸出對比一下就知道採用的是解密演算法。

第3個條件比較簡單,即blowfish演算法的輸入為假註冊碼,輸出與一固定位元組異或之後應包含“v:1.0”和“m:g”。


異或在如下的地方進行,在這裡可以找到所需的固定位元組串:
//--------------------------------------------------------------------------------------------
:0045B6CF 33F6                    xor esi, esi

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045B6DF(C)
|
:0045B6D1 8A1C30                  mov bl, byte ptr [eax+esi]
:0045B6D4 321C32                  xor bl, byte ptr [edx+esi]
:0045B6D7 8B7DFC                  mov edi, dword ptr [ebp-04]
:0045B6DA 881C37                  mov byte ptr [edi+esi], bl

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0045B724(C)
|
:0045B6DD 46                      inc esi
:0045B6DE 49                      dec ecx
:0045B6DF 75F0                    jne 0045B6D1
//--------------------------------------------------------------------------------------------
有興趣的自己寫keymaker吧。

相關文章