IP_tools2.06加密演算法揭祕 ,雁南飛老兄務請一進,呵呵 (30千字)

看雪資料發表於2002-02-13

IP_TOOLS2.06加密演算法揭密
                            
幾周前看見罈子上在討論IP_TOOLS2.06,本菜鳥對IP工具較感興趣,就想拿來試試手,happy一下。
誰知試了一週,花了n個小時(n>40),暈菜無數次,都沒搞定,只好走人咯,鬱悶啊!這陣放假,
本想再試試,整理些資料就算了,沒想到竟還大致搞明白了,暈倒!(由於這個破程式n鬱悶本菜
鳥,本菜不禁多吐了些苦水,各位老兄還請多包涵啊:))好吧,言歸正傳,下面我們開始吧:)

這個檔案註冊失敗會彈出訊息框,偶就想用MessageBox,MessageboxEx以及生成訊息框,對話方塊的那
些API來攔截,沒想到都欄不到,鬱悶偶半天。後來用VC的SPY++看(softice中用hwnd應該也能看得
來),才發現IP_tools中的對話方塊訊息框大多使用他們自己開發的類如TRegisterDlg,TRegisterDlg2,
TMessageForm, 而不是windows自帶的Dialog類。乖乖,敵人的做工還很細噢,菜鳥很佩服的恨恨的說。
(如果有時間,研究一下如何自定義視窗類實現模式對話方塊訊息框的效果倒是很有意思)

用CreateWindowExa倒是可以攔下,不過好像有點怪,菜鳥沒有繼續,就改攔截HMEMCPY了。
windows 9X下,HMemcpy是在16bit保護模式執行,被攔截下時的ES暫存器是目的地址的段selector,
通過softice的GDT ****檢視該段的詳細資訊,段的初始地址就是32位下的目的地址。對這個
地址下bpm跟噢,很快程式就會被這個段點攔截下來,看一下是32位模式下的串拷貝,一般使
用ESI, EDI, 那就接著對EDI-1(或 2,4)(其實減不減都差不多啦)下bpm,繼續跟啊。折騰了半天,
發現了程式進行計算和比較的地方了,算是取得了點階段性的成果,呵呵。不過菜鳥到這花了7,8個小時,
菜啊,傷心噢。菜鳥使用使用者名稱是happy, 密碼是1112222,

注:
*本文中的數字都是16進位制數
*文中有時指標與指標指向的值混用,不過應該能看出來什麼時候是什麼

下面看程式:

CODE:004AC629                mov    eax, [ebp+var_10]     // d eax, 看到使用者名稱happy,
CODE:004AC62C                call    sub_49D94C                //對使用者名稱進行操作,返回加密後
                                的字串長度
CODE:004AC631                mov    edi, eax
CODE:004AC633                lea    edx, [ebp+var_10]
CODE:004AC636                mov    eax, [esi]
CODE:004AC638                mov    eax, [eax+1F4h]
CODE:004AC63E                call    sub_4236DC        
CODE:004AC643                mov    eax, [ebp+var_10]     //d eax, 看到11112222
CODE:004AC646                call    sub_49D9E8        //對密碼進行操作
CODE:004AC64B                cmp    di, ax            
CODE:004AC64E                jnz    loc_4AC7CA        //到了4ac7ca我們就不happy了,
                                 

CODE:004AC654                mov    eax, ds:off_4E128C    //4e128c中存放的是地址4e3434,
                                 是使用者名稱加密後的存放地址
CODE:004AC659                mov    edx, 1FFh
CODE:004AC65E                call    sub_49D930        //對加密後的使用者名稱計算
CODE:004AC663                mov    edi, eax

CODE:004AC665                mov    eax, ds:off_4E1190    //4e1190中存放的是地址4e3634,
                                 是密碼加密後的存放地址
CODE:004AC66A                mov    edx, 1FFh
CODE:004AC66F                call    sub_49D930        //對加密後的密碼計算
CODE:004AC674                cmp    edi, eax            
CODE:004AC676                jnz    loc_4AC7CA

CODE:004AC67C                mov    eax, ds:off_4E128C    //這以下按雙字比較 4e3434+7,
                                  4e3634+7空間中的內容
CODE:004AC681                add    eax, 7
CODE:004AC684                mov    eax, [eax]
CODE:004AC686                mov    edx, ds:off_4E1190
CODE:004AC68C                add    edx, 7
CODE:004AC68F                cmp    eax, [edx]
CODE:004AC691                jnz    loc_4AC7CA

CODE:004AC697                lea    edx, [ebp+var_8]        //三次比較都成功了,註冊成功的對
                                  話框就跳出來了噢

