破解OICQ的密碼演算法 (6千字)

看雪資料發表於2001-06-25

這篇文章和OICQ本身沒有什麼聯絡,我只是想講一下程式破解的原理和方法,我在
這裡會儘量用易懂的語言來描述,如果你是一個初學者,那麼,此文就是為你而寫的。

  我以OICQ99C 0820版為例,其它版本如OICQ2000
的破解方法基本上和此版本沒有區
別。
  
首先,在OICQ目錄下,每個使用者號碼下有一個叫matrix.cnt的檔案,此檔案的長
度是20位元組,它的內容就是此號碼的原密碼經過加密後對應的密文。要證明這一點非常
容易,只要稍有一點電腦能力的人都可以證明,所以這裡我就不費口舌了。在正式開始
前,請用二進位制編輯器開啟此檔案,熟悉一下內容。
  
啟動OICQ,出現OICQ使用者登入畫面,選擇你自己的號碼,然後輸入一個錯誤的密碼
,此時按CTRL+D進入SOFTICE畫面,設定斷點。我們事先應該都知道OICQ檢查密碼是否正

確的工作原理,即:先用GetWindowText()來取得密碼框中的密碼字串,將此字串用
其內定的演算法進行加密,得出加密後的密文,然後從磁碟中讀取matrix.cnt,與使用者輸
入的密碼的加密結果進行比較,如果相同,則使用者輸入的密碼為正確密碼。(或者先讀
檔案,後讀取密碼框中的值)跟據這個原理,這們應該把斷點設在readfile上,即輸入
:bpx
readfile。返回程式介面,點選“登入”,出現SOFTICE的畫面,指標停在KERNE
L32!READFILE上。按一下F12跳過此函式,將進入OICQ的領空。
  
我們現在要做的就是特別注意轉折語句,就是JZ,JNZ,JMP等第一個字元是J的語句
。因為這們己經假設,程式中必定存在一行轉折語句,當使用者輸入的是正解密碼時,它
跳轉(或不跳轉),而當使用者輸入錯誤密碼時,它不跳轉(或跳轉)。小心地按F10單步
執行程式碼,在出現轉折語句處設下一斷點(只是做一個記號),並且記錄它們的跳轉情
況(經驗豐富者知道哪裡有必要下斷點而哪裡沒有必要),直到程式出現密碼錯誤的對
話框為止。
  
這時候你可能己經花去了1分鐘的時間。好的,現在輸入正確的密碼作為比較。同樣
單步地執行程式碼,你將看到上次你在跳轉語句上作的記號。比較兩次的跳轉是否相同。

  你將看到,當程式執行到這裡時,前後兩次的跳轉方向不同:
...
00441C1B  call 0046c256
00441C20  cmp eax, ebx
00441C22  jz 00441C28----->就是這裡!
00441C24  mov esi, edi
...

分析一下這幾個程式碼,它首先呼叫函式0046C256,然後比較EAX與EBX的值,如果EAX與E
BX的值相同,就跳轉。我們重新執行程式,發現當輸入正確密碼時,EAX=1,當輸入錯誤
密碼時,EAX=0,而EBX總是0。所以,函式0046C256是一個可疑的函式!
  按F8進入函式0046C256,我們要看看它做了什麼工作。
:0046C256  mov eax, 004CD33C
:0046C25B  call 00486B88
:0046C260  sub esp, 00000010
:0046C263  push esi
:0046C264  push edi
:0046C265  mov esi, ecx
:0046C267  mov eax, dword ptr [ebp+08]
:0046C26A  and dword ptr [ebp-04], 00000000
:0046C26E  push [eax-08]
:0046C271  push eax
:0046C272  lea eax, dword ptr [ebp-1C]
:0046C275  push eax
:0046C276  call 00456718
:0046C27B  add esp, 0000000C
:0046C27E  push 00000001
:0046C280  pop edi
:0046C281  cmp dword ptr [esi+04], edi
:0046C284  jbe 0046C29E

:0046C286  lea eax, dword ptr [ebp-1C]
:0046C289  push 00000010
:0046C28B  push eax
:0046C28C  lea eax, dword ptr [ebp-1C]
:0046C28F  push eax
:0046C290  call 00456718
:0046C295  add esp, 0000000C
:0046C298  inc edi
:0046C299  cmp edi, dword ptr [esi+04]
:0046C29C  jb 0046C286
:0046C29E  int 03
:0046C29F  mov byte ptr [eax], 6A
:0046C2A2  adc byte ptr [ebp+5056E445], cl
:0046C2A8  call 00487900
:0046C2AD  mov esi, eax
:0046C2AF  add esp, 0000000C
:0046C2B2  neg esi
:0046C2B4  sbb esi, esi
:0046C2B6  or dword ptr [ebp-04], FFFFFFFF
:0046C2BA  lea ecx, dword ptr [ebp+08]
:0046C2BD  inc esi
:0046C2BE  call 004A0665

