SoftIce45_for_win9x的安裝序列碼獲取及序列碼生成機編寫(無實際意義,純粹好玩) (9千字)

看雪資料發表於2001-05-23

標題:SoftIce45_for_win9x的安裝序列碼獲取及序列碼生成機編寫
作者:leafred
主頁:http://leafred.126.com/
工具:isDcc v1.22,TRW2000

如有錯誤歡迎來信指正(leafspring@21cn.com)

以前搞破解,都用TRW2000,今天為了搞一個程式,結果TRW2000總是出錯,無奈想起SoftIce,高高興興的下載完SoftIce,準備安裝,沒想到是要序列碼的,誰叫我們會Crack呢,自己來動手找吧。哈哈,來破解Crack工具,有點滑稽吧。

先用isDcc來把setup.ins給反編譯出來,當然了,setup.ins是在SoftIce安裝時在系統臨時目錄下找到的了。包括後面要提到的動態庫。
首先是想能直接從反編譯的檔案總給找到,來個“The serial number you entered is not valid for this product”搜尋,鐺的一聲,彈出一個提示Search string not found!,心一沉,看來要費點勁了。
慢慢看吧。
嗯,這個宣告prototype UTILITY.DigitCheck(string);可疑,從字面上看數字檢查,很想序列碼檢查哎,先看看誰呼叫它吧。
找到一下這段程式碼,發現是function143呼叫,再找function143誰呼叫,發現果真是此處進行序列碼檢查。

首先看看呼叫function143的地方:
abel187: //Ref: 00667F 
006699:0152:        RegDBGetKeyValueEx(lString0, "Onomatopoeia", lNumber1, lString1, lNumber3);
====》取得序列碼,先從登錄檔獲取初始值,讓我們進行修改,原來沒有當然輸入新值了。

。。。。。。

label188: //Ref: 0066D0 
====》先進行資料初步校驗
0066FF:00B4:        NMINST32.ValidCookie(2, 0, lString1);
006711:0021:        lNumber5 = LAST_RESULT;
006719:0128:        lNumber5 = lNumber5 = 1;
00672B:0022:        if (lNumber5 = 0) then
                        goto label190;
                    endif;
=====》初步校驗透過,進行正式檢查                   
006739:00B5:        function143(lString3);

。。。。。。


現在再來看函式
  // ------------- FUNCTION function143 --------------
    function function143(pString0)
====》省略掉變數宣告
。。。。。

    begin
0067BE:002F:        StrLength(pString0); ==》獲取長度
0067C3:0021:        lNumber1 = LAST_RESULT;
0067CB:0128:        lNumber1 = lNumber1 != 14;
=====》長度不等於14 ?
0067DD:0022:        if (lNumber1 = 0) then
=======》 No,等於14,OK下一步檢查
                        goto label192;
                    endif;
                    ====》Yes,不等於14,返回0,這裡可以知道輸入的字元共12位,因為還含兩個“-”
0067EB:012F:        return(0);

label192: //Ref: 0067DD 
=====》取第一個框裡的字元
0067F8:0030:        StrSub(lString1, pString0, 0, 4);
=====》取第二個框裡的字元
00680A:0030:        StrSub(lString2, pString0, 5, 6);
=====》取第三個框裡的字元
00681C:0030:        StrSub(lString3, pString0, 12, 2);
00682E:0124:        lString6 = lString1 + lString2;
006839:0124:        lString0 = lString6 + lString3;
====》以上程式碼合併輸入的內容,去掉“-”
006844:0031:        StrFind(lString0, "-");
=====》還含有“-”嗎?
00684D:0128:        lNumber1 = LAST_RESULT >= 0;
00685F:0022:        if (lNumber1 = 0) then
====》No,不含了,OK繼續檢查
                        goto label193;
                    endif;
                    ====》還含“-”,返回0,由此看出我們輸入的字元不可含有“-”
00686D:012F:        return(0);

====》現在開始裝載UTILITY.dll了
label193: //Ref: 00685F 
00687A:0125:        lString5 = SUPPORTDIR ^ "UTILITY.dll";
006890:00B2:        UseDLL(lString5);
006895:0021:        lNumber1 = LAST_RESULT;
00689D:0128:        lNumber1 = lNumber1 = 0;
0068AF:0022:        if (lNumber1 = 0) then
                        goto label194;
                    endif;
