冰點密碼破解 — 強悍的偵錯程式 SOFTICE

wx紅杉樹發表於2007-10-16
標 題: 【原創】冰點密碼破解 — 強悍的偵錯程式 SOFTICE
作 者: figo
時 間: 2007-06-11,15:17
鏈 接: http://bbs.pediy.com/showthread.php?t=46153

【文章標題】: 冰點密碼破解
【文章作者】: figo
【作者郵箱】: yangtengfei@56.com
【作者QQ號】: 382174647
【軟體名稱】: 冰點6.00.220.1692 企業版  
【加殼方式】: 未知殼
【保護方式】: ANIT DEBUG,加殼
【編寫語言】: C , ASM32
【使用工具】: SOFTICE  MASM32  VC++ 6.0
【操作平臺】: WINXP
【作者宣告】: 純技術交流,不針對任何軟體.請勿用於惡意破壞等非法用途,
              否則給自己或他人帶來嚴重後果,概與本人無關.失誤之處懇請批評指正,
              或有更好的方法或者技巧,歡迎互相交流.
--------------------------------------------------------------------------------
【軟體介紹】: 
  Deep Freeze 是一款類似於還原精靈的系統還原軟體,但它比還原精靈強悍,無論加密強度或安全性.
  據介紹這軟體無解,至今為找到破解方法.一旦弄丟了管理密碼,只能格式化磁碟重新安裝系統了.
  筆者釋出此文章只是為了交流技術,並無其它目的,請不要用於惡意破壞等非法用途.
  如果文章能丟失為密碼的使用者帶來一點幫助的話,筆者會十分欣慰的,畢竟好幾天的努力才完成這文章的,
  Deep Freeze 的下載地址也不提供了,網上到處都是,版本是 6.20.220.1692
  