。。。。。
CODE:004AC6D8                mov    eax, offset aThankYouForReg ; "Thank you for registering IP-To"
                                //到這菜鳥才注意到這個字串,要是開始時就
                                查詢這個子串也許省偶很多事噢,心痛心痛!

。。。。。。
CODE:004AC7CA                mov    eax, offset aSorryYourReg_0 ; "Sorry, your registration number or "
                                // game over 的字串!Go to hell!
CODE:004AC7CF                call    sub_444700

先看一下 int 49D930(int i, char *pChar), 該函式對 (pChar+0B)開始的字元竄按字求和, 長度為 i-0B (i=1ff)。


讓我們看一下重要的兩個call 49d94c,49d9e8.

*** 49d94c:
CODE:0049D94C                push    ebp
。。。。。。
CODE:0049D9A8                push    eax
CODE:0049D9A9                push    offset unk_4E3434
CODE:0049D9AE                push    ebx
CODE:0049D9AF                push    offset unk_4DCB62
CODE:0049D9B4                push    offset unk_4DCC62
CODE:0049D9B9                call    sub_49DFFA        //加密的核心函式
CODE:0049D9BE                movsx  eax, al
。。。。。。
CODE:0049D9D8                retn
CODE:0049D9D8 sub_49D94C      endp ; sp = -210h

*** 49d9e8:
CODE:0049D9E8                push    ebp
CODE:0049D9E9                mov    ebp, esp
CODE:0049D9EB                add    esp, 0FFFFFDFCh
CODE:0049D9F1                push    ebx
CODE:0049D9F2                mov    [ebp+var_4], eax
CODE:0049D9F5                mov    eax, [ebp+var_4]
CODE:0049D9F8                call    sub_4040FC
CODE:0049D9FD                xor    eax, eax
CODE:0049D9FF                push    ebp
CODE:0049DA00                push    offset loc_49DA62
CODE:0049DA05                push    dword ptr fs:[eax]
CODE:0049DA08                mov    fs:[eax], esp
CODE:0049DA0B                lea    edx, [ebp+var_204]
CODE:0049DA11                mov    ecx, 1FFh
CODE:0049DA16                mov    eax, [ebp+var_4]
CODE:0049DA19                call    sub_49D880        //將輸入密碼當作16進位制數解讀,
                                如‘11112222’被轉換成4個位元組:
                                11 11 22 22,稱之為密碼1
CODE:0049DA1E                lea    eax, [ebp+var_204]
CODE:0049DA24                push    eax
CODE:0049DA25                push    offset unk_4E3634
CODE:0049DA2A                mov    eax, [ebp+var_4]
CODE:0049DA2D                call    sub_403F48        //計算密碼1的位元組長度
CODE:0049DA32                sar    eax, 1            //計算密碼1的字長度
CODE:0049DA34                jns    short loc_49DA39
CODE:0049DA36                adc    eax, 0
CODE:0049DA39
CODE:0049DA39 loc_49DA39:                            ; CODE XREF: sub_49D9E8+4Cj
CODE:0049DA39                push    eax
CODE:0049DA3A                push    offset unk_4DCD66
CODE:0049DA3F                push    offset unk_4DCE66
CODE:0049DA44                call    sub_49DFFA        //核心加密演算法
CODE:0049DA49                movsx  ebx, al
CODE:0049DA4C                xor    eax, eax
CODE:0049DA4E                pop    edx
CODE:0049DA4F                pop    ecx
CODE:0049DA50                pop    ecx
CODE:0049DA51                mov    fs:[eax], edx
CODE:0049DA54                push    offset loc_49DA69
CODE:0049DA59
CODE:0049DA59 loc_49DA59:                            ; CODE XREF: CODE:0049DA67j
CODE:0049DA59                lea    eax, [ebp+var_4]
CODE:0049DA5C                call    sub_403CCC
CODE:0049DA61                retn
CODE:0049DA61 sub_49D9E8      endp ; sp = -210h

看到這,菜鳥就發暈了,使用者名稱和密碼1竟然都用相同演算法(49dffa)加密,再比較其加密後的值,這不是要
搞出逆演算法才行嗎?過分啊!

下面看 一下49dffa的引數:
sub_49dffa(char * pBuffToCode, char *pDestBuff, int iLenBuffToCode, char *pBuff, char *pLongIntZ)

當進行使用者名稱加密時是:
sub_49dffa('happy', 4e3434, 5, 4dcb62,4dcc62)

當進行密碼1加密時是:
sub_49dffa( '11 11 22 22', 4e3634, 4, 4dcd66, 4dce66)

