冰點密碼破解 — 強悍的偵錯程式 SOFTICE
標 題: 【原創】冰點密碼破解 — 強悍的偵錯程式 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
作 者: 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 企業版.
寫文章的時候沒有對它宣告是我的疏忽,萬用的冰點解密器我沒興趣編寫(很浪費時間的!)
不過文章中的解法卻不受版本限制,希望能認真閱讀...
關於冰點的破解其實不是偶然:
很多天以前網上的一位朋友加了我QQ,他對我說: “我在看雪論壇上找你寫的一篇老文章 ——
《還原精靈密碼演算法分析》, 寫的不錯!......”.後來他又問我對冰點有沒有研究?能不能解一下冰點?
因為冰點還原類軟體的新秀,在此之前我根本沒用過冰點,甚至不知道如何安裝冰點.
但那時的我只看到“寫的不錯!”這些字眼(呵呵,好虛榮的我,總是喜歡把人家的客套話當回事,唉...).
於是想都沒想答應他: “最近忙,過兩個禮拜幫你試試,好久沒 CRACK 了,正好練練手...”
破解冰點加寫成文章花了我一個禮拜多的時間,真後悔當初好強,隨便答應別人試試.
不過這種事不會再有下次,不會再幫別人去專門破解某個軟體了.
因為我也是計算機初學者,並且非計算機專業的,也不興趣於 CRACK ,更不會把 CRACK 當職業.
CRACK 不過是我在學習程式設計和除錯技術時,無心學會的技能,並不刻意學它.
對我來說,學會分析和除錯程式的最大用處是,可以參考別人的程式流程和糾正自己的程式碼.
所以如果你也喜歡程式設計,喜歡 ROOTKIT ,喜歡研究系統底層....,那可能我們興趣相似,我也
很樂意與你相互學習或交流技術.但如果你加我QQ是為了破解某個軟體,那麼請另請高就吧!
因為我的技術的確菜的要命,通常會讓你失望的......
因為解密的方法特殊,所以解密器只專用於 冰點6.00.220.1692 企業版.
寫文章的時候沒有對它宣告是我的疏忽,萬用的冰點解密器我沒興趣編寫(很浪費時間的!)
不過文章中的解法卻不受版本限制,希望能認真閱讀...
相關文章
- 淺議密碼強度與密碼破解(2)密碼
- 偵錯程式中的斷點是如何設定的?斷點
- 微信偵錯程式
- 偵錯程式工作原理(2):實現斷點斷點
- Process Hacker一款功能強大的系統偵錯程式
- 一小時內破解16位強密碼密碼
- YTUOJ-偵察員的密碼密碼
- 強力破解E-mail密碼三種方法(轉)AI密碼
- Xcode偵錯程式LLDBXCodeLLDB
- go語言偵錯程式Go
- “破解”XP密碼密碼
- js實現的密碼強度提示程式碼JS密碼
- 非常小巧而又強悍的C/C++程式碼檢視器:Source InsightC++
- 動網論壇密碼暴力破解程式程式碼 (轉)密碼
- 偵錯程式工作原理(三):除錯資訊除錯
- 偵錯程式工作原理(3):除錯資訊除錯
- 無線wifi密碼的破解WiFi密碼
- 手工破解solaris密碼的方法密碼
- Python 偵錯程式入門Python
- 偵錯程式到底怎樣工作
- PsySH作為偵錯程式
- 偵錯程式--jdb.exe(轉)
- VBA工程密碼破解密碼
- 短小強悍的JavaScript非同步呼叫庫JavaScript非同步
- Emacs 除錯祕籍之 GUD 偵錯程式Mac除錯
- 反除錯 -- 利用ptrace阻止偵錯程式附加除錯
- 幽默:編寫Python程式碼你們使用什麼偵錯程式?Python
- 與偵錯程式共舞 – LLDB 的華爾茲LLDB
- C 語言偵錯程式是如何工作的?
- 密碼輸入強度提示例項程式碼密碼
- 破解 RHEL7.3 的 root 密碼密碼
- 另一個Swoole偵錯程式 - Yasd
- 偵錯程式是個大騙子!
- GDB偵錯程式(學習筆記)筆記
- u盤破解WiFi密碼WiFi密碼
- Windows密碼破解工具ophcrackWindows密碼
- WiFi密碼破解那些事WiFi密碼
- Excel密碼解除方法 破解Excel密碼