Quickness 3.1 註冊演算法分析 + 序號產生器原始碼(tc2) (15千字)

看雪資料發表於2003-04-13

Quickness 3.1 註冊演算法分析 + 序號產生器原始碼(tc2)

破解目標:Quickness 3.1
官方主頁:http://www.qwertysoft.com/
軟體簡介:Quickness 是一個方便使用者輸入的小工具。如果有些文字內容是我們經常要用到的,就可以利用 Quickness 將其儲存起來,併為其指定熱鍵,這樣,當我們需要用的時候,直接按熱鍵就可以調出內容了。特別是在我們聊天的時候,有了 Quickness 的相助,可是會大大提高速度的喲。
下載頁面:http://www.hanzify.org/detail.asp?SOFT_ID=6938 (漢化版)

使用工具:PEiD 0.8、W32Dasm、Ollydbg 1.09b 漢化版、Windows 自帶的計算器、32bit Calculator 1.6 by cybult、UltraEdit,另外還要儲存大腦清醒^^

作者:炎之川[BCG]
時間:2003.4.13
主頁:http://skipli.yeah.net/

宣告:此文僅用於學習及交流,若要轉載請保持文章完整。


首先說明,我下載的是漢化版,官方主頁上不去,天空軟體站好像也沒有,所以英文原版沒有辦法找到,下面的分析都是基於漢化版的,當然從分析的角度說,無論漢化版還是英文版都是一樣的。

其實頭腦清醒的話,軟體的演算法並不是很難,只是在一個迴圈中要同時考慮三個暫存器中的數字的變化,以及其他一些變化的量,稍不留神就會亂掉。最好在分析的時候,隨時紀錄一下值的變化。


用 PEiD 0.8 徵測可知軟體無殼,使用 W32Dasm 分析,可以找到註冊成功、失敗等提示資訊,稍作分析後用 OD 裝入程式,在 4029A7 處下斷點,然後 Ctrl+F2 重新載入程式,F9 執行,輸入註冊名及假註冊碼並點選“註冊”:
Name: lovefire[BCG]
Serial: 123-456-789