其中4dce66空間算裝內容與4dcc62完全相同,長度為50h個位元組。4dcd66與4dcb62空間內容不同。


下面我們進 49dffa去看:

sub_49dffa(char * pBuffToCode, char *pDestBuff, int iLenBuffToCode, char *pBuff, char *pLongIntZ)
CODE:0049DFFA                push    ebp
CODE:0049DFFB                mov    ebp, esp
CODE:0049DFFD                push    ebx
CODE:0049DFFE                push    esi
CODE:0049DFFF                mov    esi, [ebp+arg_0]
CODE:0049E002                mov    ebx, [ebp+arg_8]
CODE:0049E005                push    esi
CODE:0049E006                call    sub_49F121    //返回pLoingIntZ指向字串的bit數,
                            從pLongIntZ+2a*2的字的高位元往下
                            找第一個非零bit位,這裡返回280
CODE:0049E00B                pop    ecx
CODE:0049E00C                add    eax, 7
CODE:0049E00F                sar    eax, 3        //計算修正後pLongIntZ位元組數,50
CODE:0049E012                movzx  edx, bx
CODE:0049E015                cmp    eax, edx        //比較iLenBuffTocode與pLongIntZ長度,小等於則繼續
                            //從演算法角度來說,這個比較很有必要噢
CODE:0049E017                jge    short loc_49E01E
CODE:0049E019                or      eax, 0FFFFFFFFh
CODE:0049E01C                jmp    short loc_49E055
CODE:0049E01E ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049E01E
CODE:0049E01E loc_49E01E:                            ; CODE XREF: sub_49DFFA+1Dj
CODE:0049E01E                push    ebx
CODE:0049E01F                push    offset unk_4E3838
CODE:0049E024                push    [ebp+arg_10]
CODE:0049E027                call    sub_49DF4D    //將pBufTofCode 拷到4e3838
CODE:0049E02C                add    esp, 0Ch
CODE:0049E02F                push    esi
CODE:0049E030                push    [ebp+arg_4]
CODE:0049E033                push    offset unk_4E3838
CODE:0049E038                push    offset unk_4E38B8
CODE:0049E03D                call    sub_49F15D    //重點!
CODE:0049E042                add    esp, 10h
CODE:0049E045                push    [ebp+arg_C]
CODE:0049E048                push    offset unk_4E38B8
CODE:0049E04D                call    sub_49DFBA
CODE:0049E052                add    esp, 8
CODE:0049E055
CODE:0049E055 loc_49E055:                            ; CODE XREF: sub_49DFFA+22j
CODE:0049E055                pop    esi
CODE:0049E056                pop    ebx
CODE:0049E057                pop    ebp
CODE:0049E058                retn    14h
CODE:0049E058 sub_49DFFA      endp


下面跟進sub_49f15d(char *pDest, char *pSource, char *pBuff, char *pLongIntZ)
pDest==4e38b8, pSource==4e3838 ;

pSource, pBuff, pLongIntZ說指向的數實際是超長正整數,和一般的32bit的正整數一樣,低位在前,高位在後,
不同是的長度>4,輸入引數最大字數只有28,是pLongIntZ的長度,從而決定操作字竄長度不超過28+2=2a,長度
值存在空間4dcf6a中。sub_49e386用來copy字串,copy字的長度一般是2a。

