序號產生器寫作教學。奉賢給想加入CCG和BCG的朋友。 (11千字)

看雪資料發表於2001-10-21

前些天在論壇看到有人問軟體的演算法是如何看懂的 ??序號產生器是如何寫出來的??有感於目前看雪教學中沒有這方面的內容(對於不是明碼比較的序號產生器工具就都沒有辦法了)。於是這篇文章出爐了.由於我對程式設計方面的技術實在是那個。所以拉來了halfbit(雲觀)老哥。讓他幫忙寫ASM,VC的序號產生器。我自己來寫VB的。
本文的目的是透過一個簡單的CRACKME的破解來說一下演算法的分析和序號產生器的寫作(針對於NAME/SERIAL保護的)。奉獻給想加入BCG和CCG的破解愛好者。我儘量寫的詳細點。如有不明之處請發信到llmen@sina.com
工具:偵錯程式一個(我用的是TRW2000)。程式設計工具一個。iceClock。

技術要求:熟悉基本的彙編指令。偵錯程式的運用。程式設計基礎(什麼 ??你說你不會。。。。那就去找一本書了。一般看完前4章就可以了。由於能力原因只給出了VB,VC,ASM的序號產生器原始碼。)

目標:http://www.cracknow.com/crackme/figugegl.1.zip    2KB。偽裝者那裡的。加了自己寫的殼,入口點是0040147B。
選目標可讓我費了些工夫。一開始halfbit讓我找個軟體,可是我沒找到簡單點的。才想到CRACKME,又小又簡單。可是手頭只有CCG和BCG的考試CRACKME。不過為了生命安全著想我還是用別的吧。:)
廢話說完了,現在我們開始。

啟動TRW2000和CRACKME。輸入姓名:liuliu,註冊碼:98765,用HMEMCPY做斷點。點下CHECK。斷下來,用PMODULE回到程式領空。跟蹤的時候要注意暫存器EAX,EBX,ECX,EDX,ESI,EDI的變化。用D命令檢視內容。
:0040132B E80C020000              call 0040153C                               
:00401330 89C6                    mov esi, eax                                  我們在這裡,
:00401332 83FE05                  cmp esi, 00000005                            比較姓名長度是不是小於5 。
這裡看看ESI裡的數值。是6。我的姓名輸入是liuliu。長度是6。所以是比較長度。你問為什麼知道是姓名長度 ??經驗啦。你不知道是比較什麼可以改變一下NAME或SERIAL的長度看看。   
:00401335 7D04                    jge 0040133B                                  不小就跳
:00401337 31C0                    xor eax, eax
:00401339 EB44                    jmp 0040137F                                  小於就掛。
:0040133B 6A14                    push 00000014
:0040133D 8D45D6                  lea eax, dword ptr [ebp-2A]
:00401340 50                      push eax             
:00401341 6A66                    push 00000066
:00401343 53                      push ebx
:00401344 E8F3010000              call 0040153C                                這個是取SERIAL的長度。
:00401349 09C0                    or eax, eax                                  看看EAX是不是0,也就是是不是註冊碼沒有輸入。
:0040134B 7432                    je 0040137F                                  是0就掛
:0040134D 31FF                    xor edi, edi                                  EDI變0,用來做計數器。
:0040134F EB15                    jmp 00401366                                  跳到演算法開始。
:00401351 0FBE443DD6              movsx eax, byte ptr [ebp+edi-2A]              這是姓名第一個字元入EAX。看看EAX裡的數值。是6C。l的ASCII碼就是6C。所以我找到地方了。:)
:00401356 0FBE543DEB              movsx edx, byte ptr [ebp+edi-15]              這裡是註冊碼第一個字元入EDX。看看EDX的數值。是39。9的ASCII碼就是39。
:0040135B 29FA                    sub edx, edi                                  用註冊碼第一個字元的ASCII碼減去EDI(現在為零)。EDX=69。
:0040135D 39D0                    cmp eax, edx                                  比較EAX和EDX是否相等。當然不等了EAX=6C,EDX=39。
:0040135F 7404                    je 00401365                                  相等就繼續。跳(這裡用r fl z強行跳過。)
:00401361 31C0                    xor eax, eax
:00401363 EB1A                    jmp 0040137F                                  不等就掛。
 