======》呼叫UTILITY.dll的DigitCheck來檢查
0068BD:00B4:        UTILITY.DigitCheck(lString0);
0068C5:0021:        lNumber0 = LAST_RESULT;
0068CD:00B3:        UnUseDLL(lString5);

label194: //Ref: 0068AF 
0068D6:0128:        lNumber1 = lNumber0 = 1;
0068E8:0022:        if (lNumber1 = 0) then
                        goto label195;
                    endif;
0068F6:012F:        return(1);
0068FF:002C:        goto label196;

OK,至此我們已經知道它如何進行序列號檢查的,首先進行ValidCookie,透過則檢查長度,長度也透過進行最後的DigitCheck。
我們現在可以把上面用來檢查的兩個動態庫搞過來反彙編,慢慢讀程式,我現在就不這樣做了,我直接用TRW2000了,不要installshiled防TRW2000哦。

老一套了,用hmemcpy中斷,幾個F12來到此處:
017F:01541C44  LEA      EAX,[ESP+0C]
017F:01541C48  PUSH    EAX
017F:01541C49  PUSH    DWORD 01555820
017F:01541C4E  CALL    0154AAA0
在這裡我們來個D EAX看看,發現是第一個框裡的前三位數字,其實往上看看我們就可以看到前三個數字被移到ESP+0C處的程式碼。它是先移到ESP+10處,然後把ESP減4,POP一個值了。不就是用ESP+0C來引用嗎。
再D 01555820,發現是許多數字組合,再跟進去,發現0154AAA0是用來判斷EAX的內容是不是在01555820中的某個數字組合中。
下面還有幾處,只要有一處找到,就可以了。
因此可以知道前三個數字必須在這些數字組合中,具體的是:
230 400 401 410 411 420 421 430 431 480 481 510 930 931 950 951 ==》第一處
231 401 411 421 431 481 511 931 951 ===》第二處,一下還有幾處全部沒有,也就是說它現在只使用兩處,下面的幾處可能是保留給將來版本使用。

好了,現在再隨便挑一個,重新輸入再進入,(當然也可以直接改了)
來到此處:
017F:01541CA1  CALL    0154A5F0
關鍵所在,F8進入。
017F:0154A64E  PUSH    DWORD 01556C20
017F:0154A653  CALL    `KERNEL32!LoadLibraryA`
017F:0154A659  MOV      ESI,EAX
017F:0154A65B  TEST    ESI,ESI
017F:0154A65D  JNZ      0154A693
====》裝載UTILITY.dll
。。。。。

017F:0154A693  PUSH    DWORD 01554588
017F:0154A698  PUSH    ESI
017F:0154A699  CALL    `KERNEL32!GetProcAddress`==》獲取DigitCheck入口
017F:0154A69F  TEST    EAX,EAX
017F:0154A6A1  JZ      0154A6B1
017F:0154A6A3  LEA      ECX,[ESP+0C]
017F:0154A6A7  PUSH    ECX
017F:0154A6A8  CALL    EAX ======》此處進入DigitCheck了!!!!!
017F:0154A6AA  ADD      ESP,BYTE +04

進入017F:0154A6A8  CALL    EAX
。。。。。。

017F:01BC1136  CALL    01BC11D0
=====》此處功能是查表求得8個數字(包含對非數字的特殊處理)
017F:01BC113B  CALL    01BC1280
=====》利用上面的8個數字,再查表得8個數字。
。。。。。。

=====》01BC91B0處存放的是上面求得的8個數字
017F:01BC114A  MOV      AL,[ECX+01BC91B4]===》後四位
017F:01BC1150  MOV      DL,[ECX+01BC91B0]===》前四位
017F:01BC1156  XOR      AL,DL ===》先XOR ECX+4與ECX處數字(ECX從0到3)
017F:01BC1158  MOV      DL,[01BC91B7] ===》最後一位
017F:01BC115E  OR      AL,DL ====》 再OR最後一位
017F:01BC1160  OR      AL,30===》再OR 0x30
017F:01BC1162  CMP      AL,39 ===》判斷是否為數字
017F:01BC1164  MOV      [ECX+01BC91B8],AL
017F:01BC116A  JNG      01BC1174
017F:01BC116C  ADD      AL,07 ===》 加7轉為字母(A-Z)
017F:01BC116E  MOV      [ECX+01BC91B8],AL
017F:01BC1174  MOV      AL,[ECX+01BC91B8]
017F:01BC117A  MOV      DL,[ECX+01BC9188]
017F:01BC1180  CMP      AL,DL ====》與輸入的後四位比較
017F:01BC1182  JZ      01BC118A
017F:01BC1184  OR      AL,20 ===》不分大小寫
017F:01BC1186  CMP      AL,DL
017F:01BC1188  JNZ      01BC119C
017F:01BC118A  INC      ECX
017F:01BC118B  CMP      ECX,BYTE +04
017F:01BC118E  JL      01BC114A
017F:01BC1190  MOV      [01BC91AC],ECX
017F:01BC1196  MOV      EAX,01
017F:01BC119B  RET   
至此,我們完全清楚它幹什麼了,我們可以在017F:01BC1180 中斷。
每次修改DL讓它與AL相等,並幾下AL值四次AL的值就是正確的後四位。
也就是說它根據我們輸入的東西,判一下前三位,然後進行計算,算出後四位,再與輸入的後四位比較,正確,則透過。