sub_49F15D      proc near              ; CODE XREF: sub_49DFFA+43p
CODE:0049F15D                                        ; CODE:0049F3DEp ...
CODE:0049F15D
CODE:0049F15D var_88          = byte ptr -88h
CODE:0049F15D var_6          = word ptr -6
CODE:0049F15D var_4          = dword ptr -4
CODE:0049F15D pDest          = dword ptr  8
CODE:0049F15D pSource        = dword ptr  0Ch
CODE:0049F15D pBuff          = dword ptr  10h
CODE:0049F15D pLongIntZ        = dword ptr  14h
CODE:0049F15D
CODE:0049F15D                push    ebp
CODE:0049F15E                mov    ebp, esp
CODE:0049F160                add    esp, 0FFFFFF78h
CODE:0049F166                push    ebx
CODE:0049F167                push    esi
CODE:0049F168                push    edi
CODE:0049F169                mov    ebx, [ebp+pLongIntZ]
CODE:0049F16C                mov    edi, [ebp+pBuff]
CODE:0049F16F                mov    esi, [ebp+pDest]
CODE:0049F172                push    1
CODE:0049F174                push    esi
CODE:0049F175                call    sub_49E3AC
CODE:0049F17A                add    esp, 8
CODE:0049F17D                cmp    word ptr [edi], 0 ;
CODE:0049F17D                                        ;
CODE:0049F17D                                        ;
CODE:0049F181                jnz    short loc_49F1B7    -->跳
。。。
CODE:0049F1B7                cmp    word ptr [ebx], 0
CODE:0049F1BB                jnz    short loc_49F1D4    -->NZ, 跳
。。。
CODE:0049F1D4                movsx  edx, ds:word_4DCF68 ;
CODE:0049F1D4                                        ;
CODE:0049F1DB                cmp    word ptr [ebx+edx*2-2], 0
CODE:0049F1E1                jge    short loc_49F1ED    --〉等0,跳
。。。
CODE:0049F1ED ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F1ED
CODE:0049F1ED loc_49F1ED:                            ; CODE XREF: sub_49F15D+84j
CODE:0049F1ED                push    ebx
CODE:0049F1EE                push    [ebp+pSource]
CODE:0049F1F1                call    sub_49E2B7    //比較大小,pLongIntZ必須大等於pSource!
CODE:0049F1F6                add    esp, 8
CODE:0049F1F9                test    ax, ax
CODE:0049F1FC                jl      short loc_49F208
CODE:0049F1FE                mov    eax, 0FFFFFFFDh
CODE:0049F203                jmp    loc_49F33C
CODE:0049F208 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F208
CODE:0049F208 loc_49F208:                            ; CODE XREF: sub_49F15D+9Fj
CODE:0049F208                push    ebx
CODE:0049F209                push    edi
CODE:0049F20A                call    sub_49E2B7    //比較大小,pLongIntZ必須大等於pBuff(why?)
CODE:0049F20F                add    esp, 8
CODE:0049F212                test    ax, ax
CODE:0049F215                jl      short loc_49F221
CODE:0049F217                mov    eax, 0FFFFFFFCh
CODE:0049F21C                jmp    loc_49F33C
CODE:0049F221 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F221
CODE:0049F221 loc_49F221:                            ; CODE XREF: sub_49F15D+B8j
CODE:0049F221                mov    dx, ds:word_4DCF68
CODE:0049F228                mov    [ebp+var_6], dx
CODE:0049F22C                push    ebx
CODE:0049F22D                call    sub_49F121    //計算pLongIntZ的bit數,=280,    
CODE:0049F232                pop    ecx
CODE:0049F233                add    eax, 20h        //為運算增加20bits,
CODE:0049F236                sar    eax, 4        //計算需要的字數(280+20)/10
CODE:0049F239                mov    ds:word_4DCF68, ax    //4DCF68=2A
CODE:0049F23F                push    ebx
CODE:0049F240                call    sub_49E8B3    //重要初始化!!!!!
CODE:0049F245                pop    ecx
CODE:0049F246                test    eax, eax
CODE:0049F248                jz      short loc_49F25F    --〉跳
CODE:0049F24A                mov    cx, [ebp+var_6]
。。。
CODE:0049F25F ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F25F
CODE:0049F25F loc_49F25F:                            ; CODE XREF: sub_49F15D+EBj
CODE:0049F25F                push    edi
CODE:0049F260                call    sub_49E3DB    //計算pBuff所指向的空間的最高非零字的位置
CODE:0049F265                pop    ecx
CODE:0049F266                test    ax, ax
CODE:0049F269                jnz    short loc_49F272    --〉nz, 跳
CODE:0049F26B                xor    eax, eax
CODE:0049F26D                jmp    loc_49F33C
CODE:0049F272 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F272
CODE:0049F272 loc_49F272:                            ; CODE XREF: sub_49F15D+10Cj
CODE:0049F272                movsx  edx, ax
CODE:0049F275                shl    edx, 4
CODE:0049F278                mov    [ebp+var_4], edx    ebp+var_4初始存放pBuff有效bit數,
CODE:0049F27B                movsx  ecx, ax
CODE:0049F27E                add    ecx, ecx
CODE:0049F280                add    edi, ecx
CODE:0049F282                add    edi, 0FFFFFFFEh    //移pBuff高位的第一個字到edi,
CODE:0049F285                mov    bx, 8000h
CODE:0049F289                jmp    short loc_49F291
CODE:0049F28B ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F28B
CODE:0049F28B loc_49F28B:                            ; CODE XREF: sub_49F15D+137j
CODE:0049F28B                shr    bx, 1
CODE:0049F28E                dec    [ebp+var_4]
CODE:0049F291
CODE:0049F291 loc_49F291:                            ; CODE XREF: sub_49F15D+12Cj
CODE:0049F291                test    [edi], bx
CODE:0049F294                jz      short loc_49F28B
CODE:0049F296                dec    [ebp+var_4]    //找到了第一個非零bit,當前bit位數減一
CODE:0049F299                push    [ebp+pSource]
CODE:0049F29C                push    esi
CODE:0049F29D                call    sub_49E386    //用 pSource 初始化 pDes
CODE:0049F2A2                add    esp, 8
CODE:0049F2A5                shr    bx, 1
CODE:0049F2A8                test    bx, bx
CODE:0049F2AB                jnz    short loc_49F30E  --〉跳
CODE:0049F2AD                mov    bx, 8000h
CODE:0049F2B1                sub    edi, 2
CODE:0049F2B4                jmp    short loc_49F30E
CODE:0049F2B6 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F2B6
CODE:0049F2B6 loc_49F2B6:                            ; CODE XREF: sub_49F15D+1BAj
CODE:0049F2B6                push    esi
CODE:0049F2B7                push    esi
CODE:0049F2B8                lea    eax, [ebp+var_88]
CODE:0049F2BE                push    eax
CODE:0049F2BF                call    sub_49E94F    //call sub_49e94f(tempBuf, pDest,pDest);!!!!!
CODE:0049F2C4                add    esp, 0Ch
CODE:0049F2C7                lea    edx, [ebp+var_88]
CODE:0049F2CD                push    edx
CODE:0049F2CE                push    esi
CODE:0049F2CF                call    sub_49E386    //copy tempBuf到 pDest
CODE:0049F2D4                add    esp, 8
CODE:0049F2D7                test    [edi], bx        //pBuff當前bit位的值是否為1?    
CODE:0049F2DA                jz      short loc_49F2FF    
CODE:0049F2DC                push    [ebp+pSource]    //=1繼續    
CODE:0049F2DF                push    esi
CODE:0049F2E0                lea    ecx, [ebp+var_88]
CODE:0049F2E6                push    ecx
CODE:0049F2E7                call    sub_49E94F    //call sub_49e94f(tempBuf, pDest, pSource);!!!!
                            //這裡竟然還有pSource作引數,菜鳥一度暈菜!