:00401365 47                      inc edi                                      計數器EDI加1。

:00401366 39F7                    cmp edi, esi                                  比較EDI是否等於ESI(姓名長度),也就是註冊碼是否計算完畢。
:00401368 7CE7                    jl 00401351                                  相等就結束。不等繼續。到這裡第一次迴圈結束。第一位註冊碼驗證完畢。在0040135D這裡是關鍵的比較。以後的幾次迴圈演算法是一樣的,只是數值不同。演算法弄的差不多了。後面總結一下。
:0040136A 6A00                    push 00000000
:0040136C 6848204000              push 00402048
:00401371 6850204000              push 00402050
:00401376 53                      push ebx
:00401377 E8E4010000              call 00401560                                註冊成功!
演算法總結:程式的流程是這樣子的
1,比較輸入姓名的長度是不是小於5。
2,比較註冊碼是不是沒有輸入。
3,演算法開始,第1位註冊碼要等於第1位姓名的ASCII碼6C-0(EDI的值)。註冊碼第1位為l(ASCII碼為6C)
            第2位註冊碼要等於第2位姓名的ASCII碼69-1。註冊碼第2位為h
            第3位註冊碼要等於第3位姓名的ASCII碼75-2。註冊碼第3位為s。依次類推。
            NAME:liuliu                              SERIAL:lhsiep
到這裡演算法分析完畢。註冊碼也出來了。程式計算的流程也弄明白了。用你熟悉的程式語言來模仿一下程式作個序號產生器。
VB的序號產生器。
先介紹一下里面用到的一般書上沒有的函式。我用的是VB6。0企業版。
LEN() 返回字串的長度。
ASC()返回字元的ASCII碼,VB返回的是10進位制的。
MID()返回引數指定的字元。用法:MID(目標字串,開始的位數,取字元的個數)
STRING()把數字轉換為字元。如:A=STRING(76)此時A=“L”。
啟動VB6,新建一個工程。在FORM上加兩個LABLE控制元件。然後加兩個TEXTBOX控制元件。一個COMMANDBUTTON控制元件。
TEXT1。TEXT用來獲取NAME,TEXT2。TEXT用來輸出SERIAL。
在COMMAND1控制元件的CLICK事件裡如下程式碼:
Private Sub Command1_Click()
Dim a, b, c, d, e                '變數宣告。VB不用特別宣告變數的型別。多簡單。:)
text2.text="姓名不要小於5位"     
a = Text1.Text                  'a=輸入的姓名
b = Len(a)                      'b=姓名的長度
c = 1                          '設一個計數器,類似於程式中的EDI。
If b < 5 Then GoTo a:          '判斷姓名長度。小於5就什麼也不做。
Do                              ’迴圈語句,用來計算註冊碼。
d = Mid(a, c, 1)               
d = Asc(d)
d = d + 1 - c
d = String(1, d)
e = e & d
c = c + 1
Loop While c <= b
Text2.Text = e                  '輸出註冊碼。         
a:
End Sub 
然後用P-CODE編譯。才12KB。
VC的序號產生器
先用APPWIZARD做一個預設的DIALOG BASED。然後刪掉上面的東西。加入兩個EDITBOX,一個BUTTON。
EDITBOX1用來獲得NAME,EDITBOX2用來輸出SERIAL。
用CLASSWIZARD加入EDITBOX1的MEMBER m_name.EDITBOX2的MEMBER m_key.
用CLASSWIZARD在BUTTON1的BN_CLICKED事件加個函式OnButton1()
加入如下程式碼:
void CLLDlg::OnButton1()
{
    // TODO: Add your control notification handler code here
    UpdateData(TRUE);
    m_key        = "";
    char * pName= m_name.GetBuffer(0);

    if(m_name.GetLength() < 5)MessageBox("name必須大於5個字母", "error", MB_OK);
    else{
        for(int n=0;n<=m_name.GetLength();n++)
        {
            m_key += *(pName+n)-n;
        }
        UpdateData(FALSE);
    };
    m_name.ReleaseBuffer();
    
}
用RELEASE編譯。
下面是彙編的。我實在是沒能力加上步驟。。。請參考iczelion的win32asm教程。
; ml /c /coff /Cp LL.asm
; link /SUBSYSTEM:WINDOWS /LIBPATH:d:\masm32\lib LL
.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include d:\masm32\include\windows.inc
include d:\masm32\include\user32.inc
include d:\masm32\include\kernel32.inc
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\kernel32.lib