【詳細過程】
  
    
  破解前的準備:
  先安裝好 冰點 和 SOFTICE,筆者用的 DS3.2 中的 SOFTICE. 還有 IceExt 0.70 外掛的安裝(這並不是必須的,
  只是寫文章的時候要用到,後面會介紹 IceExt 外掛的妙用).裝好冰點後,把客戶端的密碼設定為:382174647
  (呵呵,這是我的QQ號,  當然,你也可以設定為任意密碼 ),把還原的盤設為 Z 盤(也可以任意,
  但一般不設為自己的硬碟分割槽),最後安裝客戶端.
  
  
  開始分析:
  
  首先,按住鍵盤上的 CTRL + ALT + SHIFT + F6 四個鍵,調出冰點密碼輸入對話方塊. 輸入任意密碼,如: 234234.
  CTRL + D 調出 SOFTICE. 此時,你可千萬別指望能在記憶體中找到 '234234' 的資料,並置斷點.
  用 S 指令搜遍整個 4G 空間也一樣,就算找到了,那也不是密碼文字框的.

  因為當改變文字框的內容時,該文字框會自動呼叫 NT 的 Native API  :RtlRunEncodeUnicodeString 函式 進行加密.
  當應用程式想獲取文字內容時,該文字框又會呼叫  RtlRunDecodeUnicodeString 函式進行解密.
  關於 RtlRunEncodeUnicodeString 和  RtlRunDecodeUnicodeString 的原始碼可以在 NT 原始碼中的 sertl.c 檔案中找到.
  其實 RtlRunEncodeUnicodeString 只是對資料進行簡單的 XOR 運算,儘管加密演算法簡單,卻很有效的防止在記憶體中被找出明碼.
  雖然我們可以不用知道 RtlRunDecodeUnicodeString  的具體演算法,但為了利於破解,我們還是有必要知道它的定義:
  
  VOID RtlRunDecodeUnicodeString(  UCHAR  Seed,  PUNICODE_STRING String  )
  
  第一個引數是 :
  位元組型別, 加密的種子的值.
  
  第二個引數是:
  是個 PUNICODE_STRING 資料型別
  指向被解密的資料的地址(注意了,是雙重指標)
  
  好了,通過上面的分析,我們開始對 RtlRunDecodeUnicodeString  下斷點,點選 OK 按紐,程式被中斷在如下程式碼:
  
  
  EAX=0000002A   EBX=00000006   ECX=7C822E07   EDX=00140608   ESI=0014C2A8        
  EDI=0014CDB0   EBP=0012F088   ESP=0012F06C   EIP=7C94EF8B   o d I s Z a P c     
  CS=001B   DS=0023   SS=0023   ES=0023   FS=003B   GS=0000                       
  --------------------------------------------------byte--------------PROT---(0)--
  0023:00E20034 B0 CD 14 00 03 00 00 00-28 CF 14 00 68 00 E2 00  ........(...h.? 
  0023:00E20044 00 00 00 00 03 00 01 00-90 A5 15 00 03 00 01 00  ........惀...... 
  0023:00E20054 B0 65 17 00 03 00 01 00-D0 25 19 00 03 00 01 00  .e.......%...... 
  0023:00E20064 F0 E5 1A 00 70 00 E2 00-00 00 00 00 78 00 E2 00  .?.p.?....x.? 
  ------ntdll!RtlRunEncodeUnicodeString+004D-------------------------------PROT32-
  ntdll!RtlRunDecodeUnicodeString                                                 
  001B:7C94EF8B  8BFF                MOV       EDI,EDI                            
  001B:7C94EF8D  55                  PUSH      EBP                                
  001B:7C94EF8E  8BEC                MOV       EBP,ESP                            
  
  剛才我們瞭解到 RtlRunDecodeUnicodeString  的第二個引數是指向密文的雙重指標,輸入:
  D *(ESP - 08)
  這時,密文的地址如上面DATA 視窗所示,為 14CDB0H.
  不要急著下斷點,要等到它解密完畢.
  P RET ,跳出 RtlRunDecodeUnicodeString 
  然後 D 14CDB0
  
  --------------------------------------------------byte--------------PROT---(0)--
  0023:0014CDB0 32 33 34 32 33 34 00 00-00 00 00 00 00 00 00 00  234234.......... 
  0023:0014CDC0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................ 
  
  可以看到明碼已經出現在我們面前. 好了,可以對它下硬體讀斷點
  bpm 14CDB0 R
  G 執行. 程式被中斷在如下程式碼:
  
  ------USER32!EditWndProc+0566--------------------------------------------PROT32-
  001B:77D3352D  F3A5                REPZ MOVSD                                   
  001B:77D3352F  8BC8                MOV       ECX,EAX                            
  001B:77D33531  83E103              AND       ECX,03                             
  001B:77D33534  F3A4                REPZ MOVSB                                   
  001B:77D33536  E8E3FBFFFF          CALL      77D3311E                           
  001B:77D3353B  5F                  POP       EDI                                
  001B:77D3353C  5E                  POP       ESI                                
  001B:77D3353D  8BC3                MOV       EAX,EBX                            
  001B:77D3353F  5B                  POP       EBX                                
  001B:77D33540  5D                  POP       EBP                                
  001B:77D33541  C21000              RET       0010          
  
  不難看出,這段程式碼主要是實現資料的複製
  這時的 EDI = 00BC932C, 而 ESI 則是剛才明碼的地址, ESI = 0014CDB0H
  同樣,對 00BC932CH 下硬體讀斷點.G 執行 .
  接下來,程式再次中斷在 RtlRunDecodeUnicodeString 上,我們再次重複上面這一過程.
  唯一不同的是,這次明碼是被複制到 00BCA488H 處.於是對 00BCA488H 再下一個硬體讀斷點. 
  G 執行 .
  
  程式中斷在如下程式碼:
  
  AX=00BCA488   EBX=00BCA488   ECX=0012F348   EDX=32343332   ESI=0012F33C        
  EDI=00BCAE11   EBP=0012F284   ESP=0012F254   EIP=004961F2   o d I s Z a P c     
  CS=001B   DS=0023   SS=0023   ES=0023   FS=003B   GS=0000                       
  --------------------------------------------------byte--------------PROT---(0)--
  0023:00BCA488 32 33 34 32 33 34 00 00-26 00 00 00 EC 9C BC 00  234234..&...鞙.. 
  0023:00BCA498 00 00 00 00 34 9D BC 00-00 00 00 00 13 00 00 00  ....4?......... 
  0023:00BCA4A8 00 00 00 00 01 00 00 00-24 00 00 00 16 00 00 00  ........$....... 
  0023:00BCA4B8 EC 46 BC 00 24 AA BC 00-4F 70 74 69 14 00 00 00  霧..$?.Opti.... 
  -------------------------------------------------------------------------PROT32-
  001B:004961F0  8B10                MOV       EDX,[EAX]                          
  001B:004961F2  83C004              ADD       EAX,04                             
  001B:004961F5  8BCA                MOV       ECX,EDX                            
  001B:004961F7  81EA01010101        SUB       EDX,01010101                       
  001B:004961FD  81E280808080        AND       EDX,80808080                       
  001B:00496203  74EB                JZ        004961F0                           
  001B:00496205  F7D1                NOT       ECX                                
  001B:00496207  23D1                AND       EDX,ECX                            
  001B:00496209  74E5                JZ        004961F0                           
  
  對每個位元組減 1 ,再判斷是否為負,這段程式碼應該是測試字串長度的. 看看它返回的是什麼值?
  
  P RET
  
  程式碼如下:
  
  EAX=00000006   EBX=00BCA488   ECX=00BCA488   EDX=80800000   ESI=0012F33C        
  EDI=00BCAE11   EBP=0012F284   ESP=0012F25C   EIP=0040BF90   o d I s z a P c     
  CS=001B   DS=0023   SS=0023   ES=0023   FS=003B   GS=0000   DS:00BCAE11=0014    
  -------------------------------------------------------------------------------
  001B:0040BF87  E85CA20800          CALL      004961E8                           
  001B:0040BF8C  59                  POP       ECX                                
  001B:0040BF8D  8945FC              MOV       [EBP-04],EAX                       
  001B:0040BF90  0FB707              MOVZX     EAX,WORD PTR [EDI]                 
  001B:0040BF93  85C0                TEST      EAX,EAX                            
  001B:0040BF95  7513                JNZ       0040BFAA                           
  
  EAX 返回 6,沒猜錯,果然是測字串長度的. EAX 儲存在 EBP -4 處,再對 EBP -4  下一個硬體讀斷點.
  
  G  執行.
  
  程式中斷在如下程式碼:
  
  001B:0040BFB4  3B45FC              CMP       EAX,[EBP-04]                       
  001B:0040BFB7  7407                JZ        0040BFC0             (NO JUMP)     
  001B:0040BFB9  33C0                XOR       EAX,EAX                            
  001B:0040BFBB  E989000000          JMP       0040C049                           
  
  此時的 EAX = 9 (原來密碼的長度)  ,[EBP -4] = 6 (輸入密碼的長度)
  不相等就清零 EAX ,並跳到 40C049
  
  
  再看看   40C049 處的程式碼:
  
  001B:0040C049  5F                  POP       EDI                                
  001B:0040C04A  5E                  POP       ESI                                
  001B:0040C04B  5B                  POP       EBX                                
  001B:0040C04C  8BE5                MOV       ESP,EBP                            
  001B:0040C04E  5D                  POP       EBP                                
  001B:0040C04F  C3                  RET                        
  
  這是子過程結束的標準語句. 
   CMP       EAX,[EBP-04]  和  JZ        0040BFC0 是判斷輸入密碼和原密碼的長度是否相符.
  這兩句很重要,請記住它,寫密碼破解程式時要用到它.
  為了繼續除錯,把 Z 位 置 1,單步..
  
  程式碼如下:
  
  EAX=00000009   EBX=00BCA488   ECX=00BCA488   EDX=80800000   ESI=0012F33C        
  EDI=00BCAE11   EBP=0012F284   ESP=0012F25C   EIP=0040BFC0   o d I s Z a P c     
  CS=001B   DS=0023   SS=0023   ES=0023   FS=003B   GS=0000   DS:0012F33C=9F448C62
  --------------------------------------------------byte--------------PROT---(0)--
  0023:00BCA488 32 33 34 32 33 34 00 00-26 00 00 00 EC 9C BC 00  234234..&...鞙.. 
  0023:00BCA498 00 00 00 00 34 9D BC 00-00 00 00 00 13 00 00 00  ....4?......... 
  0023:00BCA4A8 00 00 00 00 01 00 00 00-24 00 00 00 16 00 00 00  ........$....... 
  0023:00BCA4B8 EC 46 BC 00 24 AA BC 00-4F 70 74 69 14 00 00 00  霧..$?.Opti.... 
  -------------------------------------------------------------------------PROT32-
  001B:0040BFC0  8B16                MOV       EDX,[ESI]                          
  001B:0040BFC2  895604              MOV       [ESI+04],EDX                       
  001B:0040BFC5  33C9                XOR       ECX,ECX                            
  001B:0040BFC7  8BD3                MOV       EDX,EBX                            
  001B:0040BFC9  894DF8              MOV       [EBP-08],ECX                       
  001B:0040BFCC  8D4702              LEA       EAX,[EDI+02]                       
  001B:0040BFCF  C745F402000000      MOV       DWORD PTR [EBP-0C],00000002        
  001B:0040BFD6  8955E4              MOV       [EBP-1C],EDX                       
  001B:0040BFD9  8BF8                MOV       EDI,EAX                            
  001B:0040BFDB  8B4DF8              MOV       ECX,[EBP-08]        ;已經與密碼比較過的位元組數               
  001B:0040BFDE  3B4DFC              CMP       ECX,[EBP-04]        ;密碼的長度               
  001B:0040BFE1  7D64                JGE       0040C047            ;此處改為 JMP  0040C047,也可實現暴破            
  001B:0040BFE3  56                  PUSH      ESI                                
  001B:0040BFE4  E8B7FEFFFF          CALL      0040BEA0  
  ;密碼演算法的關鍵 CALL ,喜歡研究演算法的朋友可以跟進瞧瞧,不過也無意義,等下解釋為什麼.
    
               
  001B:0040BFE9  59                  POP       ECX                                
  001B:0040BFEA  8B45E4              MOV       EAX,[EBP-1C]   ;指向輸入的密碼的第N個位元組,N = [EBP - 8]                     
  001B:0040BFED  8A18                MOV       BL,[EAX]                           
  001B:0040BFEF  8A07                MOV       AL,[EDI]                           
  001B:0040BFF1  324604              XOR       AL,[ESI+04]    ;解密出原密碼的第N個位元組                
  001B:0040BFF4  8845F3              MOV       [EBP-0D],AL    ;暫存                
  001B:0040BFF7  807D1400            CMP       BYTE PTR [EBP+14],00               
  001B:0040BFFB  7409                JZ        0040C006                           
  001B:0040BFFD  3A5DF3              CMP       BL,[EBP-0D]                        
  001B:0040C000  742F                JZ        0040C031                           
  001B:0040C002  33C0                XOR       EAX,EAX                            
  001B:0040C004  EB43                JMP       0040C049                           
  001B:0040C006  0FBED3              MOVSX     EDX,BL                             
  001B:0040C009  8955EC              MOV       [EBP-14],EDX                       
  001B:0040C00C  8B4DEC              MOV       ECX,[EBP-14]                          
  001B:0040C00F  51                  PUSH      ECX                                
  001B:0040C010  E873D40800          CALL      00499488                           
  001B:0040C015  59                  POP       ECX                                
  001B:0040C016  50                  PUSH      EAX                                
  001B:0040C017  0FBE45F3            MOVSX     EAX,BYTE PTR [EBP-0D]              
  001B:0040C01B  8945E8              MOV       [EBP-18],EAX                       
  001B:0040C01E  8B55E8              MOV       EDX,[EBP-18]       
  001B:0040C021  52                  PUSH      EDX                                
  001B:0040C022  E861D40800          CALL      00499488                           
  001B:0040C027  59                  POP       ECX                                
  001B:0040C028  59                  POP       ECX                                
  001B:0040C029  3BC8                CMP       ECX,EAX     ;   開始對比,EAX 為原密碼的第N個位元組                 
  001B:0040C02B  7404                JZ        0040C031    ;   關鍵跳轉,很重要,寫破解程式時,要用到它.
                      
  001B:0040C02D  33C0                XOR       EAX,EAX                            
  001B:0040C02F  EB18                JMP       0040C049                           
  001B:0040C031  FF45E4              INC       DWORD PTR [EBP-1C]                 
  001B:0040C034  FF45F8              INC       DWORD PTR [EBP-08]   ;對比的位元組地址加 1              
  001B:0040C037  47                  INC       EDI                                
  001B:0040C038  FF45F4              INC       DWORD PTR [EBP-0C]                 
  001B:0040C03B  47                  INC       EDI                                
  001B:0040C03C  FF45F4              INC       DWORD PTR [EBP-0C]                 
  001B:0040C03F  8B55F8              MOV       EDX,[EBP-08]                       
  001B:0040C042  3B55FC              CMP       EDX,[EBP-04]                       
  001B:0040C045  7C9C                JL        0040BFE3        ;判斷是否對比完畢.未完則繼續.               
  001B:0040C047  B001                MOV       AL,01                              
  001B:0040C049  5F                  POP       EDI                                
  001B:0040C04A  5E                  POP       ESI                                
  001B:0040C04B  5B                  POP       EBX                                
  001B:0040C04C  8BE5                MOV       ESP,EBP                            
  001B:0040C04E  5D                  POP       EBP                                
  001B:0040C04F  C3                  RET                                          
  
  
  
  
  
  
  這段程式碼便是密碼比較的最重要部分,由於程式碼長而複雜,於是就用註釋來代替跟蹤.
  對冰點密碼演算法感興趣的朋友,可以直接對 40BDC0H  置斷點,並依照註釋自己跟蹤除錯一下.
  
  
  解密器的編寫思路 :
  既然程式可以把原密碼解密出單位元組並與輸入密碼進行迴圈比較,我們可以寫一個程式,
  對程式每次解出的單位元組密碼進行拼接.
  如果把 40C029 — 40C030 之間8個位元組全部用 NOP 填充,可以實現爆破.
  這說明 40C029 — 40C030 之間有8個位元組可以利用.而不遠處 
  0040C03F 有  MOV  EDX,[EBP-08] 這麼一條指令,說明EDX 也可以利用.
  於是解密程式先為 冰點 程式遠端分配一段記憶體,然後把遠端程式碼寫入記憶體.
  最後在  40C029 — 40C030 之間寫如下程式碼:
  NOP
  MOV EDX,XXXXXXXX
  CALL EDX
  
  XXXXXXXX 為遠端程式碼的起始地址,編譯成位元組碼如下:
  90,BA XXXXXXXX ,FF D2 . 剛好8個位元組.
  
  
  
  
  寫此程式遇見的第一個問題就是: 如何確定原密碼的長度?
  也許你會說[EBP -4] 不就是嗎? 不是的,[EBP - 4]其實是我們輸入密碼的長度.
  這時,你可能更納悶了,如果密碼迴圈比較是由輸入的密碼的長度決定,那程式的安全性不就只有一個位元組了?
  別忘了,我們進入這段程式碼是通過強制跳轉的,正常情況下,只有[EBP - 4]等與原密碼的長度才進行比較.
  就算使用程式碼補丁進入密碼比較你也無法知道原密碼的長度,唯一的辦法就是讓[EBP - 4] 等於原密碼的長度,
  然後再強行跳轉.於是我們就在 40BFB4H 處的  CMP  EAX,[EBP-04] 和  JZ  0040BFC0 下文章.
  把它改為 MOV [EBP-04],EAX 和 JMP  0040BFC0 就可以完美解決.
  
  
  
  
  具體程式碼實現:
  
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;code.inc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      .486                      
      .model flat, stdcall       
      option casemap :none      
  
      include /masm32/include/windows.inc
      include /masm32/include/masm32.inc
      include /masm32/include/kernel32.inc
      include /masm32/include/advapi32.inc
      include  /masm32/include/user32.inc
      
      includelib /masm32/lib/masm32.lib
      includelib /masm32/lib/kernel32.lib
      includelib /masm32/lib/advapi32.lib
      includelib /masm32/lib/user32.lib
       
       GetPidFromProcName  proto :DWORD
       WritePMem  proto :DWORD,:DWORD,:DWORD,:DWORD
   
  .data
    procname     db  'FrzState2k.exe'  ,00
    mempatch     db   0ebh,089h,045h,0fch
    farcall      db   90h,0bah,0ffh,0d2h
     
    funadd       dd     ?
    szMsgBox     db   'MessageBoxA',0
    szuserdll    db    'user32.dll',0
    lpMsgfun     dd    ?
    szsvrname    db     'MyServerName1',0  
    szstr1       db     '冰點破解程式',0 
    szstr2     db     '執行此程式後,按 CTRL + SHIFT + ALT + F6,調出密碼輸入對話方塊',13,10 

     db     '可以不用輸入密碼,或輸入任意密碼.',13,10
     db     '點選 OK ,即可顯示密碼,並進入控制介面!',13,10 
     db     '本程式破解時,遠端分配的空間並不釋放.',13,10
     db     '多次執行後請重起!',13,10,13,10
     db     'by figo (追風者)',13, 10, 'QQ : 382174647',0
    buf1         db      120h dup (00)
    buf2         db      124h dup (00)
    szfmt        db      '"%s"',0   
    var1   db      ' sys',0

  
  .code
  
  
  mycode:
  
  lpmsg   dd  ?
  sztil   db  '密碼為: ',0
  szstr   db 'password is '
  szpwd   db  70h dup (0)
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  startcode:
  
  pushad
  
  call l1
  l1:
  pop ebx
  sub ebx,offset l1
  ;很經典的程式碼自定位技術,不陌生吧!
  lea edi, [ebx + offset szpwd]
  mov edx,[ebp - 8]
  add edi,edx
  mov byte ptr [edi],al
  inc edx
  mov eax,[ebp -4]
  cmp edx,eax
  jl ext1
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  push  MB_OK or MB_SERVICE_NOTIFICATION  
  ;由於冰點會不斷把密碼輸入對話方塊置前,所以只能加上 MB_SERVICE_NOTIFICATION 常數. 
  lea edi ,[ebx + offset sztil]
  push edi
  
  lea edi ,[ebx + offset szpwd]
  push edi
  push 0
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  mov eax,[ebx + offset lpmsg]
  call eax
  
  ext1:
  popad
  ret
  
  codeend:
  
  GetPidFromProcName proc lpProcName:DWORD
  LOCAL stProcess : PROCESSENTRY32
  LOCAL hSnapshot
  LOCAL dwProcessID
  
  mov dwProcessID, 0
  invoke RtlZeroMemory, addr stProcess, sizeof stProcess
  mov stProcess.dwSize, sizeof stProcess
  invoke CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS, 0
  mov hSnapshot, eax
  invoke Process32First, hSnapshot, addr stProcess
  .while eax
  invoke lstrcmpi, lpProcName, addr stProcess.szExeFile
  .if eax==0
  mov eax, stProcess.th32ProcessID
  mov dwProcessID, eax
  .break
  .endif
  invoke Process32Next, hSnapshot, addr stProcess
  .endw
  invoke CloseHandle, hSnapshot
  mov eax, dwProcessID
  ret
  GetPidFromProcName endp
  
  
  WritePMem   proc  hproc:DWORD, rwadd:DWORD  ,lpbuff:DWORD, nsize:DWORD
  local  dwrwcnt
  local  oldpct
  invoke  VirtualProtectEx,hproc,lpbuff,4096,PAGE_EXECUTE_READWRITE,addr oldpct
  .if !eax
  ret
  .endif
  invoke  WriteProcessMemory ,hproc,rwadd,lpbuff,nsize,addr dwrwcnt
  invoke   VirtualProtectEx,hproc,lpbuff,4096,oldpct,addr oldpct
  
  mov eax, dwrwcnt
  ret
  
  WritePMem   endp
  
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;code.inc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;deep.asm;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
  include  code.inc
  
  
  start:
  
  Main  proc
  local    hproc1
  local    hSCManager
  local     hService
  
  ;//////////提權///////////////////////////////////////////////////////////
  invoke  GetCommandLine
  mov esi,eax

  invoke GetModuleFileName,NULL,addr buf1,255
  invoke  wsprintf,addr buf2,addr szfmt,addr buf1
  ;如果不將檔案路徑加上雙引號,則無在帶有空格的路徑名中正常執行.
  invoke lstrcat,addr buf2,addr var1
  invoke lstrcmpi,addr buf2,esi
  jz startmain 

  invoke OpenSCManager, NULL, NULL, SC_MANAGER_CREATE_SERVICE
  .if eax
  mov hSCManager, eax

  invoke OpenService, hSCManager, addr szsvrname , DELETE
  .if eax!=0
  mov    hService, eax
  invoke DeleteService, hService
  invoke CloseServiceHandle,hService
  .endif

  invoke CreateService, hSCManager,addr  szsvrname, addr  szsvrname, /
  SERVICE_START + SERVICE_QUERY_STATUS + DELETE, /
  SERVICE_WIN32_OWN_PROCESS + SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, /
  SERVICE_ERROR_IGNORE, addr buf2, NULL, NULL, NULL, NULL, NULL

  .if eax!=0
  mov    hService, eax
  invoke StartService, hService, 0, NULL
  invoke DeleteService, hService
  invoke CloseServiceHandle, hService
  .endif
  invoke CloseServiceHandle, hSCManager
  .endif

  invoke ExitProcess,0

  ;////////////////////以服務的方式執行自身////////////////////////////////////////
  
  startmain:
  
  invoke GetPidFromProcName ,addr procname
  
  invoke OpenProcess,PROCESS_ALL_ACCESS,NULL,eax
  mov hproc1,eax
  lea esi,mempatch
  
  invoke   WritePMem,hproc1,0040bfb7h,esi,1
  invoke   WritePMem,hproc1,0040c02bh,esi,1
  inc esi
  invoke   WritePMem,hproc1,0040bfb4h,esi,3
  
  invoke   GetModuleHandle, addr szuserdll
  
  invoke GetProcAddress,eax,addr szMsgBox
  mov  lpMsgfun,eax
  
  
  invoke  VirtualAllocEx,hproc1,NULL,1024,MEM_COMMIT,PAGE_EXECUTE_READWRITE
  .if eax
  mov esi,eax
  
  invoke  WritePMem,hproc1,esi,offset mycode,offset codeend - offset mycode 
  invoke  WritePMem,hproc1,esi,offset lpMsgfun ,4
  mov edi,offset startcode - offset mycode
  add esi,edi
  mov funadd,esi
  mov esi,0040c029h
  
  invoke  WritePMem,hproc1,esi,offset farcall,2
  inc esi
  inc esi
  
  invoke  WritePMem,hproc1,esi,offset funadd,4
  add esi ,4
  
  invoke  WritePMem,hproc1,esi,offset farcall + 2 ,2
  
  .endif
  
  invoke  MessageBox,NULL,addr szstr2,addr szstr1,MB_OK
  ;注意這句,筆者的用意可不是僅僅為了提示使用者,而是必須要有這麼個函式.
  invoke ExitProcess,0
  
  
  Main endp
  
  end start;
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;deep.asm;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;       
  由於冰點是以服務的方式執行,程式具有SYSTEM 許可權.要對它進行記憶體的讀寫與分配,須進行提權.
  提權的方法有很多種,為了減小程式碼的篇幅,只好選最簡單的提權方式:
  以服務的方式執行自身,這樣就可以很方便得到SYSTEM 許可權.
  唯一的缺憾就是另創程式,這在程式碼除錯時,給 OD 帶來不小的麻煩.
  
  
  
  
  
  一次性密碼的演算法:
  
  G 繼續執行冰點程式,程式又被中斷.....,那是開始比較一次性密碼.
  具體除錯方法與上面類似,這裡就不再重複了,也可以把上面的程式碼稍加修改,用於解一次性密碼.
  解一次性密碼較為理智的方法就是分析服務端的主程式,下面一次性密碼的演算法就是跟蹤服務端程式得來的.
  由於篇幅的原因,我只貼出演算法,具體除錯方法就不寫了.因為分析一次性密碼演算法遠遠複雜於解客戶端密碼,
  單單一次性密碼的分析,就可以再寫成一篇文章.
  
  具體演算法如下:
  ///////////////////////////////OT.CPP////////////////////////////////////
  #include "stdio.h"
  #include "stdlib.h"
  #include  "string.h"

  #define  UL unsigned long
  #define  SI signed short int
  #define  SL signed long
  
  UL pwd(UL a,UL b,UL c);
  SI hl(SI srt);
  UL cr(char  str1[] );
  
  void main(int argc, char* argv[])
  {
      UL pwd1,pwd2,pwd3;
      char *cstcode = new char[0x80];
      char etystr[] = {"Igor Zagoruchenko"} ;
  
  
    printf("/t/t One Time Password Generation System /n/n by figo /n/n");
  
    printf("/nPlease enter the  customization code: /n");
    if(!(scanf("%s",cstcode)))
        return;
  
      printf("/nPlease enter OTP Token : /n");
    if(!(scanf("%8x",&pwd1)))
        return;
  
  
    pwd2 = cr(etystr);
    pwd3 = cr(cstcode);
  
    pwd1 = pwd(pwd1,pwd2,pwd3);
    printf("/n/nThe One Time Password is : /n/n");
    printf("%8X (Password valid for one use only)/n/n/n/n",pwd1);
  
  
   ltoa(pwd1,cstcode,16);
   pwd2 = cr(cstcode);
  
   ltoa(pwd2,cstcode,16);
   cstcode = strupr(cstcode );  
   printf("%4.4s-%8X (Password valid for multiple uses ) /n/n/n/n/n",cstcode,pwd1);
   
   delete cstcode;
   system("pause");
  
  }
  
  UL pwd(UL a,UL b,UL c)
  {
  
      SI s1,s2,s3;
          a  ^= b;
          a  ^= c;
          b = a << 0x10;
          b >>= 0x10;
    c = a >> 0x10;
    a = b^c;
    s1 = (SI)a;
    s2 = (SI)b;
    s3 = (SI)c;
    s1 = hl (s1);
    s3 = hl  (s3);
    s3 ^= s2;
    
    a= s1;
    a <<= 0x10;
    a += s3;
     return a;
  
  }
  
  SI hl(SI srt)
  {
    SL a,b,c;
    a = srt;
    b = a;
    a /=  0xb1; 
        b = b%0xb1; 
    c = b * 0xab; 
    a += a;
        c -= a;
    a = c;
    b = a;
    a <<= 0x0f;
    a -= b;
    srt = (SI)a;
  
    return srt;
  
  }
  
  UL cr(char  str1[] )
  {
  
      int i = 0 ,k =0;
      char c1;
      unsigned long rst = 0,l1,l2;
  
    while (!(str1[i] == 0))
    { 
    c1 = str1[i];
  
    if(  (c1 >= 'A') && (c1<='Z' ) )
      c1  |= 0x20;
    else 
      c1 = c1;
    
    l1 = c1;
    rst <<= 4;
    l1 += rst;
    rst = l1;
  
    l1 &= 0xf0000000;
    
    if(l1)
    {
        l2  = l1 >> 0x18;
        rst ^= l2;
    }
     l1 = ~l1;
     rst &= l1;
  
        i++;
  
    }
  
  return rst;
  
  }    
  ////////////OT.CPP///////////////////////////////////////////////////////////////////
  
  上面程式碼是模擬冰點的一次性密碼生成系統, 只是為了模擬演示演算法,所以需要輸入使用者的自定義碼.
  直接在客戶端解出一次性密碼而不用使用者自定義碼的詳細程式碼見附件(一定要安裝冰點客戶端才能解出一次性密碼).
  
  
  
  冰點的分析到此為止.文章的開始我們提到外掛 IceExt 0.70.下面講解 IceExt 0.70的妙用.
  我們都知道 SOFTICE 無法象 OD 一樣有強大的文字複製功能.但是寫破文的時候用到的那些程式碼片段怎麼辦呢?
  如果說是把它抄下來,然後再手動輸入成文章,那這樣的破文我是不會寫的.
  IceExt 0.70 外掛中有個轉存螢幕的功能,但它儲存的是RAW 格式的檔案,而不是文字.
  用十六進位制編輯器開啟IceExt 0.70 轉存的檔案,發現 RAW 格式其實很簡單:
  每個字元用2個位元組儲存:
  第一個位元組儲存字元的值.
  第二個位元組儲存字元的屬性,低四位為前景色,高四位為背景色.
  玩過十六位彙編的朋友,如果有嘗試在顯示緩衝區內寫入彩色字的,應該對此不陌生吧!
  再看一下檔案的長度,剛好等於 WIDTH 的值 * LINES 的值 * 2
  
  下面我就把提取RAW中字元的程式碼貼一下:
  
  ///////////////////////duptxt.cpp//////////////////////////////
  /*//2007.6.7      by figo (追風者)  QQ: 382174647
    
    僅用於學習交流,程式碼中有任何問題請聯絡我...
     程式用法:
     duptxt.exe rawfilename [width] 
     rawfilename 為IceExt Dump 出來的RAW 格式的檔案.
     width  為SOFTICE 中 width 指令的設定值,預設為 80。
     程式執行成功,會在 rawfilename 檔案的目錄下生成 rawfilename.txt 檔案...
  //*/
  
  
  #include "stdio.h"
  #include "afx.h"
  
  void main(int argc, char* argv[])
  {
  
  CFile f1,f2;
  CString txtfn1;
  int width = 80,lines, i,k;
  unsigned int cr=0x0a0d;
  
  unsigned char tmp;
  
  
  if( argc < 2)
  {
  printf("正確引數格式為:/n ");
  printf("%s  rawfilename [width]  /n",argv[0]);
  
  return;
  }
  else if(argc > 2)
  {
      width = atoi( argv[2] );
  }
   
  if (!(f1.Open(argv[1],CFile::modeRead )))
  {
  printf("%s 檔案開啟失敗!/n",argv[1]);
  return;
  }
  
  txtfn1 = argv[1];
  txtfn1 += ".txt";
  
  if(!(f2.Open(txtfn1, CFile::modeWrite | CFile::modeCreate )))
  {
  printf(" %s 檔案建立失敗!/n",txtfn1);
  return ;
  
  }
  
     
    f1.SeekToBegin ();
    f2.SeekToBegin ();
          
          lines = f1.GetLength ();
          lines /= width * 2;
  
    for(k=0 ;k<lines;k++) 
    {  
      for(i =0 ; i<width;i++)
      {
        f1.Read (&tmp,1);
        ////////////////// 
        if (tmp == 0xc4)
          tmp = '-';
        else if((tmp >= 0x10)&&(tmp <0x20))
          tmp = 0x20;
  
        /////////////////
        f2.Write (&tmp,1);
        f1.Seek (1,CFile::current);
        
      }
      f2.Write (&cr,2);
  
    }
  
    f1.Close ();
    f2.Close ();
  
  }
  
  //////////////////////////////duptxt.cpp///////////////////////////////////////////
  
  編譯上面程式碼時,要注意在工程設定中選擇   Use MFC in a Shared DLL .
  程式碼使用的是MFC類,所以只要稍加修改,就可移植到 MFC程式中.
  其實知道RAW 檔案的格式,完全可以嘗試自己編寫一個,也相信你們會寫的比我更好.
  
  
  
  
--------------------------------------------------------------------------------
【經驗總結】
  
  
  
  關於冰點:
  
  冰點無解! 據網上介紹說此軟體至今為找到破解方法.
  其實這話不假,冰點的加密的確強悍.強殼,反載入,反除錯,定時檢測,以服務程式執行,能攔截IO...等技術
  足以讓眾多的 Cracker 望而卻步,縱然是 脫殼高手 + 靜態分析高手,也很無奈.
  因為無法載入它,它需要以服務的形式執行.並且會不斷把窗體置前,以干擾除錯.
  採用多執行緒定時器保護,當某個執行緒檢測到自己或另一個執行緒被暫停,就退出程式.
  以上這些技術對付 OD 很是奏效,所以很有必要認識另一款功能強悍偵錯程式 SOFTICE
  
  一點補充:
  其實冰點6.00.XXX.XXXX  (企業版)的加密方法一樣,只是版本的不同,使程式碼的偏移位置也不同.
  所以解密器只針對與 6.00.220.1692 版,你也可以使用上面的跟蹤方法來跟蹤其它版的冰點.
  找出偏移地址差,只要稍微修改一下程式碼,就能把解密器用於其它版本......
  文章的目的是為了學習除錯方法和密碼演算法,所以不想花過多的時間去寫一個通用與其他版本的解密器.
  我也希望朋友們看這篇文章的時候的收穫是學會用 SOFTICE 除錯冰點,而不是得到冰點的解密器....


  
  在程式碼的註釋中我提到: 密碼演算法的關鍵 CALL,就算跟進也無意義......
  在此我做一下解釋:
  因為就算知道冰點密碼演算法你也很難做成序號產生器,它的並不難.
  只是,冰點把密文資料壓縮並寫入檔案,  你可能知道壓縮後的位置,但卻無法知道它解壓後的資料地址或解壓它
  (應該不會去跟蹤它是用哪一種壓縮引擎壓縮的吧? 萬一發現那壓縮引擎是自寫的呢?).
  知道演算法能奈它何? 唉..............

  
  關於偵錯程式:
  
  OllyDbg ,易用而功能強大的偵錯程式,除了除錯與系統底層相關的一些程式(比如 驅動,ROOTKITS,RING0 程式等)
  OD 幾乎無所不能,其強大的程式碼智慧分析功能是其它眾多偵錯程式所無法比擬的.不可否認OD 是最強使用者級偵錯程式.
  Cracker 們似乎漸漸忘掉曾經偵錯程式中的王者 -- SOFTICE,《看雪論壇精華》中漸漸沒了關於 SOFTICE 破解的文章.
  
  但象冰點這種軟體卻只能用SOFTICE 來解,SOTFICE 是核心級偵錯程式,中斷時連繫統時鐘也一起停了.
  可以不用擔心定時器檢測,所有執行緒都被掛起,作業系統也不例外,所以也不用擔心視窗置前的干擾.
  SOFTICE 是即時撥出,冰點的反載入和偵錯程式的捆綁失敗,不是你所考慮的問題,你只要專心置好斷點就行.
  
  很難相信用 OD 可以解掉此類軟體,筆者也嘗試著OD 來解冰點,結果碰的一鼻子灰.
  
  雖然隨著虛擬計算機技術的不斷成熟和計算機硬體的效能越來越好,價格卻越來越便宜(筆者學計算機近五年了,
  依然記得當初自己的 2500+ 比現在的 3800+ 貴 N 多,唉....,可怕的摩爾定律...)
  SOFTICE 很可能會被功能更為強大的雙機核心偵錯程式 WINDBG ,VISUAL SOFTICE 所替代. 
  但至少在今天,SOFTICE 的強大除錯功能,靈活,穩定.都很值得我們花一些時間學它,並使用它.
  



  文章到此結束,首先,謝謝你能看到這裡. 當然,由於文章寫的倉促錯誤在所難免.
  對文章指正與建議是你對我作品最大的支援與肯定,謝謝你..............

  
--------------------------------------------------------------------------------
【版權宣告】: 本文原創於看雪技術論壇, 轉載請註明作者與出處並保持文章的完整, 謝謝!

                                                       2007年06月12日 上午 09:36:06
 
ps:
 
一些與技術無關的話題:

關於冰點的破解其實不是偶然:
很多天以前網上的一位朋友加了我QQ,他對我說: “我在看雪論壇上找你寫的一篇老文章 ——
《還原精靈密碼演算法分析》, 寫的不錯!......”.後來他又問我對冰點有沒有研究?能不能解一下冰點?
因為冰點還原類軟體的新秀,在此之前我根本沒用過冰點,甚至不知道如何安裝冰點.
但那時的我只看到“寫的不錯!”這些字眼(呵呵,好虛榮的我,總是喜歡把人家的客套話當回事,唉...).
於是想都沒想答應他: “最近忙,過兩個禮拜幫你試試,好久沒 CRACK 了,正好練練手...”
破解冰點加寫成文章花了我一個禮拜多的時間,真後悔當初好強,隨便答應別人試試.

不過這種事不會再有下次,不會再幫別人去專門破解某個軟體了.
因為我也是計算機初學者,並且非計算機專業的,也不興趣於 CRACK ,更不會把 CRACK 當職業.
CRACK 不過是我在學習程式設計和除錯技術時,無心學會的技能,並不刻意學它.
對我來說,學會分析和除錯程式的最大用處是,可以參考別人的程式流程和糾正自己的程式碼.
所以如果你也喜歡程式設計,喜歡 ROOTKIT ,喜歡研究系統底層....,那可能我們興趣相似,我也
很樂意與你相互學習或交流技術.但如果你加我QQ是為了破解某個軟體,那麼請另請高就吧!
因為我的技術的確菜的要命,通常會讓你失望的......






因為解密的方法特殊,所以解密器只專用於 冰點6.00.220.1692 企業版.
寫文章的時候沒有對它宣告是我的疏忽,萬用的冰點解密器我沒興趣編寫(很浪費時間的!)
不過文章中的解法卻不受版本限制,希望能認真閱讀...
 

相關文章