CODE:0049F2EC                add    esp, 0Ch
CODE:0049F2EF                lea    eax, [ebp+var_88]
CODE:0049F2F5                push    eax
CODE:0049F2F6                push    esi
CODE:0049F2F7                call    sub_49E386    //copy tempBuf到 pDest
CODE:0049F2FC                add    esp, 8
CODE:0049F2FF
CODE:0049F2FF loc_49F2FF:                            ; CODE XREF: sub_49F15D+17Dj
CODE:0049F2FF                shr    bx, 1        //bx移位
CODE:0049F302                test    bx, bx
CODE:0049F305                jnz    short loc_49F30E
CODE:0049F307                mov    bx, 8000h        
CODE:0049F30B                sub    edi, 2        //edi指向pBuff的當前字
CODE:0049F30E
CODE:0049F30E loc_49F30E:                            ; CODE XREF: sub_49F15D+14Ej
CODE:0049F30E                                        ; sub_49F15D+157j ...
CODE:0049F30E                mov    eax, [ebp+var_4]
CODE:0049F311                add    [ebp+var_4], 0FFFFFFFFh    //當前bit位減一
CODE:0049F315                test    eax, eax            //遍歷完pBuff?
CODE:0049F317                jnz    short loc_49F2B6        --〉no則跳
CODE:0049F319                push    0
CODE:0049F31B                lea    edx, [ebp+var_88]
CODE:0049F321                push    edx
CODE:0049F322                call    sub_49E3AC
CODE:0049F327                add    esp, 8
CODE:0049F32A                call    sub_49F0DA
CODE:0049F32F                mov    cx, [ebp+var_6]
CODE:0049F333                mov    ds:word_4DCF68, cx
CODE:0049F33A                xor    eax, eax
CODE:0049F33C
CODE:0049F33C loc_49F33C:                            ; CODE XREF: sub_49F15D+4Ej
CODE:0049F33C                                        ; sub_49F15D+55j ...
CODE:0049F33C                pop    edi
CODE:0049F33D                pop    esi
CODE:0049F33E                pop    ebx
CODE:0049F33F                mov    esp, ebp
CODE:0049F341                pop    ebp
CODE:0049F342                retn
CODE:0049F342 sub_49F15D      endp
CODE:0049F342


這裡有兩個call,sub_49E8B3 和 sub_49e94f。