.data
ClassName db "SimpleWinClass",0
AppName  db "LL asm",0
MenuName db "FirstMenu",0
ButtonClassName db "button",0
ButtonText db "get key",0
EditClassName db "edit",0
TestString db "Wow! I'm in an edit box now",0
name5        db "name必須大於5個字母",0    ;LL add
msgError    db "error",0            ;LL add

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
keyBuffer db 100 dup(?)        ;LL add
buffer db 512 dup(?)                    ; buffer to store the text retrieved from the edit box

.const
ButtonID equ 1                                ; The control ID of the button control
EditID equ 2                                    ; The control ID of the edit control
IDM_HELLO equ 1
IDM_CLEAR equ 2
IDM_GETTEXT equ 3
IDM_EXIT equ 4

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    mov CommandLine,eax
    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov  wc.cbSize,SIZEOF WNDCLASSEX
    mov  wc.style, CS_HREDRAW or CS_VREDRAW
    mov  wc.lpfnWndProc, OFFSET WndProc
    mov  wc.cbClsExtra,NULL
    mov  wc.cbWndExtra,NULL
    push  hInst
    pop  wc.hInstance
    mov  wc.hbrBackground,COLOR_BTNFACE+1
    mov  wc.lpszMenuName,OFFSET MenuName
    mov  wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov  wc.hIcon,eax
    mov  wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov  wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName, \
                        ADDR AppName, WS_OVERLAPPEDWINDOW,\
                        CW_USEDEFAULT, CW_USEDEFAULT,\
                        300,200,NULL,NULL, hInst,NULL
    mov  hwnd,eax
    invoke ShowWindow, hwnd,SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
    .WHILE TRUE
        invoke GetMessage, ADDR msg,NULL,0,0
        .BREAK .IF (!eax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .ENDW
    mov    eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .ELSEIF uMsg==WM_CREATE
        invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
                        ES_AUTOHSCROLL,\
                        50,35,200,25,hWnd,8,hInstance,NULL
        mov  hwndEdit,eax
        invoke SetFocus, hwndEdit
        invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
                        75,70,140,25,hWnd,ButtonID,hInstance,NULL
        mov  hwndButton,eax
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF lParam==0
            .IF ax==IDM_HELLO
                invoke SetWindowText,hwndEdit,ADDR TestString
            .ELSEIF ax==IDM_CLEAR
                invoke SetWindowText,hwndEdit,NULL
;*******************************************************************************
            .ELSEIF  ax==IDM_GETTEXT
                invoke GetWindowText,hwndEdit,ADDR buffer,512    ;獲得name串
        mov    ebx,0
        .WHILE byte ptr [buffer+ebx]!=0
            mov    al,[buffer+ebx]
            sub    al,bl
            mov    [keyBuffer+ebx],al            ;變換後放入key串
            inc    ebx;
        .ENDW
        .IF ebx<5
            invoke MessageBox,NULL,offset name5, offset msgError,MB_OK
        .ELSE
            invoke MessageBox,NULL,offset keyBuffer,ADDR AppName,MB_OK      ;顯示key串
        .ENDIF
;**********************************************************************************
        .ELSE
                invoke DestroyWindow,hWnd
            .ENDIF
        .ELSE
            .IF ax==ButtonID
                shr eax,16
                .IF ax==BN_CLICKED
                    invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
                .ENDIF
            .ENDIF
        .ENDIF
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp
end start
到這裡這篇文章就差不多了。有些遺憾的是沒有DELPHI的原始碼。因為沒見到懂DELPHI的人。小樓,AJJ看到這個後能不能把DELPHI的序號產生器也加上呀。我知道的懂DELPHI的只有你們兩個。:)
                                                                              LL[CCG] & halfbit[CCG]

相關文章