004029A7  > 8B7C24 14      MOV EDI,DWORD PTR SS:[ESP+14]            ;  Case 1 of switch 00402965  /在這裡下斷點
004029AB  . 68 1A040000    PUSH 41A                                ; /ControlID = 41A (1050.)
004029B0  . 57            PUSH EDI                                ; |hWnd
004029B1  . FF15 5C654100  CALL DWORD PTR DS:[<&USER32.GetDlgItem>] ; \GetDlgItem
004029B7  . 8BD8          MOV EBX,EAX
004029B9  . 53            PUSH EBX                                ; /hWnd
004029BA  . FF15 AC644100  CALL DWORD PTR DS:[<&USER32.GetWindowTex>; \GetWindowTextLengthA
004029C0  . 8BE8          MOV EBP,EAX
004029C2  . 8D45 01        LEA EAX,DWORD PTR SS:[EBP+1]
004029C5  . 50            PUSH EAX
004029C6  . E8 35500000    CALL qns31chs.00407A00
004029CB  . 83C4 04        ADD ESP,4
004029CE  . 8BF0          MOV ESI,EAX
004029D0  . 8D45 01        LEA EAX,DWORD PTR SS:[EBP+1]
004029D3  . 50            PUSH EAX                                ; /Count
004029D4  . 56            PUSH ESI                                ; |Buffer
004029D5  . 53            PUSH EBX                                ; |hWnd
004029D6  . FF15 B4644100  CALL DWORD PTR DS:[<&USER32.GetWindowTex>; \GetWindowTextA
004029DC  . 56            PUSH ESI
004029DD  . 68 BC0C4100    PUSH qns31chs.00410CBC                  ;  ASCII "user_name"
004029E2  . C6042E 00      MOV BYTE PTR DS:[ESI+EBP],0
004029E6  . E8 C5E9FFFF    CALL qns31chs.004013B0
004029EB  . 83C4 08        ADD ESP,8
004029EE  . 56            PUSH ESI
004029EF  . E8 FC4F0000    CALL qns31chs.004079F0
004029F4  . 83C4 04        ADD ESP,4
004029F7  . B9 743F4100    MOV ECX,qns31chs.00413F74
004029FC  . 57            PUSH EDI
004029FD  . E8 6E000000    CALL qns31chs.00402A70
00402A02  . E8 C9FDFFFF    CALL qns31chs.004027D0  //關鍵call!F7 跟進
00402A07  . 85C0          TEST EAX,EAX  //比較eax是否為0,為0則註冊失敗
00402A09  . 6A 00          PUSH 0                                  ; /Style = MB_OK|MB_APPLMODAL
00402A0B  . 68 A00B4100    PUSH qns31chs.00410BA0                  ; |Title = "Quickness"
00402A10  . 74 28          JE SHORT qns31chs.00402A3A              ; |  //這裡不能跳!!
00402A12  . 68 E80C4100    PUSH qns31chs.00410CE8                  ; |Text = "正確。感謝。"
00402A17  . 57            PUSH EDI                                ; |hOwner
00402A18  . FF15 84644100  CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
00402A1E  . 6A 01          PUSH 1                                  ; /Result = 1
00402A20  . 57            PUSH EDI                                ; |hWnd
00402A21  . C705 50084100 >MOV DWORD PTR DS:[410850],0              ; |
00402A2B  . FF15 58654100  CALL DWORD PTR DS:[<&USER32.EndDialog>]  ; \EndDialog
00402A31  . 33C0          XOR EAX,EAX
00402A33  . 5F            POP EDI
00402A34  . 5E            POP ESI
00402A35  . 5D            POP EBP
00402A36  . 5B            POP EBX
00402A37  . C2 1000        RETN 10
00402A3A  > 68 C80C4100    PUSH qns31chs.00410CC8                  ; |Text = "註冊失敗。繼續試用。"
00402A3F  . 57            PUSH EDI                                ; |hOwner
00402A40  . FF15 84644100  CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
00402A46  . 33C0          XOR EAX,EAX
00402A48  . 5F            POP EDI
00402A49  . 5E            POP ESI
00402A4A  . 5D            POP EBP
00402A4B  . 5B            POP EBX
00402A4C  . C2 1000        RETN 10
00402A4F  > 8B5424 14      MOV EDX,DWORD PTR SS:[ESP+14]
00402A53  . 68 F80C4100    PUSH qns31chs.00410CF8                  ;  ASCII "a_register.htm"
00402A58  . 52            PUSH EDX
00402A59  . E8 92420000    CALL qns31chs.00406CF0
00402A5E  . 83C4 08        ADD ESP,8
00402A61  > 5F            POP EDI                                  ;  Default case of switch 00402965
00402A62  . 5E            POP ESI
00402A63  . 5D            POP EBP
00402A64  . 33C0          XOR EAX,EAX
00402A66  . 5B            POP EBX
00402A67  . C2 1000        RETN 10

----------------------------------------------------------
跟進 402A02 的關鍵call:

004027D0  /$ 81EC 94010000  SUB ESP,194
004027D6  |. 8D4424 04      LEA EAX,DWORD PTR SS:[ESP+4]
004027DA  |. 53            PUSH EBX
004027DB  |. 55            PUSH EBP
004027DC  |. 56            PUSH ESI
004027DD  |. 57            PUSH EDI
004027DE  |. 68 C8000000    PUSH 0C8
004027E3  |. 50            PUSH EAX
004027E4  |. 68 BC0C4100    PUSH qns31chs.00410CBC                  ;  ASCII "user_name"
004027E9  |. E8 32EBFFFF    CALL qns31chs.00401320
004027EE  |. 83C4 0C        ADD ESP,0C
004027F1  |. 85C0          TEST EAX,EAX
004027F3  |. 75 0B          JNZ SHORT qns31chs.00402800
004027F5  |. 5F            POP EDI
004027F6  |. 5E            POP ESI
004027F7  |. 5D            POP EBP
004027F8  |. 5B            POP EBX
004027F9  |. 81C4 94010000  ADD ESP,194
004027FF  |. C3            RETN
00402800  |> 8D8C24 DC00000>LEA ECX,DWORD PTR SS:[ESP+DC]
00402807  |. 68 C8000000    PUSH 0C8
0040280C  |. 51            PUSH ECX
0040280D  |. 68 B40C4100    PUSH qns31chs.00410CB4                  ;  ASCII "reg_key"
00402812  |. E8 09EBFFFF    CALL qns31chs.00401320
00402817  |. 83C4 0C        ADD ESP,0C
0040281A  |. 85C0          TEST EAX,EAX
0040281C  |. 75 0B          JNZ SHORT qns31chs.00402829
0040281E  |. 5F            POP EDI
0040281F  |. 5E            POP ESI
00402820  |. 5D            POP EBP
00402821  |. 5B            POP EBX
00402822  |. 81C4 94010000  ADD ESP,194
00402828  |. C3            RETN
00402829  |> 8D7C24 14      LEA EDI,DWORD PTR SS:[ESP+14]
0040282D  |. 83C9 FF        OR ECX,FFFFFFFF
00402830  |. 33C0          XOR EAX,EAX
00402832  |. F2:AE          REPNE SCAS BYTE PTR ES:[EDI]
00402834  |. F7D1          NOT ECX
00402836  |. 49            DEC ECX  //得到註冊名長度
00402837  |. 8BC1          MOV EAX,ECX  //長度放入eax
00402839  |. 83F8 01        CMP EAX,1  //比較是否大於1
0040283C  |. 894424 10      MOV DWORD PTR SS:[ESP+10],EAX
00402840  |. 73 0D          JNB SHORT qns31chs.0040284F  //大於1則繼續
00402842  |. 33C0          XOR EAX,EAX
00402844  |. 5F            POP EDI
00402845  |. 5E            POP ESI
00402846  |. 5D            POP EBP
00402847  |. 5B            POP EBX
00402848  |. 81C4 94010000  ADD ESP,194
0040284E  |. C3            RETN
0040284F  |> 33C9          XOR ECX,ECX  //ecx 清零,做計數器
00402851  |. BE 01000000    MOV ESI,1  //esi 賦值 1
00402856  |. 85C0          TEST EAX,EAX
00402858  |. BD 03000000    MOV EBP,3  //ebp 賦值 3
0040285D  |. BF 05000000    MOV EDI,5  //edi 賦值 5
00402862  |. 76 4F          JBE SHORT qns31chs.004028B3


下面開始就是計算註冊碼的迴圈了,開始的時候我沒有理清思路,在這裡轉來轉去,頭都大了(汗…典型的菜鳥-_-b),後來經過仔細分析,發現這個迴圈的任務實際上是在計算三個值,並儲存到不同的三個暫存器中,所以其他值都是無關緊要的中間變數,分析的時候,只要注意三個值的變化情況即可。

為了便於理解,我把這個迴圈分成三個部分,每一部分都寫出了這一部分重要的中間變數和重要的暫存器的具體變化和演算法。

下面均使用C語言的運算子表述,記住 ESI、EBP、EDI 這三個暫存器的值是我們需要掌握的,EAX 和 EDX 是關鍵的中間變數,name[i] 指使用者名稱的 ASCII 值。

另外,從C語言運算子的優先順序角度講,其實並不需要用那麼多的括號,但是我為了自己不看亂掉,所以每一運算均使用括號來分隔,不要數錯了^_^
(最後差點數錯的好像是我自己…狂汗-_-bbb)

00402864  |> 0FBE5C0C 14    /MOVSX EBX,BYTE PTR SS:[ESP+ECX+14]  //逐位取註冊名的ASCII值放入ebx
00402869  |. 8D0476        |LEA EAX,DWORD PTR DS:[ESI+ESI*2]  //eax=esi*2+esi=esi*3
0040286C  |. 33D2          |XOR EDX,EDX  //edx清零
0040286E  |. C1E0 04        |SHL EAX,4  //eax 左移4,等於4次*2運算
00402871  |. 2BC6          |SUB EAX,ESI  //eax=eax-esi
00402873  |. BE E8030000    |MOV ESI,3E8  //給 esi 賦值為 3E8
00402878  |. 03C3          |ADD EAX,EBX  //eax=eax+ebx,ebx中是註冊名的ASCII值
0040287A  |. F7F6          |DIV ESI  //eax/esi=eax/3E8,餘數放入edx

eax=(((esi*3)<<4-esi)+name[i])/0x3E8
edx=(((esi*3)<<4-esi)+name[i])%0x3E8 = 值1

0040287C  |. 8BC5          |MOV EAX,EBP  //eax=ebp
0040287E  |. C1E0 04        |SHL EAX,4  //eax再次左移4
00402881  |. 03C5          |ADD EAX,EBP  //eax=eax+ebp
00402883  |. BD E8030000    |MOV EBP,3E8  //ebp=3E8,為下面的計算再次賦值
00402888  |. 8BF2          |MOV ESI,EDX  //esi=edx,edx是上面 eax mod 3E8 得到的值
0040288A  |. 8D1443        |LEA EDX,DWORD PTR DS:[EBX+EAX*2]  //edx=ebx+eax*2,ebx是註冊名ASCII
0040288D  |. 03C2          |ADD EAX,EDX  //eax=eax+edx
0040288F  |. 33D2          |XOR EDX,EDX  //edx 清零
00402891  |. F7F5          |DIV EBP  //eax=eax/ebp=eax/3E8,餘數放入edx

eax=((((ebp<<4)+ebp)*2)+name[i])+((ebp<<4)+ebp)
edx=(((ebp<<4)+ebp)+(name[i]+(((ebp<<4)+ebp)*2)))%0x3E8 = 值2
esi=值1 (!)

00402893  |. 8D04FF        |LEA EAX,DWORD PTR DS:[EDI+EDI*8]  //eax=edi+edi*8=edi*9
00402896  |. C1E0 03        |SHL EAX,3  //eax 左移3
00402899  |. 2BC7          |SUB EAX,EDI  //eax=eax-edi
0040289B  |. BF E8030000    |MOV EDI,3E8  //edi=3E8
004028A0  |. 03C3          |ADD EAX,EBX  //eax=eax+ebx
004028A2  |. 8BEA          |MOV EBP,EDX  //ebp=edx,edx是上面 eax mod 3E8 得到的值
004028A4  |. 33D2          |XOR EDX,EDX  //edx 清零
004028A6  |. F7F7          |DIV EDI  //eax=eax/edi

eax=(edi*8<<3-edi+name[i])/0x3E8
ebp=值2 (!)
edx=(edi*8<<3-edi+name[i])%3E8 = 值3

004028A8  |. 8B4424 10      |MOV EAX,DWORD PTR SS:[ESP+10]  //註冊名長度放入eax
004028AC  |. 41            |INC ECX  //計數器+1
004028AD  |. 3BC8          |CMP ECX,EAX  //比較計數器與註冊名長度
004028AF  |. 8BFA          |MOV EDI,EDX  //edi=edx
004028B1  |.^72 B1          \JB SHORT qns31chs.00402864  //沒有取完就跳回去繼續迴圈

edi=值3 (!)

004028B3  |> 57            PUSH EDI
004028B4  |. 55            PUSH EBP
004028B5  |. 56            PUSH ESI
004028B6  |. 8D4424 20      LEA EAX,DWORD PTR SS:[ESP+20]
004028BA  |. 68 A40C4100    PUSH qns31chs.00410CA4                  ;  ASCII "%03d-%03d-%03d"  //註冊碼格式,十進位制輸出,寬度為3
004028BF  |. 50            PUSH EAX
004028C0  |. E8 BB500000    CALL qns31chs.00407980  //將 esi、ebp、edi 分別作為註冊碼的第一、二、三部分,合併起來成為完整的註冊碼。
004028C5  |. 83C4 14        ADD ESP,14
004028C8  |. 8DB424 DC00000>LEA ESI,DWORD PTR SS:[ESP+DC]  //假碼放入esi
004028CF  |. 8D4424 14      LEA EAX,DWORD PTR SS:[ESP+14]  //真碼放入eax
004028D3  |> 8A10          /MOV DL,BYTE PTR DS:[EAX//下面開始比較註冊碼
004028D5  |. 8A1E          |MOV BL,BYTE PTR DS:[ESI]
004028D7  |. 8ACA          |MOV CL,DL
004028D9  |. 3AD3          |CMP DL,BL
004028DB  |. 75 30          |JNZ SHORT qns31chs.0040290D
004028DD  |. 84C9          |TEST CL,CL
004028DF  |. 74 16          |JE SHORT qns31chs.004028F7
004028E1  |. 8A50 01        |MOV DL,BYTE PTR DS:[EAX+1]
004028E4  |. 8A5E 01        |MOV BL,BYTE PTR DS:[ESI+1]
004028E7  |. 8ACA          |MOV CL,DL
004028E9  |. 3AD3          |CMP DL,BL
004028EB  |. 75 20          |JNZ SHORT qns31chs.0040290D
004028ED  |. 83C0 02        |ADD EAX,2
004028F0  |. 83C6 02        |ADD ESI,2
004028F3  |. 84C9          |TEST CL,CL
004028F5  |.^75 DC          \JNZ SHORT qns31chs.004028D3
004028F7  |> 33C0          XOR EAX,EAX
004028F9  |. 33C9          XOR ECX,ECX
004028FB  |. 85C0          TEST EAX,EAX
004028FD  |. 0F94C1        SETE CL
00402900  |. 8BC1          MOV EAX,ECX
00402902  |. 5F            POP EDI
00402903  |. 5E            POP ESI
00402904  |. 5D            POP EBP
00402905  |. 5B            POP EBX
00402906  |. 81C4 94010000  ADD ESP,194
0040290C  |. C3            RETN


演算法總結如下:
註冊碼分三個部分,分別用 esi、ebp、edi 代表。每個部分為三位十進位制數字,中間用“-”分隔。
設初始值:esi=1、ebp=3、edi=5,name[i]為取得的註冊使用者名稱的 ASCII 值:

第一部分演算法:
esi=((((esi*3)<<4)-esi)+name[i])%0x3E8

第二部分演算法:
ebp=(((((ebp<<4)+ebp)*2)+name[i])+((ebp<<4)+ebp))%0x3E8

第三部分演算法:
edi=((((edi*9)<<3)-edi)+name[i])%0x3E8


至此 Quickness 3.1 註冊演算法分析完成,一組可用的註冊碼:Name: lovefire[BCG]  Serial: 409-351-613

註冊資訊儲存:
軟體安裝目錄下的 qns31.ini 檔案中,註冊資訊儲存如下:
[x]
user_name=lovefire[BCG]
reg_key=409-351-613

----------------------------------------------------------
序號產生器原始碼(TC 2.0)

順便再寫一下注冊機,TC 2.0 編譯透過。

/* KeyGen by 炎之川[BCG],2003.4.12 */

#include <stdio.h>
#include <string.h>
main()
{
        char name[255];
        int name_len,i;
        unsigned long int esi=1;
        unsigned long int ebp=3;
        unsigned long int edi=5;
        clrscr();
        printf("\n    _/_/_/      _/_/_/    _/_/_/\n  _/    _/  _/        _/\n  _/_/_/    _/        _/  _/_/\n _/    _/  _/        _/    _/\n_/_/_/      _/_/_/    _/_/_/\n\n -= Quickness v3.1 KeyGen by lovefire[BCG] =-\n\n\nPlease enter your name: ");
        gets(name);
        name_len=strlen(name);
        if (name_len>0)
        {
                for (i=0;i<name_len;i++)
                {
                        esi=((((esi*3)<<4)-esi)+name[i])%0x3E8;
                        ebp=(((((ebp<<4)+ebp)*2)+name[i])+((ebp<<4)+ebp))%0x3E8;
                        edi=((((edi*9)<<3)-edi)+name[i])%0x3E8;
                }
                printf("\nok, try this serial: %03ld-%03ld-%03ld\n",esi,ebp,edi);
                printf("\n\nNOTE: serial only for test!");
                printf("\nIf you like it, buy it to support the soft's author!");
        }
        else
        {
                printf("\nI think you should tell me your name first ;)\n");
        }
        printf("\n\nhave fun^^\nwelcome to http://skipli.yeah.net/");
        getch();
}
----------------------------------------------------------

炎之川
屬於中國破解組織BCG(Beginner's Cracking Group)

    _/_/_/      _/_/_/    _/_/_/
  _/    _/  _/        _/
  _/_/_/    _/        _/  _/_/
_/    _/  _/        _/    _/
_/_/_/      _/_/_/    _/_/_/

相關文章