先看sub_49e8b3, 首先將pLongIntZ的地址存入4DD76C+0。4dd76c+4開始的空間存放了16個地址,
那些地址指向的空間用來存放pLongIntZ*2^n (n=1到16), 把pLongIntZ*2^n(n=0到16)的
最高位元組存到4DD7B0+2*n, 把pLongIntZ*2^n(n=0到16)的次高位元組存到4DD7D2+2*n, 便於
後面比較大小時使用。

sub_49e94f, 是最核心的函式了,好長啊,從49e94f到49f0d9,好在結構還比較簡單,呵呵

來看sub_49e94f(char *pTempDest, char *pLongIntX, char *pLongIntY)

CODE:0049E94F sub_49E94F      proc near              ; CODE XREF: sub_49F15D+162p
CODE:0049E94F                                        ; sub_49F15D+18Ap
CODE:0049E94F
CODE:0049E94F var_6          = word ptr -6
CODE:0049E94F var_4          = dword ptr -4
CODE:0049E94F arg_0          = dword ptr  8
CODE:0049E94F arg_4          = dword ptr  0Ch
CODE:0049E94F arg_8          = dword ptr  10h
CODE:0049E94F
CODE:0049E94F                push    ebp
CODE:0049E950                mov    ebp, esp
CODE:0049E952                add    esp, 0FFFFFFF8h
CODE:0049E955                push    ebx
CODE:0049E956                push    esi
CODE:0049E957                push    edi
CODE:0049E958                mov    edi, [ebp+arg_8]
CODE:0049E95B                mov    ebx, [ebp+arg_0]
CODE:0049E95E                push    [ebp+arg_4]
CODE:0049E961                push    offset dword_4DDF74
CODE:0049E966                call    sub_49E872    //該函式首先將pLongIntX的地址存入4ddf74。
                            4ddf74+4開始的15個DW空間存放地址,這些地
                            址指向的空間的值為 pLongIntX*2^n,n=1到15
    
CODE:0049E96B                add    esp, 8
CODE:0049E96E                movsx  eax, ds:word_4DCF68
CODE:0049E975                add    eax, eax
CODE:0049E977                add    eax, ebx
CODE:0049E979                add    eax, 0FFFFFFFEh
CODE:0049E97C                mov    [ebp+var_4], eax    //ebp+var4儲存pTempDest的最高字地址
CODE:0049E97F                mov    esi, [ebp+var_4]
CODE:0049E982                sub    esi, 2        //esi儲存pTempDest次高字地址
CODE:0049E985                push    0
CODE:0049E987                push    ebx
CODE:0049E988                call    sub_49E3AC    //初始化ptempDest指向的空間為0
CODE:0049E98D                add    esp, 8
CODE:0049E990                push    edi
CODE:0049E991                call    sub_49E3DB    //計算pLongIntY的字長
CODE:0049E996                pop    ecx
CODE:0049E997                mov    [ebp+var_6], ax    //pLongIntY字長存入ebp+bar_6
CODE:0049E99B                cmp    [ebp+var_6], 0
CODE:0049E9A0                jnz    short loc_49E9A9    -->nz跳
CODE:0049E9A2                xor    eax, eax
CODE:0049E9A4                jmp    loc_49F0D3
CODE:0049E9A9 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049E9A9
CODE:0049E9A9 loc_49E9A9:                            ; CODE XREF: sub_49E94F+51j
CODE:0049E9A9                movsx  edx, [ebp+var_6]
CODE:0049E9AD                add    edx, edx
CODE:0049E9AF                add    edi, edx
CODE:0049E9B1                add    edi, 0FFFFFFFEh    //edi儲存pLongIntY的當前字的地址

CODE:0049E9B4                jmp    loc_49F0BF    --〉跳

CODE:0049E9B9 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049E9B9
CODE:0049E9B9 loc_49E9B9:                            ; CODE XREF: sub_49E94F+77Cj
CODE:0049E9B9                push    ebx
CODE:0049E9BA                call    sub_49E83C        //將pTempDest移高一個字,也就是
                                將pTempDest*2^16(這步非常重要噢!)
CODE:0049E9BF                pop    ecx
CODE:0049E9C0                test    byte ptr [edi+1], 80h    //比較pLongIntY當前字的第15bit,
CODE:0049E9C4                jz      short loc_49E9D7
CODE:0049E9C6                push    0
CODE:0049E9C8                push    ds:off_4DDFB0        //ds:off_4DDFB0存有pLongIntX*2^15的指標
CODE:0049E9CE                push    ebx
CODE:0049E9CF                call    sub_49E199        //兩超長正整數相加,存回pTempDest,
                                //位元組間的進位處理還晃了本菜一下,呵