因而,也就有了序列碼生成機(不知可有更好的名字,因為它不能叫做序號產生器了)的概念。
程式碼如下:(僅僅要你輸入前八位數值,不帶“-”)

#include "stdafx.h"
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
    unsigned int tab[8][10] = {
        {15,1,11,3,8,4,13,7,12,0},
        {10,12,1,8,2, 0 ,9, 15, 5, 11},
        {9 ,5, 12, 2, 7, 6, 15, 4 , 14, 10},
        {3, 4, 12, 11,1, 0, 13 ,8, 0, 14},
        {13 ,1, 6,11 ,8 ,10 ,14 ,4,3, 12},
        {7,11,6,10,5,9,4,8,0,3},
        {0,12,3,15,10,8,2,12,4,6},
        {9, 5, 13, 1,3,11,12 ,4, 2 ,8}
} ; //索引表
    char  *fthree[] ={
        "230" ,"231","400","401","410","411" ,"420", "421", "430", "431",
        "480", "481","510","511","930","931", "950","951"
    }; //前三個字元範圍
    unsigned char fthreelen = 18;
    char regcode[4],getcode[80];
    int i,j;
    unsigned int itmp;
    unsigned int code[8] ={0,0,0,0,0,0,0,0} ;

    printf("SoftIce4.5 for Win9x serial number Generater\n");
    printf("Written by Leafred\n");
    printf("Http://leafred.126.com/\n");
    printf("\nPlease Input the initial 8 letters:\n");
    do {
    gets(getcode);
    if(strlen(getcode) != 8)
        printf("Please Input the initial 8 letters:\n");
    else
        break;

    } while(1) ;
    for(i=0 ;i < fthreelen ; i++)
        if(! strncmp(getcode,fthree[i],3)) break;
    if(! (i < fthreelen)){
        printf("\nFirst three letters must in:\n");
        for(i=0;i< fthreelen;i++)
            printf("%s ",fthree[i]);
        printf("\n");
        return 0 ;
    }
    strupr(getcode);
    //第一個CALL
    for(i=0;i<8;i++){
        itmp = getcode[i] ;
        if(itmp >='0' && itmp <= '9')
            itmp = 132;
        else if(itmp >= 'A' && itmp <= 'F')
            itmp = 129;
        else if(itmp >= 'G' && itmp <= 'Z')
            itmp = 1;
        else if(itmp >= 'a' && itmp <= 'f')
            itmp = 130;
        else if(itmp >= 'g' && itmp <= 'z')
            itmp = 2;
        else
            itmp = 16;
        if(!(itmp & 4))break;
        code[i] = getcode[i] & 0xf;
    }
    //對前8各輸入有字母處理
    if(i < 8)
    {
        i--;
        j = 7;
        do{
            if(i>=0){
                code[j]=code[i];
                i--;
            }
            else
                code[j] = 0;
            j--;
            if(j < 0)
                break;

        }while (1) ;
    }
    //查表取值
    for(i=0;i<8;i++)
        code[i] = tab[i][code[i]];
        
    //最後一步
    for(i=0;i<4;i++){
        regcode[i] = code[i] ^ code[i+4];
        regcode[i] |= code[7];
        regcode[i] |= 0x30 ;
        if(regcode[i] > 0x39)regcode[i] += 7;
    }
    printf("Your serial number is:\n");
    printf("%c%c%c%c-%s%c%c-%c%c\n",getcode[0],getcode[1],getcode[2],getcode[3],getcode+4,regcode[0],regcode[1],regcode[2],regcode[3]);
    return 0;
}

相關文章