EditPlus v2.12en破解全過程

看雪資料發表於2004-12-22

第一篇破文,還望大家多多指教!!!!

【破解作者】icytear
【作者郵箱】icytear@126.com
【使用工具】SoftIce4.3.1,IDA4.5,PEiD0.92
【破解平臺】WindowsXP Pro SP1.
【破解日期】2004.12.7 - 2004.12.22
【軟體名稱】EditPlus v2.12en
【軟體大小】913,408 BYTE
【加殼方式】無殼
【下載地址】
【軟體簡介】

    EditPlus是Internet時代的32位文字編輯程式,HTML編輯及程式設計師的Windows平臺編輯器。它可以充分的替換記事本,它也提供網頁作家及程式設計師許多強悍的功能。對於HTML、CSS、PHP、ASP、Perl、C/C++、Java、JavaScript及VBScript的語法突顯。當然,它也可以在自定義語法檔案後擴充其他的程式語言。嵌合網頁瀏覽器作HTML頁的預覽,及FTP命令做本地檔案上傳到FTP伺服器。其他功能還包含HTML工具欄、使用者工具、列號、標尺、URL突顯。自動完成、剪貼文字、行列選擇、強大的搜尋與替換、多重撤消/重做、拼寫檢測、自定義鍵盤快捷鍵、以及更多。

【破解宣告】本文僅供技術交流、學習之用。
【破解內容】

1. 用PEiD開啟editplus發現無殼。

2. 開啟程式出現註冊對話方塊,點選輸入註冊碼,Username輸入"icytear",Regcode輸入"280060443",下斷點
    addr editplus
    bpx GetWindowTextA
   單擊註冊按鈕,程式被中斷,按F12退出GetWindowTextA函式,到如下位置


001B:004BFC91    PUSH    DWORD PTR [ESP+08]
001B:004BFC95    PUSH    DWORD PTR [ESP+08]
001B:004BFC99    PUSH    DWORD PTR [ECX+1C]
001B:004BFC9C    CALL    [USER32!GetWindowTextA] 
001B:004BFCA2    JMP    004BFCB6        ;---->按F12後到這裡,goto #exit
...
001B:004BFCB6    RET    0008            ;#exit

按2次F10執行程式碼,程式返回到#R01