:0046C2C3  int 03
:0046C2C4  dec ebp
:0046C2C5  hlt
:0046C2C6  mov eax, esi
:0046C2C8  pop edi
:0046C2C9  pop esi
:0046C2CA  mov dword ptr fs:[00000000], ecx
:0046C2D1  leave
:0046C2D2  ret 0004
...
  按F10單步執行。我們發現在這個函式中有一個非常有意思的地方:
:0046C286  lea eax, dword ptr [ebp-1C]
:0046C289  push 00000010
:0046C28B  push eax
:0046C28C  lea eax, dword ptr [ebp-1C]
:0046C28F  push eax
:0046C290  call 00456718
:0046C295  add esp, 0000000C
:0046C298  inc edi
:0046C299  cmp edi, dword ptr [esi+04]
:0046C29C  jb 0046C286
程式反覆地執行這些程式碼!!

為了能看的更清楚些,我用C++語言來簡述這幾個語句:
for( long i=0 ; i< *(esi+04) ; i++)
{
eax=*(ebp-1c);
呼叫函式 00456718;
}
就是說,函式00456718要被呼叫很多次,這個次數就是ESI+04的值,用D
ESI+04命令來
檢視其值,天哪!這不是matrix.cnt的內容嗎?(你原先在二進位制編輯器中己經開啟過
此檔案並且看到過它的內容)而ESI+04正是matrix.cnt的前4個位元組!我們現在有足夠的
理由相信,密碼被加密成了128位(即16個位元組),且加密函式存在於函式00456718中!

  
抬起眼睛看一下,在函式0046C256中,一開始也呼叫了一次00456718函式!為了再
進一步地證實我們的設想,讓我們再重新執行OICQ,輸入一個錯誤的密碼,但這次你輸
入的密碼長度最好和正確密碼的長度相同,在第一次呼叫00456718前設下一個斷點:
:0046C265  mov esi, ecx
:0046C267  mov eax, dword ptr [ebp+08]
:0046C26A  and dword ptr [ebp-04], 00000000----->在這裡設一個斷點
:0046C26E  push [eax-08]
:0046C271  push eax
:0046C272  lea eax, dword ptr [ebp-1C]
:0046C275  push eax
:0046C276  call 00456718

  
當程式執行至斷點處時,檢視各個暫存器的值,你在EAX裡看到了什麼?是的,EAX
裡面是你輸入的密碼,你用這個密碼進行登入,程式將出現密碼錯誤的資訊,但是,如
果你此時修改一下EAX的值,把它改為正確的密碼,你又驚喜地發現:OICQ己經成功地登
錄了!注意:只要你稍微留意一下,EAX-8的值正是密碼的長度。以上的事實己經證明了
:函式00456718就是OICQ的加密函式。
  
跟據種種跡象,這個函式具體是什麼演算法,學過密碼學的朋友己經不用往下看了。
但我們還必須深入證實。
  按F8,將看到此函式:
:00456718  push ebp
:00456719  mov ebp, esp
:0045671B  sub esp, 0000005C
:0045671E  lea eax, dword ptr [ebp-5C]
:00456721  push eax
:00456722  call 00455A6E
:00456727  push [ebp+10]
:0045672A  lea eax, dword ptr [ebp-5C]
:0045672D  push [ebp+0C]
:00456730  push eax
:00456731  call 00455AA9
:00456736  lea eax, dword ptr [ebp-5C]
:00456739  push eax
:0045673A  push [ebp+08]

:0045673D  call 004565FD
:00456742  add esp, 00000018
:00456745  leave
:00456746  ret
函式看上去很短小,但它又呼叫了三個函式。檢視第一個函式:
:00455A6E  push esi
:00455A6F  mov esi, dword ptr [esp+08]
:00455A73  push 0000005C
:00455A75  push 00000000
:00455A77  push esi
:00455A78  call 00486FD0
:00455A7D  and dword ptr [esi+10], 00000000
:00455A81  and dword ptr [esi+14], 00000000
:00455A85  and dword ptr [esi+58], 00000000
:00455A89  add esp, 0000000C
:00455A8C  mov dword ptr [esi], 67452301
:00455A92  mov [esi+04], EFCDAB89
:00455A99  mov [esi+08], 98BADCFE
:00455AA0  mov [esi+0C], 10325476
:00455AA7  pop esi
:00455AA8  ret
  
看到標有紅色的四個語句了嗎?加密函式在一開始設定了4個32位的常數!!接下來
,在函式00455D5A中連續出現了64次諸如:

00455D60  mov edi, dword ptr [ebp+08]
00455D63  xor ebx, edx
00455D65  add ebx, dword ptr [eax]
00455D67  lea edi, dword ptr [edi+ebx-28955B88] ;注意,這是個常數!
00455D6E  mov ebx, edi
形式的語句。至此為止,OICQ用的是什麼加密演算法,己經是不言而明瞭

相關文章