CODE:0049E9D4                add    esp, 0Ch
CODE:0049E9D7
CODE:0049E9D7 loc_49E9D7:                            ; CODE XREF: sub_49E94F+75j

......    
            
CODE:0049EB12
CODE:0049EB12 loc_49EB12:                            ; CODE XREF: sub_49E94F+1B0j
CODE:0049EB12                test    byte ptr [edi], 1
CODE:0049EB15                jz      short loc_49EB28
CODE:0049EB17                push    0
CODE:0049EB19                push    ds:dword_4DDF74
CODE:0049EB1F                push    ebx
CODE:0049EB20                call    sub_49E199
CODE:0049EB25                add    esp, 0Ch
CODE:0049EB28

//以上對edi+1,和edi的各個非零位元,將pTempDest加上相應的pLongIntX*2^n


CODE:0049EB28 loc_49EB28:                            ; CODE XREF: sub_49E94F+1C6j
CODE:0049EB28                mov    ecx, [ebp+var_4]
CODE:0049EB2B                mov    ax, [ecx]            //ax=pTempDest的最高字的值
CODE:0049EB2E                sub    ax, ds:word_4DD7D0    //4dd7d0儲存了 pLongIntZ*2^16
                                的最高字的值
CODE:0049EB35                test    ax, ax
CODE:0049EB38                jg      short loc_49EB6B        //pTempDest大就跳到49eb6b
CODE:0049EB3A                test    ax, ax
CODE:0049EB3D                jnz    short loc_49EB7C
CODE:0049EB3F                mov    dx, [esi]            //dx=pTempDest的次高字的值
CODE:0049EB42                cmp    dx, ds:word_4DD7F2    //4dd7d0儲存了 pLongIntZ*2^16
                                的次高字的值
CODE:0049EB49                ja      short loc_49EB6B        //pTempDest大就跳到49eb6b
CODE:0049EB4B                mov    cx, [esi]
CODE:0049EB4E                cmp    cx, ds:word_4DD7F2    
CODE:0049EB55                jnz    short loc_49EB7C        //小於就跳過49eb6b
CODE:0049EB57                push    ds:off_4DD7AC
CODE:0049EB5D                push    ebx
CODE:0049EB5E                call    sub_49E2B7        //比較pTempDest與pLongIntZ*2^16大小
CODE:0049EB63                add    esp, 8
CODE:0049EB66                test    ax, ax
CODE:0049EB69                jl      short loc_49EB7C        //小於就跳走
CODE:0049EB6B
CODE:0049EB6B loc_49EB6B:                            ; CODE XREF: sub_49E94F+1E9j
CODE:0049EB6B                                        ; sub_49E94F+1FAj
CODE:0049EB6B                push    0
CODE:0049EB6D                push    ds:off_4DD7AC
CODE:0049EB73                push    ebx
CODE:0049EB74                call    sub_49E1E6        //將pTempDest指向的值減去pLongIntZ*2^16
CODE:0049EB79                add    esp, 0Ch
。。。。。。
CODE:0049F068
CODE:0049F068 loc_49F068:                            ; CODE XREF: sub_49E94F+6DAj
CODE:0049F068                                        ; sub_49E94F+6F2j ...
CODE:0049F068                mov    eax, [ebp+var_4]
CODE:0049F06B                mov    ax, [eax]
CODE:0049F06E                sub    ax, ds:word_4DD7B0
CODE:0049F075                test    ax, ax
CODE:0049F078                jg      short loc_49F0AB
CODE:0049F07A                test    ax, ax
CODE:0049F07D                jnz    short loc_49F0BC
CODE:0049F07F                mov    dx, [esi]
CODE:0049F082                cmp    dx, ds:word_4DD7D2
CODE:0049F089                ja      short loc_49F0AB
CODE:0049F08B                mov    cx, [esi]
CODE:0049F08E                cmp    cx, ds:word_4DD7D2
CODE:0049F095                jnz    short loc_49F0BC
CODE:0049F097                push    ds:dword_4DD76C
CODE:0049F09D                push    ebx
CODE:0049F09E                call    sub_49E2B7
CODE:0049F0A3                add    esp, 8
CODE:0049F0A6                test    ax, ax
CODE:0049F0A9                jl      short loc_49F0BC
CODE:0049F0AB
CODE:0049F0AB loc_49F0AB:                            ; CODE XREF: sub_49E94F+729j
CODE:0049F0AB                                        ; sub_49E94F+73Aj
CODE:0049F0AB                push    0
CODE:0049F0AD                push    ds:dword_4DD76C
CODE:0049F0B3                push    ebx
CODE:0049F0B4                call    sub_49E1E6
CODE:0049F0B9                add    esp, 0Ch