001B:0047C850    MOV    EAX,[ESP+0C]
001B:0047C854    MOV    ECX,[ESP+04]
001B:0047C858    PUSH    ESI
001B:0047C859    MOV    ESI,[ESP+0C]
001B:0047C85D    PUSH    EAX
001B:0047C85E    PUSH    ESI
001B:0047C85F    CALL    004BFC8A
001B:0047C864    MOV    AL,[ESI]        ;#R01---->程式返回到這裡
001B:0047C866    CMP    AL,20            ;---->從前向後比較字元是否為空格
001B:0047C868    JZ    0047C86E        ;---->為空格則跳轉,繼續比較下一個字元
001B:0047C86A    CMP    AL,09            ;---->比較這個字元是否為製表符
001B:0047C86C    JNZ    0047C871        ;---->如果不為空格也不是製表符則跳轉到#J01↓
001B:0047C86E    INC    ESI            ;---->如果字元為空格或製表符則刪除
001B:0047C86F    JMP    0047C864        ;---->繼續比較下一個字元(跳轉到#R01↑)
===>:0047C871    PUSH    ESI            ;↑#J01---->使用者名稱入棧
001B:0047C872    CALL    [KERNEL32!lstrlen]    ;---->不用說了吧,得到使用者名稱長度
001B:0047C878    MOV    ECX,[ESP+14]
001B:0047C87C    TEST    EAX,EAX            ;---->檢查是否輸入了使用者名稱
001B:0047C87E    MOV    [ECX],EAX        ;---->把結果儲存起來
001B:0047C880    JLE    0047C899
001B:0047C882    MOV    EAX,[ECX]
001B:0047C884    MOV    DL,[ESI+EAX-01]        ;---->取出最後一個字元
001B:0047C888    CMP    DL,20            ;---->比較是否為空格
001B:0047C88B    JZ    0047C892
001B:0047C88D    CMP    DL,09
001B:0047C890    JNZ    0047C899
001B:0047C892    DEC    EAX            ;---->繼續向前比較
001B:0047C893    TEST    EAX,EAX
001B:0047C895    MOV    [ECX],EAX
001B:0047C897    JG    0047C882
001B:0047C899    MOV    EDX,[ECX]
001B:0047C89B    MOV    BYTE PTR [ESI+EDX],00    ;---->刪除末尾的空格和製表符
001B:0047C89F    MOV    EAX,[ECX]
001B:0047C8A1    TEST    EAX,EAX            ;
001B:0047C8A3    JNZ    0047C8AD
001B:0047C8A5    PUSH    40
001B:0047C8A7    CALL    [USER32!MessageBeep]
001B:0047C8AD    MOV    EAX,ESI
001B:0047C8AF    POP    ESI
001B:0047C8B0    RET

上面的程式碼大概的意思就是:檢查輸入的使用者名稱開始和末尾是否為有效字元(非空格和製表符)。
然後返回到#R02:

...

001B:0047C8E1    CALL    0047C850        ;---->取輸入的使用者名稱
001B:0047C8E6    MOV    EBX,EAX            ;#R02---->D EAX;EAX指向的就是輸入的使用者名稱icytear
001B:0047C8E8    MOV    EAX,[ESP+20]        ;---->[esp+20]存的是使用者名稱的長度
001B:0047C8EC    ADD    ESP,10            ;---->平衡堆疊
001B:0047C8EF    TEST    EAX,EAX            ;---->檢查輸入的用使用者名稱是否有效
001B:0047C8F1    JZ    0047C9B1
001B:0047C8F7    LEA    EAX,[ESP+0C]        ;---->SS:[ESP+0C] = 00000034
001B:0047C8FB    LEA    ECX,[ESP+14]        ;---->SS:[ESP+14] = 0
001B:0047C8FF    PUSH    EAX
001B:0047C900    PUSH    31
001B:0047C902    LEA    EDX,[ESI+5C]
001B:0047C905    PUSH    ECX
001B:0047C906    PUSH    EDX
001B:0047C907    CALL    0047C850        ;---->用上面同樣的方法得到輸入的註冊碼
001B:0047C90C    MOV    ECX,[ESP+1C]        ;---->[ESP+1C]輸入的註冊碼長度
001B:0047C910    ADD    ESP,10            ;---->平衡堆疊
001B:0047C913    TEST    ECX,ECX            ;---->檢查有效註冊碼長度
001B:0047C915    MOV    EDI,EAX
001B:0047C917    JZ    0047C9B1
001B:0047C91D    XOR    EAX,EAX
001B:0047C91F    TEST    ECX,ECX
001B:0047C921    JLE    0047C93B
001B:0047C923    XOR    ECX,ECX
001B:0047C925    MOV    CL,[EDI+EAX]        ;---->從輸入的註冊碼取一個字元
001B:0047C928    INC    EAX            ;---->移動指標指向下一個字元
001B:0047C929    MOV    DL,[ECX+00522C90]    ;---->查表,把小寫轉換成大寫
001B:0047C92F    MOV    [EDI+EAX-01],DL
001B:0047C933    MOV    ECX,[ESP+0C]
001B:0047C937    CMP    EAX,ECX
001B:0047C939    JL    0047C923
001B:0047C93B    PUSH    EDI            ;---->把輸入的註冊碼入棧
001B:0047C93C    PUSH    EBX            ;---->輸入的使用者名稱入棧
001B:0047C93D    CALL    0047CA60        ;#C01---->關鍵呼叫
001B:0047C942    ADD    ESP,08
001B:0047C945    TEST    EAX,EAX
001B:0047C947    JNZ    0047C961        ;---->註冊成功的關鍵
001B:0047C949    PUSH    FF
001B:0047C94B    PUSH    10
001B:0047C94D    PUSH    00005F81
001B:0047C952    CALL    004C7E94        ;---->這裡就彈出錯誤對話方塊了
001B:0047C957    POP    EDI
001B:0047C958    POP    ESI
001B:0047C959    POP    EBX
001B:0047C95A    ADD    ESP,00000230
001B:0047C960    RET
001B:0047C961    PUSH    EDI
001B:0047C962    PUSH    EBX
001B:0047C963    CALL    0047C3B0
...

進入#C01 (CALL    0047CA60)繼續跟蹤

001B:0047CA60    SUB    ESP,0C
001B:0047CA63    PUSH    EBX            ;---->使用者名稱入棧
001B:0047CA64    MOV    EBX,[KERNEL32!lstrlen]
001B:0047CA6A    PUSH    ESI
001B:0047CA6B    PUSH    EDI
001B:0047CA6C    MOV    EDI,[ESP+1C]        ;---->edi指向了使用者名稱
001B:0047CA70    PUSH    EDI
001B:0047CA71    CALL    EBX            ;---->call [lstrlen],得到使用者名稱長度
001B:0047CA73    MOV    ESI,EAX
001B:0047CA75    TEST    ESI,ESI            ;---->
001B:0047CA77    JNZ    0047CA80        ;---->跳到#C01.C1
001B:0047CA79    POP    EDI
001B:0047CA7A    POP    ESI
001B:0047CA7B    POP    EBX
001B:0047CA7C    ADD    ESP,0C
001B:0047CA7F    RET

001B:0047CA80    CALL    0047C9C0        ;#C01.C1---->跟進去
001B:0047CA85    PUSH    ESI
001B:0047CA86    PUSH    EDI
001B:0047CA87    PUSH    00
001B:0047CA89    CALL    0047CA10        ;#C01.C2---->
001B:0047CA8E    ADD    ESP,0C
001B:0047CA91    AND    EAX,0000FFFF
001B:0047CA96    PUSH    EAX
001B:0047CA97    LEA    EAX,[ESP+10]
001B:0047CA9B    PUSH    0051824C
001B:0047CAA0    PUSH    EAX
001B:0047CAA1    CALL    004AEABC        ;#C01.C3---->sprintf
001B:0047CAA6    MOV    ESI,[ESP+2C]
001B:0047CAAA    MOV    AL,[ESP+18]
...

進入#C01.C1 (CALL 0047C9C0).

001B:0047C9C0    PUSH    ESI
001B:0047C9C1    PUSH    EDI            
001B:0047C9C2    MOV    ECX,00000080        ;---->計數 0x80
001B:0047C9C7    XOR    EAX,EAX            ;---->EAX清零
001B:0047C9C9    MOV    EDI,00523410
001B:0047C9CE    XOR    ESI,ESI
001B:0047C9D0    REPZ    STOSD            ;---->從00523410~00523610清零
001B:0047C9D2    MOV    EDX,00523410
001B:0047C9D7    MOV    EAX,0000C0C1        ;#loop1--->第一層迴圈
001B:0047C9DC    MOV    ECX,00000001
001B:0047C9E1    TEST    ESI,ECX            ;#loop2--->第二層迴圈
001B:0047C9E3    JZ    0047C9E8
001B:0047C9E5    XOR    [EDX],AX
001B:0047C9E8    ADD    EAX,EAX
001B:0047C9EA    SHL    ECX,1
001B:0047C9EC    XOR    EAX,00004003
001B:0047C9F1    CMP    ECX,00000100
001B:0047C9F7    JL    0047C9E1        ;---->跳轉到#loop2
001B:0047C9F9    ADD    EDX,02
001B:0047C9FC    INC    ESI
001B:0047C9FD    CMP    EDX,00523610
001B:0047CA03    JL    0047C9D7        ;---->跳轉到#loop1
001B:0047CA05    POP    EDI
001B:0047CA06    POP    ESI
001B:0047CA07    RET

以上程式碼用C語言表示如下:

WORD list[0x80*2];
void sub_0047C9C0()
{
    int i,j=0;
    DWORD ieax,iecx,iesi=0;
    WORD temp;
    for(i=0;i<0x80*2;i++)
        list[i] = 0;
    
    do{
        ieax = 0x0C0C1; //ieax = 49345
        iecx = 1;
        do{    
            if ((iesi&iecx)!=0)
            {
                temp = (WORD)(ieax&0x0FFFF);
                list[j] = list[j]^temp;
            }
            ieax*=2;
            iecx*=2;
            ieax = ieax^0x04003;
            
        }while(iecx<0x100);
        j++;
        iesi++;
    }while(j<0x80*2);
}

從#C01.C1 CALL 出來

...
001B:0047CA85    PUSH    ESI            ;---->使用者名稱長度
001B:0047CA86    PUSH    EDI            ;---->使用者名稱指標入棧
001B:0047CA87    PUSH    00
001B:0047CA89    CALL    0047CA10        ;#C01.C2--->跟進去..
001B:0047CA8E    ADD    ESP,0C
...

進入#C01.C2 (CALL 0047CA10).

001B:0047CA10    MOV    ECX,[ESP+08]        ;---->ECX指向使用者名稱'icytear'
001B:0047CA14    MOV    EAX,[ESP+0C]        ;---->EAX存使用者名稱長度,
001B:0047CA18    PUSH    ESI
001B:0047CA19    LEA    ESI,[EAX+ECX]        ;---->ESI指向了使用者名稱的末尾'\0'
001B:0047CA1C    CMP    ECX,ESI
001B:0047CA1E    JAE    0047CA4A        ;---->如果大於等於則跳轉#exit.
001B:0047CA20    MOV    EAX,[ESP+08]
001B:0047CA24    PUSH    EBX
001B:0047CA25    MOV    EDX,EAX            ;#loop3
001B:0047CA27    XOR    EBX,EBX
001B:0047CA29    MOV    BL,[ECX]        ;---->開始逐個字元取使用者名稱
001B:0047CA2B    AND    EDX,000000FF
001B:0047CA31    XOR    EDX,EBX
001B:0047CA33    XOR    EBX,EBX
001B:0047CA35    MOV    BL,AH
001B:0047CA37    MOV    AX,[EDX*2+00523410]    ;---->(00523410~00523610) #C01.C1 CALL 生成的東東
001B:0047CA3F    XOR    AX,BX
001B:0047CA42    INC    ECX
001B:0047CA43    CMP    ECX,ESI
001B:0047CA45    JB    0047CA25        ;---->如果小於跳轉倒#loop3↑
001B:0047CA47    POP    EBX
001B:0047CA48    POP    ESI
001B:0047CA49    RET
001B:0047CA4A    MOV    AX,[ESP+08]        ;#exit.
001B:0047CA4F    POP    ESI
001B:0047CA50    RET

##C01.C2 (CALL    0047CA10) C語言程式碼如下:

char username[]="icytear";

int sub_0047CA10(int n,char *pname,int unamelen)
{
    DWORD ieax,iebx,iedx,temp;
    char *iecx;
    iecx = pname;
    ieax = unamelen;
    if(*iecx == '\0')
        return 0;
    
    ieax = n;
    do{
        //MOV EDX,EAX
        iedx = ieax;
        //XOR EBX,EBX
        iebx = 0;
        //MOV BL,[ECX]
        temp = *iecx;
        iebx = iebx & 0xFFFFFF00;
        iebx = iebx ^ temp;
        //AND EDX,000000FF
        iedx = iedx & 0x000000FF;
        //XOR EDX,EBX
        iedx = iedx ^ iebx;
        //XOR EBX,EBX
        iebx = 0;
        //MOV BL,AH
        temp = ieax;
        temp = temp>>8;
        temp = temp & 0x000000FF;
        iebx = iebx & 0xFFFFFF00;
        iebx = iebx ^ temp;
        //MOV AX,[EDX*2+00523410]
        temp = list[iedx]
        ieax = ieax & 0xFFFF0000;
        ieax = ieax ^ temp;
        //XOR AX,BX
        temp = iebx;
        temp = temp & 0x0000FFFF;
        ieax = ieax ^ temp;

        iecx++;
            
    }while(*iecx != '\0');

    return ieax;
}

從#C01.C2 CALL 出來到 #C01CALL

...
001B:0047CA8E    ADD    ESP,0C            ;---->#C01.C2 CALL 出來到這裡
001B:0047CA91    AND    EAX,0000FFFF        ;---->AX是用使用者名稱算出的結果
001B:0047CA96    PUSH    EAX
001B:0047CA97    LEA    EAX,[ESP+10]
001B:0047CA9B    PUSH    0051824C        ;---->;"%02X"
001B:0047CAA0    PUSH    EAX            ;
001B:0047CAA1    CALL    004AEABC        ;---->sprintf,把使用者名稱算出的16進位制結果以字元形式儲存
001B:0047CAA6    MOV    ESI,[ESP+2C]
001B:0047CAAA    MOV    AL,[ESP+18]        ;---->[ESP+18] = "5CF",由"icytear"算出的值
001B:0047CAAE    ADD    ESP,0C
001B:0047CAB1    MOV    CL,[ESI+02]        ;---->[ESI+02] 註冊碼的第三個字元
001B:0047CAB4    LEA    EDI,[ESI+02]
001B:0047CAB7    CMP    CL,AL            ;---->比較,在這裡比較註冊碼第三個字元是否為'5'
001B:0047CAB9    JZ    0047CAC4
001B:0047CABB    POP    EDI
001B:0047CABC    POP    ESI
001B:0047CABD    XOR    EAX,EAX
001B:0047CABF    POP    EBX
001B:0047CAC0    ADD    ESP,0C
001B:0047CAC3    RET
001B:0047CAC4    MOV    DL,[ESI+03]        ;---->註冊碼第四個字元
001B:0047CAC7    MOV    AL,[ESP+0D]        ;---->"5CF"的第二個字元
001B:0047CACB    CMP    DL,AL            ;---->比較註冊碼的第四個字元是否為'C'
001B:0047CACD    JZ    0047CAD8
001B:0047CACF    POP    EDI
001B:0047CAD0    POP    ESI
001B:0047CAD1    XOR    EAX,EAX
001B:0047CAD3    POP    EBX
001B:0047CAD4    ADD    ESP,0C
001B:0047CAD7    RET
001B:0047CAD8    PUSH    ESI            ;---->註冊碼
001B:0047CAD9    CALL    EBX            ;---->KERNEL!lstrlen
001B:0047CADB    SUB    EAX,02
001B:0047CADE    PUSH    EAX            ;---->EAX == 註冊碼長度 - 2;
001B:0047CADF    PUSH    EDI            ;---->第三位以後的註冊碼
001B:0047CAE0    PUSH    00
001B:0047CAE2    CALL    0047CA10        ;---->前面出現過這個函式,用註冊碼第三為以後的字元計算出一個值
001B:0047CAE7    ADD    ESP,0C
001B:0047CAEA    AND    EAX,0000FFFF
001B:0047CAEF    PUSH    EAX
001B:0047CAF0    LEA    EAX,[ESP+10]
001B:0047CAF4    PUSH    0051824C        ;---->"%02X"
001B:0047CAF9    PUSH    EAX
001B:0047CAFA    CALL    004AEABC        ;---->sprintf
001B:0047CAFF    MOV    CL,[ESI]        ;---->取註冊碼的第一個字元
001B:0047CB01    MOV    AL,[ESP+18]        ;---->由第三位以後的註冊碼計算出的值(第一個字元)
001B:0047CB05    ADD    ESP,0C
001B:0047CB08    CMP    CL,AL            ;---->比較註冊碼的第一位
001B:0047CB0A    JZ    0047CB15
001B:0047CB0C    POP    EDI
001B:0047CB0D    POP    ESI
001B:0047CB0E    XOR    EAX,EAX
001B:0047CB10    POP    EBX
001B:0047CB11    ADD    ESP,0C
001B:0047CB14    RET
001B:0047CB15    MOV    DL,[ESI+01]        ;---->取註冊碼的第二個字元
001B:0047CB18    MOV    CL,[ESP+0D]        ;---->由第三位以後的註冊碼計算出的值(第二個字元)
001B:0047CB1C    XOR    EAX,EAX
001B:0047CB1E    CMP    DL,CL            ;---->比較註冊碼的第二位
001B:0047CB20    POP    EDI
001B:0047CB21    POP    ESI
001B:0047CB22    SETZ    AL
001B:0047CB25    POP    EBX
001B:0047CB26    ADD    ESP,0C
001B:0047CB29    RET                ;---->出#C01 CALL


3.  以上程式碼,驗證了註冊碼的前四位,以上可知註冊碼的第3、4位是由使用者名稱用sub_0047CA10(int,char*,int)函式計算出的值16進位制碼的字元格式的前兩位, 在這裡為"5C"; 註冊碼的第1、2位是由註冊碼第三位以後的字元用sub_0047CA10函式計算出的16進位制碼的字元格式的前兩位,用"5C60443"計算的結果為"EF",所以在這時註冊碼應為"ef5c60443".
回到註冊對話方塊重新輸入註冊碼"ef5c60443",提示需要重啟EditPlus啟用註冊碼,看來第一步驗證透過了.

4.  重啟EditPlus,提示"Invalid registration code.",看來其它的地方還有註冊碼的驗證過程,好我們回到程式繼續跟蹤...
這次跟蹤註冊碼用"EF5C60443".

出#C01 CALL 到...

001B:0047C942    ADD    ESP,08            ;---->返回到這裡
001B:0047C945    TEST    EAX,EAX            ;---->
001B:0047C947    JNZ    0047C961        ;---->跳轉則第一步註冊成功
001B:0047C949    PUSH    FF
001B:0047C94B    PUSH    10
001B:0047C94D    PUSH    00005F81
001B:0047C952    CALL    004C7E94        ;---->出錯對話方塊,
001B:0047C957    POP    EDI
001B:0047C958    POP    ESI
001B:0047C959    POP    EBX
001B:0047C95A    ADD    ESP,00000230
001B:0047C960    RET
===>:0047C961    PUSH    EDI            ;---->註冊碼
001B:0047C962    PUSH    EBX            ;---->使用者名稱
001B:0047C963    CALL    0047C3B0        ;#C02---->關於登錄檔的動作????,跟進去看看..
001B:0047C968    ADD    ESP,08
001B:0047C96B    TEST    EAX,EAX
001B:0047C96D    JNZ    0047C986        ;--->輸入"ef5c60443"時,在這裡我們跳轉了..
001B:0047C96F    PUSH    FF
001B:0047C971    PUSH    EAX
001B:0047C972    PUSH    00004E7F
001B:0047C977    CALL    004C7E94        ;--->註冊失敗!!
001B:0047C97C    POP    EDI
001B:0047C97D    POP    ESI
001B:0047C97E    POP    EBX
001B:0047C97F    ADD    ESP,00000230
001B:0047C985    RET
===>:0047C986    MOV    ECX,[ESI+000000D8]
001B:0047C98C    PUSH    EBX            ;---->使用者名稱
001B:0047C98D    CALL    004C0367        ;---->CString::=
001B:0047C992    MOV    ECX,[ESI+000000DC]
001B:0047C998    PUSH    EDI            ;---->註冊碼"EF5C60443"
001B:0047C999    CALL    004C0367        ;---->CString::=
001B:0047C99E    MOV    EAX,[ESI+000000E4]
001B:0047C9A4    MOV    ECX,ESI
001B:0047C9A6    MOV    DWORD PTR [EAX],00000000
001B:0047C9AC    CALL    004BF482        ;---->CDialog::0nOK(void)
001B:0047C9B1    POP    EDI
001B:0047C9B2    POP    ESI
001B:0047C9B3    POP    EBX
001B:0047C9B4    ADD    ESP,00000230
001B:0047C9BA    RET
001B:0047C9BB    NOP
...


進入#C02 ...

001B:0047C3B0    SUB    ESP,000000E0
001B:0047C3B6    PUSH    EBX            ;---->使用者名稱(保護現場)
001B:0047C3B7    PUSH    EBP
001B:0047C3B8    PUSH    ESI
001B:0047C3B9    MOV    ESI,[ESP+000000F0]    ;---->讓ESI指向使用者名稱
001B:0047C3C0    PUSH    EDI            ;---->註冊碼(保護現場)
001B:0047C3C1    MOV    EDI,[KERNEL32!lstrlen]
001B:0047C3C7    PUSH    ESI            ;---->使用者名稱入棧了
001B:0047C3C8    CALL    EDI            ;---->得到使用者名稱長度
001B:0047C3CA    MOV    EBX,EAX
001B:0047C3CC    MOV    EAX,[ESP+000000F8]
001B:0047C3D3    PUSH    EAX            ;---->EAX指向註冊碼
001B:0047C3D4    CALL    EDI            ;---->註冊碼長度
001B:0047C3D6    LEA    EBP,[EBX+EAX+02]    ;---->ebp = name_len+sn_len+2;
001B:0047C3DA    MOV    [ESP+14],EAX
001B:0047C3DE    PUSH    EBP
001B:0047C3DF    CALL    004AD84D        ;---->malloc(size_t)分配記憶體
001B:0047C3E4    MOV    ECX,EBX
001B:0047C3E6    LEA    EDI,[EAX+01]
001B:0047C3E9    MOV    EDX,ECX    
001B:0047C3EB    MOV    [EAX],BL        ;---->把bl(使用者名稱長度)存到新分配的空間中的第一個位元組
001B:0047C3ED    SHR    ECX,02
001B:0047C3F0    REPZ    MOVSD            ;---->把使用者名稱存到分配的空間中
001B:0047C3F2    MOV    ECX,EDX
001B:0047C3F4    MOV    [ESP+1C],EAX
001B:0047C3F8    AND    ECX,03
001B:0047C3FB    REPZ    MOVSB            ;---->把使用者名稱存到分配的空間中
001B:0047C3FD    MOV    ECX,[ESP+18]        ;---->註冊碼長度
001B:0047C401    MOV    ESI,[ESP+000000FC]    ;---->ESI指向註冊碼
001B:0047C408    MOV    [EAX+EBX+01],CL        ;---->把cl(註冊碼長度)存到分配的空間中
001B:0047C40C    LEA    EDI,[EAX+EBX+02]
001B:0047C410    MOV    EAX,ECX
001B:0047C412    SHR    ECX,02
001B:0047C415    REPZ    MOVSD            ;---->存註冊碼
001B:0047C417    MOV    ECX,EAX
001B:0047C419    MOV    EAX,51EB851F
001B:0047C41E    IMUL    EBP            ;---->EDX:EAX=0x51eb851f * 0x12 = 5C28F5C2E
001B:0047C420    AND    ECX,03
001B:0047C423    REPZ    MOVSB            ;---->存註冊碼,此時記憶體中的資料為"\x07icytear\x09EF5C60443"
001B:0047C425    SAR    EDX,05            ;---->移位操作
001B:0047C428    MOV    ECX,EDX
001B:0047C42A    SHR    ECX,1F
001B:0047C42D    ADD    EDX,ECX
001B:0047C42F    LEA    EDX,[EBP+EDX+0C]    ;---->計算要下一個操作要分配多少空間n
001B:0047C433    PUSH    EDX
001B:0047C434    MOV    [ESP+18],EDX        ;---->把n存下來
001B:0047C438    CALL    004AD84D        ;---->malloc(size_t)分配記憶體
001B:0047C43D    MOV    EDI,[ESP+20]        ;---->EDI指向"\x07icytear\x09EF5C60443"
001B:0047C441    PUSH    EBP
001B:0047C442    LEA    EDX,[ESP+1C]        ;---->EDX指向上次分配空間大小n
001B:0047C446    MOV    ESI,EAX            ;---->讓ESI指向最近分配的記憶體空間
001B:0047C448    PUSH    EDI            ;---->EDI指向"\x07icytear\x09EF5C60443",
001B:0047C449    PUSH    EDX
001B:0047C44A    PUSH    ESI
001B:0047C44B    MOV    [ESP+38],ESI
001B:0047C44F    CALL    0049F820        ;#C1---->關鍵,計算出一段值(size:1E),要寫入登錄檔License,在此處按F9下一個斷點
001B:0047C454    ADD    ESP,18
001B:0047C457    TEST    EAX,EAX
001B:0047C459    JZ    0047C477        ;---->跳轉到#J1
001B:0047C45B    PUSH    EDI
001B:0047C45C    CALL    004AD764        ;---->call????
001B:0047C461    PUSH    ESI
001B:0047C462    CALL    004AD764        ;---->call????
001B:0047C467    ADD    ESP,08
001B:0047C46A    XOR    EAX,EAX
001B:0047C46C    POP    EDI
001B:0047C46D    POP    ESI
001B:0047C46E    POP    EBP
001B:0047C46F    POP    EBX
001B:0047C470    ADD    ESP,0E0
001B:0047C476    RET
===>:0047C477    MOV    EAX,[ESP+10]        ;#J1---->
001B:0047C47B    ADD    EAX,08
001B:0047C47E    PUSH    EAX
001B:0047C47F    MOV    [ESP+18],EAX
001B:0047C483    CALL    004AD84D        ;---->malloc(size_t)分配記憶體
001B:0047C488    MOV    ECX,[0051A58]        ;---->[0051A58]==DWORD 0x182989DB 定值
001B:0047C48E    MOV    EBX,EAX
001B:0047C490    MOV    [EBX],ECX        ;---->write memory...
001B:0047C492    MOV    EDX,[00518A58]
001B:0047C498    PUSH    EDX
001B:0047C499    CALL    004AD987        ;---->void _cdecl srand(unsigned int)
001B:0047C49E    CALL    004AD994        ;---->int rand(void)產生一個偽隨機數
001B:0047C4A3    ADD    EAX,EBP            ;---->ebp == name_len+sn_len+2
001B:0047C4A5    MOV    [EBX+04],AX        ;---->write memory... to [ebx+4] 
001B:0047C4A9    MOV    EAX,[00518A58]
001B:0047C4AE    INC    EAX
001B:0047C4AF    PUSH    EAX
001B:0047C4B0    CALL    004A987            ;---->srand
001B:0047C4B5    ADD    ESP,0C
001B:0047C4B8    CALL    004AD994        ;---->rand()  產生一個偽隨機數
001B:0047C4BD    MOV    ECX,[ESP+10]
001B:0047C4C1    LEA    EDI,[EBX+08]
001B:0047C4C4    ADD    EAX,ECX
001B:0047C4C6    MOV    [EBX+06],AX        ;---->write memory... to [ebx+6] = 0xb78188+6
001B:0047C4CA    MOV    ECX,[ESP+10]
001B:0047C4CE    MOV    EDX,ECX
001B:0047C4D0    SHR    ECX,02
001B:0047C4D3    REPZ    MOVSD
001B:0047C4D5    MOV    ECX,EDX
001B:0047C4D7    AND    ECX,03
001B:0047C4DA    REPZ    MOVSB
...

把剛才生成的16進位制碼寫登錄檔...

...

按F5執行程式,又提示重啟editplus,退出程式..在這裡程式被上面按F9下的那個斷點中斷(在#C02.#C1,001B:0047C44B),看來程式在關閉時又呼叫了一次#C02 Call,也就是又寫了一次登錄檔,好我們用D edi命令檢視edi指向的記憶體為"\x07icytear\x090F5C60443",看到區別了嗎,前面我們看到的是"\x07icytear\x09EF5C60443",看來是被程式修改了,用這個再一次計算出16進位制程式碼寫入登錄檔,重啟editplus時和第一次寫得當然就不一樣了,看來程式是在這裡做了手腳..

我們按F12退出此次呼叫(CALL 0047C3B0)

...
001B:0042E691    CALL    0047C3B0
001B:0042E696    ADD    ESP,08        ;---->到這裡
...
我們向上檢視程式碼,看到
...
001B:0042E661    TEST    EAX,EAX
001B:0042E663    JZ    0042E69A    ;---->這裡有個跳轉,如果跳就不能執行CALL 0047C3B0了,按F9在這裡下個斷點(把其它得斷點可以先禁掉),如果跳轉我們就可以註冊成功..

重新輸入註冊碼後退出editplus程式被中斷,單步執行看看
...
001B:0042E653    MOV    EAX,[ESI+B44]
001B:0042E659    MOV    DWORD PTR [ESP+10],08
001B:0042E661    TEST    EAX,EAX
001B:0042E663    JZ    0042E69A
001B:0042E665    MOV    EAX,[ESI+0B30]    ;---->D EAX,發現eax指向的還是"EF5C60443",由此判斷可能是由於下面的程式碼改變了此字串,我們保持此記憶體的視窗,繼續往下執行
001B:0042E66B    PUSH    EDI
001B:0042E66C    LEA    EDI,[ESI+0B30]
001B:0042E672    MOV    AL,[EAX]
001B:0042E674    CMP    AL,30
001B:0042E676    JNZ    0042E67C
001B:0042E678    PUSH    31
001B:0042E67A    JMP    0042E67E
001B:0042E67C    PUSH    30
001B:0042E67E    PUSH    00
001B:0042E680    MOV    ECX,EDI
001B:0042E682    CALL    004C069E    ;#C03---->執行此呼叫後,"EF5C60443"被改為"0F5C60443",看來我們的判斷是真確的.
001B:0042E687    MOV    EDI,[EDI]
001B:0042E689    MOV    EAX,[ESI+B2C]
001B:0042E68F    PUSH    EDI
001B:0042E690    PUSH    EAX
001B:0042E691    CALL    0047C3B0
...
我們再看看TEST EAX,EAX 中的EAX從那來的,向上看到MOV  EAX,[ESI+B44],用D ESI+B44檢視記憶體,顯示如下
...
0023:00B7590C 01 00 00 00 .....
0023:00B7591C .......
...
那我們下一個記憶體斷點試試,BPMD 0B7590C,再次輸入註冊碼點選註冊,OK,程式被中斷在..
...
001B:0047C9A6    MOV    DWORD PTR [EAX],0    ;---->這裡改變記憶體,賦值0
001B:0047C9AC    CALL    004BF482        ;---->中斷在此
...

MOV DWORD PTR [EAX],0;把記憶體B7590C賦值0,我們要看看在那裡把其改為1的,按F5執行程式,再次中斷

...
001B:0047C718    MOV    DWORD PTR [ECX],01    ;---->改變記憶體,賦值1
001B:0047C71E    LEA    ECX,[EDI+98]        ;---->中斷在此
...

我們向上看程式
001B:0047C707    MOV    AL,[EAX,04]        ;---->把第5位註冊碼存入AL
001B:0047C70A    MOV    CL,[ESP+10]        ;---->那[esp+10]存的是什麼呢?我們繼續向上看程式


001B:0047C670    PUSH    FF
001B:0047C672    PUSH    004E6183
001B:0047C677    MOV    EAX,FS:[00000000]
001B:0047C67D    PUSH    EAX
001B:0047C67E    MOV    FS:[0],ESP
001B:0047C685    SUB    ESP,10
001B:0047C688    PUSH    EBP
001B:0047C689    PUSH    ESI
001B:0047C68A    PUSH    EDI
001B:0047C68B    MOV    EDI,ECX
001B:0047C691    MOV    DWORD PTR [EDI],004F41E0
001B:0047C697    MOV    EAX,[EDI+D8]
001B:0047C69D    MOV    DWORD PTR [ESP+24],01
001B:0047C6A5    MOV    EBP,[EAX]        ;---->讓EBP指向使用者名稱"icytear"
001B:0047C6A7    MOV    ESI,[EBP-08]        ;---->ESI存使用者名稱長度
001B:0047C6AA    TEST    ESI,ESI
001B:0047C6AC    JLE    0047C71E        ;---->跳過賦值1的那個指令
001B:0047C6AE    XOR    EAX,EAX
001B:0047C6B0    MOV    ECX,01            ;---->ECX賦值1
001B:0047C6B5    TEST    ESI,ESI
001B:0047C6B7    JLE    0047C6C5
===>:0047C6B9    XOR    EDX,EDX            ;#LOOP
001B:0047C6BB    MOV    DL,[EBP+EAX]
001B:0047C6BE    ADD    ECX,EDX
001B:0047C6C0    INC    EAX
001B:0047C6C1    CMP    EAX,ESI
001B:0047C6C3    JL    0047C6B9        ;---->跳到#LOOP,使用者名稱每一位的值相加再加1;
001B:0047C6C5    LEA    ECX,[ECX*8+ECX+0A]
001B:0047C6C9    MOV    EAX,55555556
001B:0047C6CE    IMUL    ECX
001B:0047C6D0    MOV    EAX,EDX
001B:0047C6D2    SHR    EAX,1F
001B:0047C6D5    LEA    ECX,[EAX+EDX+24]    
001B:0047C6D9    AND    ECX,8000000F
001B:0047C6DF    JNS    0047C6E6
001B:0047C6E1    DEC    ECX
001B:0047C6E2    OR    ECX,-10
001B:0047C6E5    INC    ECX
===>:0047C6E6    PUSH    ECX
001B:0047C6E7    LEA    EDX,[ESP+14]
001B:0047C6EB    PUSH    0051700C        ;---->"%1X"
001B:0047C6F0    PUSH    EDX
001B:0047C6F1    CALL    004AEABC        ;---->sprintf
001B:0047C6F6    MOV    EAX,[EDI+DC]
001B:0047C6FC    ADD    ESP,0C
001B:0047C6FF    MOV    EAX,[EAX]        ;---->EAX指向註冊碼
001B:0047C701    CMP    DWORD PTR[EAX-8],05    ;---->[EAX-8]存著註冊碼長度,也就是說註冊碼長度應該大於5
001B:0047C605    JL    0047C712
001B:0047C607    MOV    AL,[EAX,04]        ;---->註冊碼第5位
001B:0047C60A    MOV    CL,[ESP+10]        ;---->很顯然是我們用使用者名稱算出的那個值
001B:0047C60E    CMP    AL,CL            ;---->驗證第5位註冊碼,在這裡我們計算出的是'D'
001B:0047C610    JZ    0047C71E        ;---->第二次驗證透過則註冊成功..^_^,勝利!!
001B:0047C612    MOV    ECX,[EDI+E4]
001B:0047C618    MOV    DWORD PTR[ECX],01
...

5.  用我的使用者名稱'icytear'計算出的值是'D'所以我的第5位註冊碼應為'D',前2位應用'5CD0443'由sub_0047CA10重新計算為'E4',重新輸入註冊碼'E45CD0443',哈哈,註冊成功!!

6.  好累,序號產生器大家寫吧,別忘了給我發一份!!


####################
username: icytear
Regcode: E45CD0443
####################

相關文章