GIF Movie Gear v3.0.2 破解小談(附序號產生器原始碼)

看雪資料發表於2015-11-15

GIF Movie Gear v3.0.2 破解小談(附序號產生器原始碼)
最近在老羅的罈子裡好多人的簽名都換成了PL的圖片。嘿嘿,偶自然也不願落後,so便想自己DIY一個英俊瀟灑玉樹臨風貌比潘安才比伯虎的掛上去,可是以前買的Flash MX D版盤怎麼也找不到了,於是便到天空那邊兒去找做GIF動畫的軟體,再於是便找到了這個軟體,據說是使用簡單,方便快捷…
結果,呵呵(冷汗…搞了一個上午也沒搞出張像樣的圖片來)。偷雞不成,怎麼也要抓一把米回來吧,反正今天除了沒完成的事兒其它的事兒都做完了… ;)
首先當然是先要看一下人家有沒有加殼,結果是另人滿意的,過程是另人愉快的,答案是VC6.0的。^_^具然沒加殼…
那還等什麼呢?點Help選單中的Register Now…。接著就撥出你埋伏已久的偵錯程式吧,我用的是TRW2000。(隨便問一句哥們兒,TRW2000撥出是按Ctrl+N這事兒你知道吧,知道啊。那上海2010年辦世博會,這事兒你也知道吧,哦,都知道了,那甲A前天晚上…當!…好好好,我繼續就是了)撥出TRW2000後下斷點bpx hmemcpy(我用的是98嘛),然後按F5返回。接著在Name處偶輸入Suunb[CCG],在Code處輸入20030413(呵呵,今天的日期 ^_^) 好的,接下來就按OK吧。
結果是顯而易見的,成功被我軍愛國者導彈給攔截掉了。之後就一個pmodule導彈過去跳出程式的領空,之後在按F12的時候會發現只按1次就提示出錯了。
好的,知道這些後,就再來一遍吧。這次在pmodule返回後就按F10來單步執行,程式碼如下:
0167:00431972  lea      edx,[esp+c4]             <--會來到這裡!
0167:00431979  push     byte +64
0167:0043197b  push     edx
0167:0043197c  push     dword 0450
0167:00431981  push     esi
0167:00431982  call     edi                      <--看上邊兒壓進去的引數,這個Call應該是呼叫API函式GetDlgItem來得到註冊碼輸入框的控制程式碼。
0167:00431984  push     eax
0167:00431985  call     ebx                      <--用先前得到的註冊碼輸入框的控制程式碼透過呼叫GetWindowTextA來得到輸入的註冊碼
0167:00431987  lea      eax,[esp+c4]             <--用d指令可以知道esp+c4處裝的是使用者輸入的註冊碼,將這個地址裝入eax中
0167:0043198e  lea      ecx,[esp+60]             <--同樣用d指令可以知道esp+60處裝的是使用者輸入的註冊名,裝其地址裝入ecx中
0167:00431992  push     eax                      <--註冊碼地址壓棧
0167:00431993  push     ecx                      <--註冊名地址壓棧
0167:00431994  call     00431590                 <--嘿嘿,整個過程就由這個CALL一手操控了
0167:00431999  add      esp,byte +08             <--棧頂還原
0167:0043199c  test     eax,eax                  <--測試eax中裝入的值
0167:0043199e  jz       near 00431a51            <--為0就跳到00431a51處,跳過去就Over了
0167:004319a4  lea      edx,[esp+10]             <--從這裡開始程式透過呼叫RegCreateKeyExA、RegSetvalueExA等其它一些登錄檔相關API來向登錄檔中寫入使用者的註冊資訊。也就是HKEY_CURRENT_USER\Software\gamani\GIFMovieGear\2.0主鍵下面的RegName3與RegCode3子鍵。當然這是在你輸入的註冊碼正確的前提下,RegName3中裝的是你的註冊名,RegCode3中自然就是你輸入的冊碼了…
0167:004319a8  lea      eax,[esp+0c]
0167:004319ac  push     edx
0167:004319ad  push     eax
0167:004319ae  push     byte +00
0167:004319b0  push     dword 000f003f
0167:004319b5  push     byte +00
0167:004319b7  push     dword 0044ed14
0167:004319bc  push     byte +00
0167:004319be  push     dword 0044b3f8           <--此處可以看一下0044b3f8,得到Software\gamani\GIFMovieGear\2.0
0167:004319c3  push     dword 80000001           <--這個值就是HKEY_CURRENT_USER
0167:004319c8  call     `ADVAPI32!RegCreateKeyExA`   <--API函式RegCreateKeyExA    
0167:004319ce  lea      edi,[esp+60]
0167:004319d2  or       ecx,byte -01
0167:004319d5  xor      eax,eax
0167:004319d7  mov      edx,[esp+0c]
0167:004319db  repne scasb
0167:004319dd  not      ecx
0167:004319df  mov      ebx,[00448018]
0167:004319e5  push     ecx
0167:004319e6  lea      ecx,[esp+64]
0167:004319ea  push     ecx
0167:004319eb  push     byte +01
0167:004319ed  push     eax
0167:004319ee  push     dword 0044d498           <--0044d498處就是字串RegName3
0167:004319f3  push     edx
0167:004319f4  call     ebx                      <--RegSetvalueExA
0167:004319f6  lea      edi,[esp+c4]
0167:004319fd  or       ecx,byte -01
0167:00431a00  xor      eax,eax
0167:00431a02  repne scasb
0167:00431a04  not      ecx
0167:00431a06  lea      eax,[esp+c4]
0167:00431a0d  push     ecx
0167:00431a0e  mov      ecx,[esp+10]
0167:00431a12  push     eax
0167:00431a13  push     byte +01
0167:00431a15  push     byte +00
0167:00431a17  push     dword 0044d4a4           <--0044d4a4嘛,就是字串RegCode3
0167:00431a1c  push     ecx
0167:00431a1d  call     ebx                      <--RegSetvalueExA
0167:00431a1f  mov      edx,[esp+0c]
0167:00431a23  push     edx
0167:00431a24  call     `ADVAPI32!RegCloseKey`
0167:00431a2a  push     dword 0044d4b0
0167:00431a2f  push     dword 80000002
0167:00431a34  call     `ADVAPI32!RegDeleteKeyA`
0167:00431a3a  push     byte +01
0167:00431a3c  push     esi
0167:00431a3d  call     `USER32!EndDialog`       <--用EndDialog來關掉輸入註冊碼的這個對話方塊
0167:00431a43  pop      edi
0167:00431a44  pop      esi
0167:00431a45  xor      eax,eax
0167:00431a47  pop      ebx
0167:00431a48  add      esp,011c
0167:00431a4e  ret      10                       <--返回
0167:00431a51  push     byte +30                 <--在前邊兒0043199c處如果沒透過就會跳到這裡,到了這裡就一切都玩兒完了 ;)
0167:00431a53  push     dword 9d15
0167:00431a58  push     dword 9d14
0167:00431a5d  push     esi
0167:00431a5e  call     0040ee90
0167:00431a63  add      esp,byte +10
0167:00431a66  push     dword 044f
0167:00431a6b  push     esi
0167:00431a6c  call     edi
0167:00431a6e  push     eax
0167:00431a6f  call     `USER32!SetFocus`
0167:00431a75  pop      edi
0167:00431a76  pop      esi
0167:00431a77  xor      eax,eax
0167:00431a79  pop      ebx
0167:00431a7a  add      esp,011c
0167:00431a80  ret      10