//以上依次將pTempDest與pLongIntZ*2^n(n=16到0)比較大小,大等則將pTempDest減去pLongIntZ*2^n
//看出這實值是什麼了嗎?是將pTempDester mod(pLongIntZ)啊!!!

CODE:0049F0BC
CODE:0049F0BC loc_49F0BC:                            ; CODE XREF: sub_49E94F+72Ej
CODE:0049F0BC                                        ; sub_49E94F+746j ...
CODE:0049F0BC                sub    edi, 2        //下移pLongIntY的當前字    
CODE:0049F0BF
CODE:0049F0BF loc_49F0BF:                            ; CODE XREF: sub_49E94F+65j
CODE:0049F0BF                mov    ax, [ebp+var_6]
CODE:0049F0C3                add    [ebp+var_6], 0FFFFh
CODE:0049F0C8                test    ax, ax        //pLongIntY的字都讀完了嗎?
CODE:0049F0CB                jnz    loc_49E9B9    --〉nz跳
CODE:0049F0D1                xor    eax, eax
CODE:0049F0D3
CODE:0049F0D3 loc_49F0D3:                            ; CODE XREF: sub_49E94F+55j
CODE:0049F0D3                pop    edi
CODE:0049F0D4                pop    esi
CODE:0049F0D5                pop    ebx
CODE:0049F0D6                pop    ecx
CODE:0049F0D7                pop    ecx
CODE:0049F0D8                pop    ebp
CODE:0049F0D9                retn
CODE:0049F0D9 sub_49E94F      endp

看出來sub_49e94f(char *ptempDest, char *pLongIntX, char *pLongIntY)做了什麼嗎?說出來
簡單s了,就是 (*pTempDest)=((*pLongIntX)*(*pLongIntY))mod (*pLongIntZ)啊!具體推理
菜鳥就不寫了,手寫不動了啊:) 各位應該能推得出來,不然要加油噢。

哇,菜鳥到這快寫完了噢,開心啊:) 各位是不是看得也有點累了?呵呵
OK! 快要勝利了噢,現在結合sub_49F15D虛擬碼來看看就究竟是怎麼回事吧!

sub_49f15d(char *pDest, char *pSource, char *pBuff, char *pLongIntZ)
{
    初始化pLongIntZ*2^n(n=1到16,其實可以認為n=0到16)
    從高位到底位找到 pBuff的第一個非0位元位,初始化(*pDest)=(*pSource);
    對此後從高到底的pBuff的每個位元位
    {
        sub_49e94f(tempBuf, pDest,pDest);!
        (*pDest)=(*tempBuf);//這兩行實際上是(*pDest)=(*pDest)^2 mod (*pLongIntZ);
        if(當前bit位值==1)
        {
        sub_49e94f(tempBuf, pDest,pSource);!
        (*pDest)=(*tempBuf);//這兩行實際上是(*pDest)=(*pDest)*(*pSource) mod (*pLongIntZ);
                    這裡的pSource前期一度讓偶認為無法求出逆演算法            
        }
    }    
}

實質上, 最終(*pDest)=(*pSource)^m mod (*pLongIntZ) , m是由pBuff決定的一個常數!偶用*pSorce=1
試了一下,(*pDest)果然等於1,哈哈。。。還試了一個*pSource=10, *pBuff=07, 這時
*Dest=00 00 00 10,perfect!哈!
    
對於偶的例子,就是要求

sub_49f15d(char *pDest1, "happy", 4dcb62, 4dcc62)
sub_49f15d(char *pDest2, '11 11 22 22', 4dcb66, 4dce66)
*4dcc62=*4dce66
時,要求

1)*pDest1的位數=*pDest2的位數,
2)*pDest1的第8位開始的DW等於*pDest2的第8位開始的DW。
3)*pDest1的第0B位開始的位元組和等於*pDest2的第0B位開始的位元組和。

嗯,一切都很明瞭了吧!可是對於 x^m mod Z =y, m,Z常數,知道y,怎麼求x? 菜鳥不會啊!應該有什
麼公式吧?不知道和RSA演算法有沒有什麼關係?不過,本菜鳥被這破程式折騰得夠嗆啊,實在是不想再動了。好
了,就到這裡吧!IP_TOOLS,go to hell!呵呵。。。這是本菜第一次寫關於破解的東東,沒有什麼經
驗,希望各位沒有看得暈菜過去噢,呵


半點星
02/02/13

相關文章