• 熱門專題

從破解實例到探討反調試

作者:中二病也要寫代碼!  發布日期:2016-08-08 21:07:28
Tag標簽:反調  實例  
  • 系統 : Windows xp

    程序 : KeyGenMe 1 by Taliesin

    程序下載地址 :http://pan.baidu.com/s/1c2HTuqk

    要求 : 注冊機編寫 

    使用工具 : OD

    可在看雪論壇中查看關于此程序的討論:傳送門

    老規矩,先查看下字符串,定位關鍵代碼:

    004014DF  |.  B8 6C304000   mov     eax, 0040306C                    ;  great job!
    004014E4  |.  8BD8          mov     ebx, eax
    004014E6  |.  83C3 0B       add     ebx, 0B
    004014E9  |.  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
    004014EB  |.  50            push    eax                              ; |Title => 'Great Job!'
    004014EC  |.  53            push    ebx                              ; |Text => 'You have completed Key Gen Me #1.'
    004014ED  |.  6A 00         push    0                                ; |hOwner = NULL
    004014EF  |.  E8 B4000000   call    <jmp.&user32.MessageBoxA>        ; MessageBoxA
    004014F4  |.  C3            retn
    004014F5  |>  6A 00         push    0                                ; /Style = MB_OK|MB_APPLMODAL
    004014F7  |.  68 C2304000   push    004030C2                         ; |not this time.
    004014FC  |.  68 99304000   push    00403099                         ; |try again, something did not work right.
    00401501  |.  6A 00         push    0                                ; |hOwner = NULL
    00401503  |.  E8 A0000000   call    <jmp.&user32.MessageBoxA>        ; MessageBoxA
    00401508  |.  6A 00         push    0                                ; /ExitCode = 0
    0040150A  .  E8 A5000000   call    <jmp.&kernel32.ExitProcess>      ; ExitProcess

    大概就是簡單的一個判斷邏輯,現在我們下斷點看看程序的流程。

    輸入密碼之后發現程序沒有斷在API上,反而顯示:'Try Again, something did not work right.'

    看來是遇到反調試了,反復查驗發現有一處檢測內存是否中斷指令的代碼:

    00401519   $  BF 96124000   mov     edi, 00401296                    ;  Entry address
    0040151E   .  B9 00010000   mov     ecx, 100
    00401523   .  B0 99         mov     al, 99
    00401525   .  34 55         xor     al, 55                           ;  al = cc
    00401527   .  F2:AE         repne   scas byte ptr es:[edi]           ;  掃描
    00401529   .  85C9          test    ecx, ecx
    0040152B   .  74 06         je      short 00401533
    0040152D   .  5E            pop     esi
    0040152E   .  33F6          xor     esi, esi
    00401530   .  57            push    edi
    00401531   .^ EB C2         jmp     short 004014F5
    00401533   >  C3            retn

    可以粗暴點直接爆破,也可以將ZF Set為1覆蓋判斷結果。

    接下來還有一處反調試代碼:

    00401485   .  33DB          xor     ebx, ebx
    00401487   .  BF 80144000   mov     edi, 00401480
    0040148C   .  83EF 60       sub     edi, 60
    0040148F   .  B8 DE000000   mov     eax, 0DE
    00401494   .  83F0 12       xor     eax, 12
    00401497   .  B9 59000000   mov     ecx, 59
    0040149C   .  F2:AE         repne   scas byte ptr es:[edi]           ;  內存檢查
    0040149E   .  85C9          test    ecx, ecx
    004014A0   .  74 06         je      short 004014A8
    004014A2   .  5E            pop     esi
    004014A3   .  33F6          xor     esi, esi
    004014A5   .  57            push    edi
    004014A6   .  EB 4D         jmp     short 004014F5
    004014A8   >  C3            retn
    004014A9   $  BE 9C154000   mov     esi, <jmp.&user32.GetDlgItemText>;  Entry address
    004014AE   .  8B7E 02       mov     edi, dword ptr [esi+2]
    004014B1   .  8B3F          mov     edi, dword ptr [edi]             ;  API地址
    004014B3   .  B9 06000000   mov     ecx, 6
    004014B8   .  B0 CC         mov     al, 0CC
    004014BA   .  F2:AE         repne   scas byte ptr es:[edi]           ;  掃描
    004014BC   .  85C9          test    ecx, ecx
    004014BE   .  74 06         je      short 004014C6
    004014C0   .  5E            pop     esi
    004014C1   .  33F6          xor     esi, esi
    004014C3   .  57            push    edi
    004014C4   .  EB 2F         jmp     short 004014F5
    004014C6   >  C3            retn

    小心點繞過即可,當然啦,如果會執行太多次還是直接爆破為好。

    接下來是算法部分:

    00401332   $  33C0          xor     eax, eax
    00401334   .  B9 00000000   mov     ecx, 0
    00401339   .  BE 23304000   mov     esi, 00403023                    ;  ASCII 'TELBJTMPWM'
    0040133E   .  8A06          mov     al, byte ptr [esi]
    00401340   .  EB 10         jmp     short 00401352
    00401342   >  0FB6C0        movzx   eax, al                          ;  遍歷序列號
    00401345   .  80B8 50314000>cmp     byte ptr [eax+403150], 2         ;  是否是大寫字母
    0040134C   .  75 0A         jnz     short 00401358                   ;  不是則 輸入不合法
    0040134E   .  41            inc     ecx
    0040134F   .  8A0431        mov     al, byte ptr [ecx+esi]
    00401352   >  3C 00         cmp     al, 0                            ;  字符創結尾?
    00401354   .^ 77 EC         ja      short 00401342                   ;  是則結束循環
    00401356   .  EB 07         jmp     short 0040135F
    00401358   >  C605 44304000>mov     byte ptr [403044], 40
    0040135F   >  BE 00304000   mov     esi, 00403000                    ;  ASCII 'pediy'
    00401364   .  33C9          xor     ecx, ecx
    00401366   .  B8 01000000   mov     eax, 1
    0040136B   .  33D2          xor     edx, edx
    0040136D   .  C705 45304000>mov     dword ptr [403045], 0
    00401377   >  B9 00000000   mov     ecx, 0
    0040137C   .  8A0C32        mov     cl, byte ptr [edx+esi]           ;  遍歷用戶名
    0040137F   .  80F9 00       cmp     cl, 0                            ;  字符創結尾?
    00401382   .  74 09         je      short 0040138D                   ;  是則結束循環
    00401384   .  42            inc     edx
    00401385   .  000D 45304000 add     byte ptr [403045], cl            ;  累加
    0040138B   .^ EB EA         jmp     short 00401377
    0040138D   >  A1 45304000   mov     eax, dword ptr [403045]
    00401392   .  B9 18000000   mov     ecx, 18
    00401397   .  99            cdq
    00401398   .  F7F9          idiv    ecx
    0040139A   .  8815 4F304000 mov     byte ptr [40304F], dl            ;  保存 累加結果除以 18 的余數
    004013A0   .  8A0D 44304000 mov     cl, byte ptr [403044]
    004013A6   .  80F9 40       cmp     cl, 40
    004013A9   .  75 05         jnz     short 004013B0
    004013AB   .  E9 45010000   jmp     004014F5
    004013B0   >  E9 CB000000   jmp     00401480
    004013B5   .  C3            retn

    比較序列號:

    004013B6   $  55            push    ebp
    004013B7   .  8BEC          mov     ebp, esp
    004013B9   .  68 23304000   push    00403023                         ;  ASCII 'TELBJTMPWM'
    004013BE   .  E8 7D010000   call    00401540                         ;  算出長度
    004013C3   .  83F8 0A       cmp     eax, 0A
    004013C6   .  0F85 29010000 jnz     004014F5
    004013CC   .  BE 23304000   mov     esi, 00403023                    ;  ASCII 'TELBJTMPWM'
    004013D1   .  B8 00000000   mov     eax, 0
    004013D6   .  BB 00000000   mov     ebx, 0
    004013DB   .  33C9          xor     ecx, ecx
    004013DD   .  EB 06         jmp     short 004013E5
    004013DF   >  8A0C30        mov     cl, byte ptr [eax+esi]
    004013E2   .  03D9          add     ebx, ecx                         ;  累加字符串前九位
    004013E4   .  40            inc     eax
    004013E5   >  83F8 09       cmp     eax, 9                           ;  循環結束?
    004013E8   .^ 72 F5         jb      short 004013DF
    004013EA   .  8BC3          mov     eax, ebx
    004013EC   .  B9 09000000   mov     ecx, 9
    004013F1   .  99            cdq
    004013F2   .  F7F9          idiv    ecx                              ;  累加數除以9
    004013F4   .  A3 4A304000   mov     dword ptr [40304A], eax          ;  保存商
    004013F9   .  8B7D 08       mov     edi, dword ptr [ebp+8]
    004013FC   .  8A15 4F304000 mov     dl, byte ptr [40304F]
    00401402   .  8AC2          mov     al, dl
    00401404   .  3C 18         cmp     al, 18                           ;  之前的余數大于18?
    00401406   .  76 02         jbe     short 0040140A
    00401408   .  2C 18         sub     al, 18
    0040140A   >  A2 4E304000   mov     byte ptr [40304E], al            ;  保存
    0040140F   .  33C0          xor     eax, eax
    00401411   .  A0 4E304000   mov     al, byte ptr [40304E]
    00401416   .  8A2438        mov     ah, byte ptr [eax+edi]           ;  取字符
    00401419   .  8A36          mov     dh, byte ptr [esi]
    0040141B   .  38F4          cmp     ah, dh                           ;  是否一致?
    0040141D   .  0F85 D2000000 jnz     004014F5
    00401423   .  80EE 41       sub     dh, 41
    00401426   .  8AF2          mov     dh, dl
    00401428   .  B4 00         mov     ah, 0
    0040142A   .  A2 4E304000   mov     byte ptr [40304E], al
    0040142F   .  33C0          xor     eax, eax
    00401431   .  A0 4E304000   mov     al, byte ptr [40304E]
    00401436   .  02C2          add     al, dl                           ;  余數相加
    00401438   .  3C 18         cmp     al, 18                           ;  大于18?
    0040143A   .  76 02         jbe     short 0040143E
    0040143C   .  2C 18         sub     al, 18
    0040143E   >  B9 02000000   mov     ecx, 2
    00401443   .  8A2438        mov     ah, byte ptr [eax+edi]           ;  從表中取字符
    00401446   .  8A3431        mov     dh, byte ptr [ecx+esi]
    00401449   .  38F4          cmp     ah, dh                           ;  是否一致?
    0040144B   .  0F85 A4000000 jnz     004014F5
    00401451   .  EB 24         jmp     short 00401477
    00401453   >  A2 4E304000   mov     byte ptr [40304E], al
    00401458   .  33C0          xor     eax, eax
    0040145A   .  A0 4E304000   mov     al, byte ptr [40304E]
    0040145F   .  80EE 41       sub     dh, 41                           ;  對于首字母A的偏移
    00401462   .  8AD6          mov     dl, dh
    00401464   .  41            inc     ecx
    00401465   .  02C2          add     al, dl
    00401467   .  3C 18         cmp     al, 18                           ;  低于等于18?
    00401469   .  76 02         jbe     short 0040146D
    0040146B   .  2C 18         sub     al, 18
    0040146D   >  8A2438        mov     ah, byte ptr [eax+edi]
    00401470   .  8A3431        mov     dh, byte ptr [ecx+esi]
    00401473   .  38F4          cmp     ah, dh
    00401475   .  75 7E         jnz     short 004014F5
    00401477   >  83F9 08       cmp     ecx, 8                           ;  3 - 8
    0040147A   .^ 72 D7         jb      short 00401453
    0040147C   .  C9            leave
    0040147D   .  C2 0400       retn    4

    序列號的最后一位字符 和 第二位:

    004014CE  /$  BE 23304000   mov     esi, 00403023                    ;  ASCII 'TELBJTMPWM'
    004014D3  |.  A1 4A304000   mov     eax, dword ptr [40304A]          ;  取出商
    004014D8  |.  8A5E 09       mov     bl, byte ptr [esi+9]
    004014DB  |.  38D8          cmp     al, bl
    004014DD  |.  75 16         jnz     short 004014F5
    00401510   $  A0 24304000   mov     al, byte ptr [403024]
    00401515   .  3C 45         cmp     al, 45                           ;  序列號第二個字符必須是E
    00401517   .^ 75 DC         jnz     short 004014F5

    看得暈了?不要緊,我來總結一下構成序列號的過程:

    1.必須全部大寫

    2.長度為10.

    3.第一個字符按余數從表中載入

    4.第二個字符為“E”

    5.第三個字符按余數從表中載入

    6.第4-9個字符按照前一個字符取數,再從表中載入

    7.最后一位為前9位的平均數。

    整體算法不困難,就是稍微有點復雜,有點耐心就可以搞定啦。

    打開http://www.cnblogs.com/ZRBYYXDM/p/5115596.html中搭建的框架,將OnBtnDecrypt函數編輯如下:

    void CKengen_TemplateDlg::OnBtnDecrypt() 
    {
        // TODO: Add your control notification handler code here
        CString str;
        GetDlgItemText( IDC_EDIT_NAME,str );                    //獲取用戶名字串基本信息。
        int len = str.GetLength();
    
        if ( len != 0 ){                                        //格式控制。
            char* KeyList = 'ZWATRQLCGHPSXYENVBJDFKMU';
            char Key[11];
            byte sum = 0;
    
            for ( int i = 0 ; i != len ; i++ ){
                sum += str[i];
            }
            byte remainder = sum % 0x18;
    
            Key[0] = KeyList[remainder];
            Key[1] = 'E';
            
            remainder *= 2;
    
            if ( remainder > 0x18 )
                remainder -= 0x18;
    
            Key[2] = KeyList[remainder];
    
            for ( i = 3 ; i != 9 ; i++ ){
                remainder += (Key[i-1] - 'A');
    
                if ( remainder > 0x18 )
                    remainder -= 0x18;
    
                Key[i] = KeyList[remainder];
            }
    
            DWORD KeySum = 0;
            
            for ( i = 0 ; i != 9 ; i++ ){
                KeySum += Key[i];
            }
    
            Key[9] = KeySum / 9;
            Key[10] = '';
    
            SetDlgItemText( IDC_EDIT_PASSWORD,Key );
        }
        else
            MessageBox( '用戶名格式錯誤!' );
    }

    再在OnInitDialog中添加此代碼修改標題:SetWindowText(_T('Keygen'));

    運行效果:

     

    本例中,分別對幾個程序關鍵點和API檢測斷點,在流程中不斷則執行這些代碼。這就讓破解者比較頭疼。

    我認為比較強大的防護不是無法攻破的城堡,而是盡量拖延時間,消耗對方的精力。能做到 破解成本 > 軟件價值,那就是很好的防御措施。

    例如,代碼開始執行的時候 重復檢測斷點,啟動防調試機制(格盤,關機,等等不可描述的行為),讓破解者頭疼不已,只能選擇爆破程序。

    這時,將反調試代碼送入MD5函數,生成一段不可逆的子串。

    再給子串做操作生成特殊數值,最終跳轉到特定地址( 基地址 + 特殊數值 )。

    這樣,一旦動了反調試代碼,程序將執行未知指令,即刻崩潰。

    想要逆向這樣的程序還是比較痛苦的,特別是對于不熟悉加密算法的駭客來說。就算掌握了整個流程,要得到真正的地址就要先默默忍受反調試的折磨:)

About IT165 - 廣告服務 - 隱私聲明 - 版權申明 - 免責條款 - 網站地圖 - 網友投稿 - 聯系方式
本站內容來自于互聯網,僅供用于網絡技術學習,學習中請遵循相關法律法規
彩票联盟网站甘洛县| 图片|