HeHe~~很明顯吧,00431994處的那個CALL就是關鍵的所在嘛。
也就是說如果在00431994處的那個CALL中程式確定註冊碼是正確的話就會將其與使用者名稱一同輸入進登錄檔,以後每次程式啟動的時候都會進行比較。But你輸入的是錯誤的話嘛,程式就懶得去寫進登錄檔了。所以我們儘管可以在0043199c處的時候用r fl z指令來欺騙程式,但一點兒用都沒有 (眾人:那你說它幹嘛)
那接著就再來一遍,這次就可以直接用斷點bpx 00431994了。斷到後就按F8跟進去吧:
0167:00431590  push     ebx
0167:00431591  push     ebp
0167:00431592  mov      ebp,[esp+10]             <--將註冊碼的地址裝入ebp中
0167:00431596  push     esi
0167:00431597  push     edi
0167:00431598  cmp      byte [ebp+00],6d         <--ebp+00也就是註冊碼的第一位,用註冊碼的第一位與6d相比(6d即m的ASCII碼)
0167:0043159c  jnz      near 00431642            <--第一位不是m就跳到00431642處,跳過去就玩兒完了。呵呵,我輸入的是20030413,在這裡就掛掉了,再來一遍,這次把前4位改成mg37,即mg3720030413
0167:004315a2  cmp      byte [ebp+01],67         <--判斷註冊碼的第2位是否為g
0167:004315a6  jnz      near 00431642
0167:004315ac  cmp      byte [ebp+02],33         <--同理,判斷第3位是否為3
0167:004315b0  jnz      near 00431642
0167:004315b6  cmp      byte [ebp+03],37         <--第4位是否為4
0167:004315ba  jnz      near 00431642
0167:004315c0  mov      ebx,0044d4c4        
0167:004315c5  mov      edx,[ebx]          
0167:004315c7  or       ecx,byte -01          
0167:004315ca  mov      edi,edx            
0167:004315cc  xor      eax,eax              
0167:004315ce  repne scasb
0167:004315d0  not      ecx
0167:004315d2  dec      ecx
0167:004315d3  mov      edi,edx
0167:004315d5  mov      esi,ebp
0167:004315d7  xor      eax,eax              
0167:004315d9  repe cmpsb                  
0167:004315db  jz       00431642            
0167:004315dd  add      ebx,byte +04
0167:004315e0  cmp      ebx,0044d4c8
0167:004315e6  jl       004315c5
0167:004315e8  cmp      byte [ebp+04],73         <--比較看註冊碼的第5位是否為s,ebp中裝的其實是註冊碼的地址,這點很重要,後邊兒會有說明
0167:004315ec  jnz      004315ef                 <--不是就跳到004315ef處
0167:004315ee  inc      ebp                      <--是的話ebp+1
0167:004315ef  add      ebp,byte +07             <--ebp加上7
0167:004315f2  push     ebp                      <--ebp入棧
0167:004315f3  call     0043f3c8                 <--!!
0167:004315f8  mov      edx,[esp+18]
0167:004315fc  add      esp,byte +04
0167:004315ff  mov      edi,edx
0167:00431601  xor      ecx,ecx                  <--ecx清0
0167:00431603  mov      dl,[edx]                 <--裝入註冊名中的第一個字元
0167:00431605  mov      esi,0bdf                 <--esi中裝入0bdf,即十進位制數3039
0167:0043160a  test     dl,dl                    <--看dl中是否為0
0167:0043160c  jz       00431634
0167:0043160e  movsx    edx,dl                   <--霸佔整個edx暫存器 ;)
0167:00431611  inc      ecx                      <--ecx加1
0167:00431612  imul     edx,ecx                  <--用edx中此時裝入的註冊名中的某一位字元乘的ASCII碼乘以ecx中的值
0167:00431615  add      esi,edx                  <--用esi中的值加上edx中的值
0167:00431617  cmp      esi,17be                 <--用esi中的值與17be,即十進位制數6078比較
0167:0043161d  jng      00431625                 <---不大於不跳到00431625處
0167:0043161f  sub      esi,17be                 <--大於的話就減去它
0167:00431625  cmp      ecx,byte +0a             <--用A(也就是10)與ecx中的值比較
0167:00431628  jng      0043162c                 <--不大於就跳到0043162c處
0167:0043162a  xor      ecx,ecx                  <--ecx清0
0167:0043162c  mov      dl,[edi+01]              <--dl中裝入註冊名中的下一個字元
0167:0043162f  inc      edi                      <--edi加上1
0167:00431630  test     dl,dl                    <--測試dl
0167:00431632  jnz      0043160e                 <--不為0就跳加0043160e處繼續用下一位來進行計算
0167:00431634  cmp      esi,eax                  <--比較esi與eax中的值,esi中裝入的就是前邊兒0043160e-00431632處將註冊名中各位字元進行計算後的值,而eax中的值是透過004315f3處的這個CALL裝進來的,相對於我輸入的這個註冊名及註冊碼,它的值是76CD,也就是十進位制數30413。
0167:00431636  jnz      00431642                 <--不相等就跳到00431642處
0167:00431638  pop      edi
0167:00431639  pop      esi
0167:0043163a  pop      ebp
0167:0043163b  mov      eax,01                   <--相等的話就繼續執行到這裡,並將eax置1,我們已經知道出來後會比較看eax是否為0,是的話就Game Over
0167:00431640  pop      ebx
0167:00431641  ret    
0167:00431642  pop      edi                      <--從前面跳過來的話就…
0167:00431643  pop      esi
0167:00431644  pop      ebp
0167:00431645  xor      eax,eax                  <--可惡吧,會將eax置0
0167:00431647  pop      ebx
0167:00431648  ret    

