明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

怎么在Windows應(yīng)用程序中完成電子注冊(cè)技巧

[摘要]目前,國(guó)內(nèi)軟件銷售過程中采用了一種新的方式:開發(fā)者根據(jù)計(jì)算機(jī)中不同的硬件配置標(biāo)志直接在應(yīng)用程序中設(shè)置密鑰,限制程序的使用次數(shù)或者限制某些先進(jìn)功能的使用,然后將受限制的應(yīng)用程序無償提供給用戶。用戶在試...
目前,國(guó)內(nèi)軟件銷售過程中采用了一種新的方式:開發(fā)者根據(jù)計(jì)算機(jī)中不同的硬件配置標(biāo)志直接在應(yīng)用程序中設(shè)置密鑰,限制程序的使用次數(shù)或者限制某些先進(jìn)功能的使用,然后將受限制的應(yīng)用程序無償提供給用戶。用戶在試用一段時(shí)間之后如果覺得很滿意,就可以將安裝程序提取的硬件配置解密密鑰或已經(jīng)采集機(jī)器配置情況的應(yīng)用程序提供給開發(fā)者,并花少量費(fèi)用購買自己機(jī)器中的電子注冊(cè)密鑰,從而能夠充分利用應(yīng)用程序的所有功能。  

  在應(yīng)用程序中利用電子注冊(cè)來限制應(yīng)用程序的部分功能,這樣既可以讓用戶先試用然后再?zèng)Q定是否購買應(yīng)用程序,又保護(hù)了開發(fā)者的合法勞動(dòng)成果,減少了用戶與開發(fā)者之間的不必要的中間環(huán)節(jié)。開發(fā)者直接得到用戶購買軟件的費(fèi)用,真正地體現(xiàn)了開發(fā)者所創(chuàng)造的價(jià)值;用戶在試用軟件之后再?zèng)Q定是否購買,從而使得用戶能夠得到稱心如意、物有所值的軟件。因此,不通過中間環(huán)節(jié)這種銷售方式降低了軟件的成本,使開發(fā)者和用戶雙方都受益。同時(shí),這種方式還可以使得開發(fā)者能夠直接獲得用戶的反饋信息,促使開發(fā)者開發(fā)出功能更加完善的應(yīng)用程序。  

  然而,要想在應(yīng)用程序中實(shí)現(xiàn)電子注冊(cè)功能決不是件容易的事情,尤其是在Windows  平臺(tái)推出以后,要想實(shí)現(xiàn)一個(gè)跨平臺(tái)的應(yīng)用程序電子注冊(cè)功能,則要求開發(fā)者應(yīng)具有豐富的編程技巧和實(shí)際開發(fā)經(jīng)驗(yàn)以及廣闊的開發(fā)視野。筆者通過實(shí)踐探索,終于成功地實(shí)現(xiàn)了跨越DOS、Windows  3.X和Windows  95平臺(tái)的應(yīng)用程序電子注冊(cè)功能。下面將闡述其實(shí)現(xiàn)原理及技巧。  

  一、注冊(cè)密鑰點(diǎn)的選擇與生成  

  實(shí)現(xiàn)應(yīng)用程序的電子注冊(cè)功能,最關(guān)鍵的問題是采集硬件配置中的密鑰點(diǎn)。在DOS  系統(tǒng)下,可以通過硬盤端口1F6H和1F7H直接讀取硬盤的序列號(hào)等作為密鑰算法的數(shù)據(jù),因?yàn)槊繅K硬盤的型號(hào)、版本號(hào)和序列號(hào)均不同,只要用戶提供上述內(nèi)容,利用這種方法生成的注冊(cè)密鑰在每臺(tái)計(jì)算機(jī)中均不同,從而實(shí)現(xiàn)電子注冊(cè)的功能。著名的字表處理軟件CCED  5.18中采用的就是類似的方法。雖然這種方法在絕大數(shù)場(chǎng)合下很有效,甚至可以在Windows  3.X系統(tǒng)和Windows  95系統(tǒng)的兼容模式下通過,但在最高性能配置的Windows  95保護(hù)模式下卻行不通,原因是Windows  95保護(hù)模式下不允許通過端口方式讀取硬盤類型參數(shù),所以利用這種方法無法實(shí)現(xiàn)跨平臺(tái)的通用電子注冊(cè)功能。  

  本人仔細(xì)分析計(jì)算機(jī)中ROM區(qū)的F000H-FFFFH內(nèi)容后  ,發(fā)現(xiàn)該區(qū)域中記錄著很多與硬件配置有關(guān)的信息(如CMOS配置信息、主板名稱、型號(hào)和序列號(hào)、主機(jī)標(biāo)志字節(jié)和生產(chǎn)日期等)?梢圆杉渲幸惶幓驇滋幾鳛樽(cè)密鑰算法的原始數(shù)據(jù)(如機(jī)器ROM區(qū)中的F000H:FFF5H-F000H:FFFFH中依次存放主機(jī)出廠日期和主機(jī)標(biāo)志字節(jié)的內(nèi)容),這些硬件特有的信息對(duì)于不同型號(hào)的計(jì)算機(jī)來說是不可能相同的。因此,完全可以將其作為注冊(cè)密鑰算法的原始數(shù)據(jù),而且這些內(nèi)容在DOS、Windows  3.X和Windows  95下均相同。需要注意的是,如果在實(shí)際應(yīng)用中真的將該采集點(diǎn)作為算法的原始數(shù)據(jù),則不應(yīng)該包括F000:FFF0H開始的前五個(gè)字節(jié)的內(nèi)容,原因是該地址已被用作機(jī)器熱啟動(dòng)時(shí)的入口地址,在DOS、Windows  3.X和Windows  95系統(tǒng)中對(duì)熱啟動(dòng)復(fù)合鍵Ctrl+Alt+Del的處理程序均不同,因此該處的內(nèi)容在三者之中也都不相同,讀者應(yīng)記住這一點(diǎn)。  

  利用上述方法取得注冊(cè)密鑰算法的原始數(shù)據(jù)后,開發(fā)者就可以確定自己的加密算法,這可以通過編程語言中豐富的位操作功能來實(shí)現(xiàn)。然后將注冊(cè)加密算法增加到應(yīng)用程序中需要限制的部分,并可根據(jù)應(yīng)用程序的實(shí)際需要和限制的功能任意設(shè)置多處,使盜版者很難解密,從而有效地保護(hù)開發(fā)者的成果。利用這一方法,即使機(jī)器中有多個(gè)應(yīng)用程序使用相同的硬件配置信息采集點(diǎn),也不可能發(fā)生任意加密沖突問題;即便是使用了相同的算法原始數(shù)據(jù),由于算法不同,注冊(cè)密鑰也不會(huì)完全相同;即使解密者知道加密算法的原始數(shù)據(jù),由于無法知道加密算法,再加上加密算法貫穿于整個(gè)應(yīng)用程序,所以很難解密。因此,上述方法可以有效地實(shí)現(xiàn)跨越DOS、Windows  3.X和Windows  95平臺(tái)的電子注冊(cè)功能。此外,由于ROM  區(qū)關(guān)鍵點(diǎn)的內(nèi)容不可能發(fā)生變化,所以即使將來推出新型的操作系統(tǒng)平臺(tái),這種方法仍然會(huì)很有效。  

  二、利用解密密鑰建立聯(lián)系  

  應(yīng)用程序的加密部分完成之后,就需要建立相應(yīng)的解密密鑰。所謂解密密鑰,就是將加密算法的原始數(shù)據(jù)經(jīng)過加密之后,直接顯示給用戶并寫入應(yīng)用程序的相應(yīng)位置。這樣,用戶既可以通過電話或計(jì)算機(jī)網(wǎng)絡(luò)給開發(fā)者提供注冊(cè)功能的算法原始數(shù)據(jù),也可以將安裝后的應(yīng)用程序寄給開發(fā)者。加密密鑰既可以是ROM  區(qū)域內(nèi)的原始數(shù)據(jù)(最好不要原樣提供),也可以是由原始數(shù)據(jù)經(jīng)過一定換算后形成的新的數(shù)據(jù)。因此,開發(fā)者提供的應(yīng)用程序中的加密算法部分應(yīng)包括兩部分:將機(jī)器ROM  區(qū)域內(nèi)的數(shù)據(jù)經(jīng)過解密密鑰算法后形成解密密鑰,再將解密密鑰數(shù)據(jù)經(jīng)注冊(cè)算法后形成注冊(cè)密鑰。  

  應(yīng)用程序中注冊(cè)密鑰的算法、注冊(cè)密鑰的長(zhǎng)度、顯示或提供給開發(fā)者的方式可自己確定,但解密密鑰的長(zhǎng)度和算法應(yīng)與注冊(cè)密鑰完全相同。解密密鑰也沒有必要做得那么復(fù)雜,只需進(jìn)行簡(jiǎn)單處理后就可以實(shí)現(xiàn),例如本文程序中實(shí)現(xiàn)的方法是將ROM中采集的數(shù)據(jù)簡(jiǎn)單地減去0x2020。  

  三、電子注冊(cè)密鑰生成程序  

  開發(fā)者得到用戶提供的解密密鑰原始數(shù)據(jù)后,需要利用專用的密鑰生成程序?qū)⑵滢D(zhuǎn)換成注冊(cè)密鑰,并將注冊(cè)密鑰交給用戶。注冊(cè)密鑰的算法與應(yīng)用程序中判斷注冊(cè)密鑰的加密算法程序應(yīng)該完全相同。該程序一般應(yīng)具有以下三種取得注冊(cè)密鑰算法原始數(shù)據(jù)的方式,以方便進(jìn)行密鑰的處理。該程序的名稱為READKEY.EXE,其功能如下:  

  (1)當(dāng)READKEY不帶參數(shù)時(shí),則直接從當(dāng)前機(jī)器中取得注冊(cè)密鑰;  

  (2)當(dāng)READKEY帶參數(shù)時(shí),則從鍵盤輸入解密密鑰來獲取注冊(cè)密鑰;  

 。3)當(dāng)READKEY帶EXE文件名參數(shù)時(shí),則從相應(yīng)應(yīng)用程序的特定位置取得解密密鑰,并生成注冊(cè)密鑰。  

  用戶得到注冊(cè)密鑰后,重新安裝一次應(yīng)用程序或在需要輸入注冊(cè)密鑰處直接輸入密鑰,則應(yīng)用程序會(huì)自動(dòng)將這個(gè)注冊(cè)密鑰存放到文件的特定位置處,當(dāng)應(yīng)用程序被他人拷貝到其它機(jī)器中之后,由于注冊(cè)密鑰隨機(jī)器的不同而不同,所以應(yīng)用程序的功能或使用次數(shù)仍然受限,要想在其它機(jī)器中使用該應(yīng)用程序,則必須重新注冊(cè)。  

  應(yīng)用程序中解密密鑰和注冊(cè)密鑰的位置,可先用特殊字符來標(biāo)識(shí),然后用DEBUG  等程序直接查找其位置,再修改其它程序中讀取或?qū)懭霐?shù)據(jù)的地址值。至于解密密鑰顯示和注冊(cè)密鑰的輸入方式,可由開發(fā)者確定是用安裝程序的方法還是在應(yīng)用程序中直接處理的方法。  

  /*電子注冊(cè)功能密鑰讀取程序清單READKEY.C*/  

  #include  

  #include  

  #include  

  #include  

  #include  

  #include  

  #include  

  #include  

  #include  

  #include  

  #include  

  void  readser(void);  

  void  readser1(void);  

  unsigned  char  Buff[18];  

  unsigned  int  keyrom[9];  

  unsigned  int  sum,sumi,sumj;  

  unsigned  int  far  *pt=  

    (unsigned  int  far  *)0xf000fff6L;  

  unsigned  int  i=0,j=0,m;  

  unsigned  char  p;  

  unsigned  int  nn,nn1,nn2;  

  unsigned  char  rbuff[100],cc,cc1,cc2;  

  int  fp;  

  void  main(int  argc,char  *argv[])  

  {  if((argc>3) ((argc==2)&&(argv[1][1]!=':'))){  

    printf("USAGE:READKEY  程序路徑及名稱.\n");  

    scanf("%s",rbuff);  //手工輸入加密密鑰  

    printf("sss:%s,%u\n",rbuff,strlen(rbuff));  

    j=strlen(rbuff);  

    if(j!=20)  exit(1);  

    for(i=0;i<20;i++){  

    if((rbuff[i]>='a')&&(rbuff[i]<='f'))  rbuff[i]&=0xdf;  

    if((rbuff[i]>='A')&&(rbuff[i]<='F'))  rbuff[i]-=0x37;  

    else  if((rbuff[i]>='0')&&(rbuff[i]<='9'))  rbuff[i]-=0x30;  

    else  exit(1);  

    }  

    printf("num:");  

    for(i=0;i<5;i++){  

    cc1=rbuff[i*4]&0xf;  

    cc2=rbuff[i*4+1]&0xf;  

    cc=(cc1<<4) cc2;  

    nn1=(unsigned  int)cc;  

    cc1=rbuff[i*4+2]&0xf;  

    cc2=rbuff[i*4+3]&0xf;  

    cc=(cc1<<4) cc2;  

    nn2=(unsigned  int)cc;  

    nn=(nn1<<8) nn2;  

    keyrom[i]=nn;  

    printf("%04x",keyrom[i]);  

    }  

    printf("\n");  

    sum=0x2020;  

    for(sumj=0;sumj<4;sumj++){  //形成16位密鑰  

    for(sumi=0;sumi<5;sumi++)  

    sum-=keyrom[sumi];  //形成解密密鑰  

    sum^=0x0404<      sprintf(Buff+4*sumj,"%04x",sum);  

    }  

    printf(Buff);  

    exit(1);  

    }  

    if(argc>1){  

    strlwr(argv[1]);  

    if(strstr(argv[1],".EXE")==NULL){  

    printf("USAGE:READKEY  路徑及文件名.\n");  

    exit(1);  

    }  

    if((fp=open(argv[1],O_RDWR O_BINARY))==-1){  

    printf("File  %s  open  error!",argv[1]);  

    exit(1);  

    }  

    lseek(fp,0xf040L,SEEK_SET);//ROM  10個(gè)數(shù)據(jù)地址+200H  

    read(fp,keyrom,0xaL);  //讀取數(shù)據(jù)  

    readser1();  //讀文件中的注冊(cè)密鑰  

    }  else  readser();  //讀機(jī)器中的注冊(cè)密鑰  

  }  

  void  readser(void)  

  {  

    sum=0x2020;  

    for(sumj=0;sumj<4;sumj++){//形成16位密鑰  

    for(sumi=0;sumi<5;sumi++)  

    sum-=(*(pt+sumi)-0x2020);//形成解密密鑰  

    sum^=0x0404<      sprintf(Buff+4*sumj,"%04x",sum);  

    }  

    printf(Buff);  

  }  

  void  readser1(void)  

  {  

    sum=0x2020;  

    for(sumj=0;sumj<4;sumj++){//形成16位密鑰  

    for(sumi=0;sumi<5;sumi++)  

    sum-=keyrom[sumi];  //形成解密密鑰  

    sum^=0x0404<      sprintf(Buff+4*sumj,"%04x",sum);  

    }  

    printf(Buff);  

  }  

    

  四、應(yīng)用程序中密鑰的讀取及限制  

  當(dāng)應(yīng)用程序進(jìn)行電子注冊(cè)之后,安裝程序會(huì)將注冊(cè)密鑰寫入到應(yīng)用程序中。在應(yīng)用程序中,判斷是否進(jìn)行注冊(cè)的方法就是重新生成注冊(cè)密鑰并進(jìn)行判斷處理。注冊(cè)密鑰的讀取函數(shù)如下:  

  void  ImeCmpkey(void)  

  {//Windows下注冊(cè)密鑰的讀取函數(shù)  

    static  unsigned  int  sum,sumi,sumj;  

    static  BOOL  flag;  

    static  unsigned  int  far  *pt;  

    static  UINT  Sel1,Sel2;  

    static  WORD  Seg,Off,Start;  

    static  DWORD  Bas,Lim;  

    flag=TRUE;  

    sum=0x2020;  

    __asm  mov  Sel1,ds;  //將DS作為模板  

    Sel2=AllocSelector(Sel1);  //分配一個(gè)新選擇符  

    if(Sel2==NULL){  

    flag=FALSE;  

    pt=(unsigned  int  far*)0xf000fff0L;  

    }  else  {  

    Seg=0xffff;  //絕對(duì)地址段址  

    Off=0x10;  //絕對(duì)地址偏移  

    Start=0x0;  

    Bas=((unsigned  long)Seg)<<4 Start;  

    Lim=(unsigned  long)Off-1;  

    SetSelectorBase(Sel2,Bas);  

    SetSelectorLimit(Sel2,Lim);  

    pt=(unsigned  int  far*)((((unsigned  long)Sel2)<<16) Start);  

    }  

    for(sumj=0;sumj<4;sumj++){  //形成16位密鑰  

    for(sumi=0;sumi<5;sumi++)  

    sum-=(*(pt+3+sumi)-0x2020);//形成解密密鑰  

    sum^=0x0404<      wsprintf((LPSTR)sImeG.ImeBuff+4*sumj,(LPSTR)"%04x",sum);  

    }  

    if(flag==TRUE)  FreeSelector(Sel2);  

    sImeG.ImeBuff[16]==0;  

    for(sumi=0;sumi<16;sumi++)  

    sImeG.ImeBuff[sumi]+=(unsigned  char)sumi;  

    if(lstrcmpi(sImeG.ImeBuff,sImeG.ImeKey)==0)  

    sImeG.UseFlag=FALSE;//已經(jīng)注冊(cè)  

    else  sImeG.UseFlag=TRUE;  

  }  

  利用注冊(cè)密鑰讀取函數(shù),就可在應(yīng)用程序的多處關(guān)鍵代碼部分增加程序功能的限制。例如,本人使用的限制代碼部分如下:  

  ImeCmpKey1();  

  if(lstrcmpi(sImeG.ImeBuff,sImeG.ImeKey)==0){  

  for(i=0;i<18;i++)  sImeG.ImeBuff[i]=0;  

    sImeG.UseFlag=FALSE;//已經(jīng)注冊(cè)  

    sImeG.UseNum=0;  

  }  else{  

    sImeG.UseFlag=TRUE;//未注冊(cè)  

  }  

  由于直接讀取內(nèi)存單元中的數(shù)據(jù)來生成注冊(cè)密鑰和注冊(cè)限制功能的代碼部分,其執(zhí)行速度特別快,對(duì)應(yīng)用程序幾乎沒有任何影響。因此,可以在應(yīng)用程序中增加若干個(gè)注冊(cè)密鑰生成函數(shù)和限制功能代碼,使解密者知難而退,從而達(dá)到保護(hù)開發(fā)者的勞動(dòng)成果的目的。這種增加注冊(cè)密鑰生成及判斷限制功能的方法,其缺點(diǎn)是使應(yīng)用程序的長(zhǎng)度增加了,但這對(duì)于目前高檔計(jì)算機(jī)的大容量硬盤來說只不過是九牛一毛而已,所以該方法非常可行。