翻譯一篇寫序號產生器的教程!大俠就不要看了 (5千字)

看雪資料發表於2001-07-18

原著:raZZia
翻譯:TAE![CCG]
    呵呵,今日閒來無事,碰巧最近對寫序號產生器感興趣所以翻譯了一篇寫序號產生器的教
    程,較簡單,不知有沒有大俠翻過。有疏漏錯誤的地方還請各位更正!
工具!
    你需要一個像softice那樣的Windows下的除錯軟體,和一個Dos庫C編譯器
   

內容!
    在這篇教程中我將告訴你如何做一個序號產生器,軟體用的保護方式是很眾所周知的
    輸入姓名和註冊碼的方式,在選擇註冊後,一個視窗彈了出來,那就是你要輸入
    名字和註冊碼的地方,這兒的對策就是在記憶體中找出輸入的資料,在你繼續之前
    你必須確定你已經根據PWD的教程一設定了softice.dat檔案
       
軟體 1: Scanline Swiftsearch 2.0!
    Swiftsearch 是一個很有用的小工具,你可以用它來在網路中搜尋,我將一步步
    的告訴你如何破解它!
   
    步驟 1: 執行程式 :)

    步驟 2: 選擇選單重的“註冊”,你將發現一個可以輸入姓名和註冊碼的視窗。

    步驟 3: 進入softice (ctrl-d)

    步驟 4: 我現在將設定一個像GetWindowText(a)和GetDlgItemText(a)這樣的斷點
    來找到記憶體中我們剛剛輸入的資料。能夠被用於這個程式的函式僅僅是GetDlgItemTexta
    (對與錯還是你自己試試吧 :)所以,在SoftIce中輸入 BPX GetDlgItemTexta
    然後用 g 命令退出SoftIce。

    步驟 5: 現在輸入名字和註冊碼(我使用的是 razzia 和 12345)並且按 OK,這將帶
    你回到SoftIce,現在你已經在GetDlgItemTexta函式中了,按 F11離開函式。你應
    該看到下面的程式碼:
   
    lea eax, [ebp-2C]          ;<--- 我們在找這個位置(?不理解)
    push eax
    push 00000404
    push [ebp+08]
    call [USER32!GetDlgItemTextA]
    mov edi, eax              ;<--- eax 已經指向字串長度了,並且一會兒
                                      就會被儲存到 edi 中了。

    我們看見 EAX 讀入了一個記憶體地址並且作為函式GetDlgItemTextA的一個引數被
    壓進了堆疊中,而後函式GetDlgItemTextA準備開始執行了,我們來檢視 EBP-2c
    (用 ED EDP-2c)並且可以看見那兒有我們輸入的名字,現在我們知道我們的名字
    被存放在記憶體中的什麼地方了,通常應該把這個地址記下來,但我們即將看到,
    那是不必的。
     
    那麼,下一步做什麼? 現在我們必須跟著程式來讀取我們輸入的註冊碼。輸入 g 我
    們再次返回softice的時候按F11,你將看到下面的程式碼:

    push 0000000B
    lea ecx, [ebp-18]        ;<--所以, ebp-18 是存放輸入的註冊碼的地方
    push ecx                 
    push 0000042A
    push [ebp+08]
    call [USER32!GetDlgItemTextA]
    mov ebx, eax              ;<--將字元長度儲存在 EBX 中
    test edi, edi            ;<--還記得 EDI 是放我們輸入名字長度的地方嗎?
    jne 00402FBF             

    我們看見我們輸入得註冊碼被存放在 EBP-18 中了 ,不相信得話可以用ED EBP-18
    檢視一下。 通常這個地址也應該記下來,並且我們看見它檢查我們的名字長度是
    否是0,如果不是的話,程式將繼續。
   
    步驟 6: 那好,現在我們知道我們輸入的資料被存放在哪裡了。那麼,下一步呢?
    現在我們已經知道怎樣做了,通常我們應該在記憶體中設定斷點以便於知道程式哪些
    地方讀取了這裡。但在這個步軟體裡僅僅需要按住F10,直到呢看見了以下程式碼:
   
    cmp ebx, 0000000A      ;<--記得 EBX 是放輸入註冊碼長度的地方嗎?
    je 00402FDE           

    這兩行很重要!它們檢查了輸入註冊碼的長度是否等於10。如果不是,那麼程式就
    已經認為註冊碼是錯誤的了。修改 EBX 或者在暫存器資料視窗修改標誌位暫存器(FLAG)
    以便讓程式跳轉.繼續按F10知道呢到達下面的程式碼處。
    (記住,這可能和你的地址不一樣!)

    :00402FDE xor esi, esi        ;<-- 清空 ESI
    :00402FE0 xor eax, eax        ;<-- 清空 EAX
    :00402FE2 test edi, edi
    :00402FE4 jle 00402FF2
    :00402FE6 movsx byte ptr ecx, [ebp + eax - 2C] ;<-- ECX 載入我們輸入名字的一個字母.
    :00402FEB add esi, ecx        ;<-- 將字母加到 ESI
    :00402FED inc eax            ;<-- EAX 加1以便得到下一個字母
    :00402FEE cmp eax, edi        ;<-- 取完了嗎?
    :00402FF0 jl 00402FE6        ;<-- 如果沒有,就去取下一個字母。

    好的,我們看見程式將我們輸入名字的所有字母加起來,那麼 ESI 就是總和了,讓
    我們繼續並且找出程式用那個值做什麼!

    :00402FF2 push 0000000A
    :00402FF4 lea eax, [ebp-18]  ;<-- 將輸入註冊碼的地址放入 EAX
    :00402FF7 push 00000000
    :00402FF9 push eax            ;<-- 壓入 EAX (作為下面一個Call的引數)
    :00402FFA call 00403870      ;<-- 好的,你認為這個Call是幹什麼的呢?:)
    :00402FFF add esp, 0000000C
    :00403002 cmp eax, esi        ;<-- 嘿!
    :00403004 je 00403020

    我們進入CALL,它最終反回 ESI,並和 EAX 比較.嗯,讓我們看看 EAX 是什麼。‘? EAX’顯示
    00003039 0000012345 "09"

    好極了!那是我們輸入的註冊碼! 那麼ESI呢?我們知道,ESI中是我們輸入名字
    的所有字母總和!!

    步驟 7: 現在我們知道程式是如何計算註冊碼的了,我們可以做序號產生器了!
    但別忘了程式檢查了註冊碼是不是10位!
    一個簡單的C程式將計算出這個軟體的註冊碼:

    #include  <stdio.h>
    #include  <string.h>
    main() {
        char Name[100];
        int NameLength,Offset;
        long int Reg = 0, Dummy2 = 10;
        int Dummy = 0;
        int LengtDummy = 1;
        int Lengt , Teller;
        printf("Scanline SwiftSearch 2.0 crack by raZZia.\n");
        printf("Enter your name: ");
        gets(Name);
        NameLength=strlen(Name);

    /* 計算輸入的名字字元的總和*/
    /* 並儲存到Reg中          */
        for (Offset=0;Offset<NameLength;Offset=Offset+1) {
          Reg=Reg+Name[Offset];
        }

    /* the while lus calculates the lenght of the figure in */
    /* Reg and places it in Lengt                          */
        while (Dummy != 1) {
          if ( Reg < Dummy2 ) {
              Lengt = LengtDummy ; Dummy =1;
          }
              else {
                LengtDummy=LengtDummy + 1; Dummy2=Dummy2*10;
              }
        };

        printf("\nYour registration number is : " );

    /* 收先列印(10-Lengt)次0        */
        Lengt=10-Lengt;
        for (Teller=1;Teller<=Lengt;Teller=Teller+1) printf("0");
    /* 列印註冊碼                    */
        printf("%lu\n",Reg);
    }

相關文章