我認為我有必要講一下,其實這並不難理解。在004315e8處的時候我們可以透過d指令知道ebp中裝的其實就是註冊碼的地址,在004315e8處的時候會比較註冊碼的第5位是否為s,是的話就將ebp加上1。而到了004315ef處的時候會將ebp加上7,之後就將這個地址壓棧了。過了004315f3處的那個CALL後EAX中的值就會改變了,完全不必要追進去,猜也能猜出來了。呵呵,這個CALL的作用就是將之前004315f2處壓入的ebp中的地址處開始的值裝入eax中。而ebp中裝的就是註冊碼的第7位的地址,明白過來了嗎?註冊碼從第7位開始的值就是程式真正要用的 ;)可問題是第7位以後還有幾位呢?嘿嘿,這個很容易就能發現,在00431617的時候程式不是會判斷esi中的值是否大於6078嗎?而6078,也就是6078只有4位,所以嘛,註冊碼的位數就是7+4即11位!不過在004315e8和我們會發現程式會判斷註冊碼的第5位是否為s,是的話就接著將ebp加上1,所以問題就解決了。正確的註冊碼位數只有兩種情況:一種是11位,另一種是12位,這個12位的第5位是一個固定不變的,即s。
呵呵,我們來看一下正確的註冊碼的格式吧,第一種11位的是mg37XXXXXXX,另一種12位的是mg37sXXXXXXX。
現在我們知道的已經夠多了,那就寫序號產生器吧 ;)
這之前再大概說一遍程式註冊碼的計算過過程:
首先固定不變的是程式註冊碼的前4位,永遠是mg37,然後有一個可有可無的位,即第5位,要這一位的話,就讓它為s (注意如果註冊碼的第5位是s,那就應該在其後再補上3位),否則就不要它而直接在mg37後邊兒隨便補充3位,就比如說CCG ^_^。而接下來就是最後4位了,這個也是重要的地方所在了 ;) 後4位的計算過程其實也不難,就是用你輸入的註冊名的首位字元的ASCII碼乘以X(X每計算一位字元就加上1,如果值後來一直累加到11,就會還原為0)。再用這個乘積加上3039。並將其儲存起來,這裡稱它為Y,之後比較Y是否大於6078,如果大於就用Y減去6078。接下來第二位字元參加運算,同樣用其值乘以X,然後加上Y,再比較Y是否大於6078,再接下來第三位字元參加運算,用其乘以X,然後加上Y…直到所有字元均參加完運算…
BTW:如果字元參加完運算後得到的是一個3位有效值,比如123,就在1的前邊兒補上一個0,如0123。
貼的這個是序號產生器原始碼是Delphi的,直接宣告這個函式就能用了:
function KeyGen(Name: String): String;
var
 i,Cnt,vai,ASC:integer;
 Serial:String;
begin
 Cnt:=3039;
 vai:=0;
 for i:=1 to Length(Name) do
   begin
     inc(vai);
     ASC:=Ord(Name[i]);
     ASC:=ASC*vai;
     Cnt:=Cnt+ASC;
     if Cnt>6078 then Cnt:=Cnt-6078;
     if vai>10 then vai:=0;
   end;
 Serial:=inttostr(Cnt);
 Case Length(Serial) of
  3:Serial:='0'+Serial;
  2:Serial:='00'+Serial;
  1:Serial:='000'+Serial;
 end;
 Serial:='mg37CCG'+Serial;
 Result:=Serial;
end;

OK,就這些。

相關文章