現在、Win32アプリを作っています。試用版としてリリースしたいのですが、どのように試用期限のチェックをしようか悩んでいます。ぜひ、サンプルコード本体を貼り付けていただくか、サンプルコードを掲載しているサイトを教えていただけますか。ピンポイントの回答には高得点を差し上げます。宜しく御願い致します。

回答の条件
  • URL必須
  • 1人3回まで
  • 登録:2006/11/25 22:10:17
  • 終了:2006/12/02 22:15:03

回答(4件)

id:kazu1107 No.1

kazu1107回答回数199ベストアンサー獲得回数142006/11/26 10:21:53

ポイント23pt

#include <iostream>

const int key[] = {20263006,9056919,28901031,34037154,41412405};

const int WORDS=5;

const int DIGITS=5;

// キーチェック関数

inline bool KeyCheck(const char** str){

int buf[WORDS] = {0,0,0,0,0};

int i;

for(i=0;i<WORDS;i++){ // 区切りの数だけループ</p>

for(int j=0,wait=1;j<DIGITS;j++){ // 桁の数だけループ</p>

char c;

if(str[i][j] >= '0' && str[i][j]<= '9'){

c = str[i][j]-'0';

}else if(str[i][j] >= 'A' && str[i][j]<= 'Z'){

c = str[i][j]-'A'+10;

// 今回はアルファベットの大文字小文字は区別してません

}else if(str[i][j] >= 'a' && str[i][j]<= 'z'){

c = str[i][j]-'a'+10;

}else c = 0;

buf[i] += c * wait;

wait *= 36;

}

if(key[i] != buf[i])

break;

}

return i==WORDS ? true : false;

}


// キーからコードを取得

inline void OutCode(const char** str){

int buf[WORDS] = {0,0,0,0,0};

int i;

for(i=0;i<WORDS;i++){ // 区切りの数だけループ</p>

for(int j=0,wait=1;j<DIGITS;j++){ // 桁の数だけループ</p>

char c;

if(str[i][j] >= '0' && str[i][j]<= '9'){

c = str[i][j]-'0';

}else if(str[i][j] >= 'A' && str[i][j]<= 'Z'){

c = str[i][j]-'A'+10;

// 今回はアルファベットの大文字小文字は区別してません

}else if(str[i][j] >= 'a' && str[i][j]<= 'z'){

c = str[i][j]-'a'+10;

}else c = 0;

buf[i] += c * wait;

wait *= 36;

}

}

// デバッグコード(認証キーから得た認証コード値を表示する)

std::cout<< buf[0] << " " << buf[1] << " "

<< buf[2] << " " << buf[3] << " " << buf[4] << std::endl;

}




int main(){

// 1つ5桁の5つのキーコード(

const char* teststr[WORDS] = {"A1B2C","3D4E5","F6G7H","I8J9K","L0MNO"};

std::cout<< "認証..." << (KeyCheck(teststr)?"Ok":"No") << std::endl;

OutCode(teststr);

while(1);

return 0;

}


WindowsにこういうのをチェックするAPIがあるのかどうか知らないので、適当に組んでみましたけどどうでしょうか?

あまりその手のテクニックに詳しくないので、どうすれば安全な仕組みになるのかいまいちわかりません。大体これぐらいなら一般にはわからないだろって程度です。

今回は内容5桁×5ワード×36(A~Z + 0~9)の組み合わせで認証しています。

プログラム側ではキーを5つのint型として保持しているので、ワードを直書きするよりは特定しにくくなるかと。

さらにチェックコードをインライン関数にすることで、認証ルーチンも特定しにくくなると思います。


やっちゃいけないのは、リソースとして保持すること。

書き換えられて0,0,0,0,0にでもされれば00000-00...で認証されます。


あと認証後の起動ですが、これは入力してもらったままの状態でならレジストリなど目に見えるところに置いても特に問題無いかと。

レジストリやiniファイルからキー文字列を取得し、起動のたびに認証すれば問題ないと思います。

(これは簡易的な認証なので、高価なソフトならもっと複雑にするべきです)

ダミー:http://q.hatena.ne.jp/

id:er7

ありがとうございます。パスワードチェックということになるのでしょうか。今回、有効期限を設定してその期間だけ使えるようにしたいと考えています。有効期限をハードコーディングした場合に、どんな処理を書けばチェックできるのか、サンプルをご存知であれば教えていただけますか。宜しく御願い致します。

2006/11/26 23:31:16
id:wm5775 No.2

wm5775回答回数351ベストアンサー獲得回数42006/11/26 22:47:54

ポイント23pt

http://www.hatena.ne.jp

#URLはダミーです。

Windowsのみであれば、売り物ですが、ProtectKitというツールが便利です。

だいたい思いつくやりたいと思いつくことはすべて網羅されていると思います。

それから、ソフトにそれなりに高い金額をつけようとしているのなら、アラジンのHaspというハードウェアキーを使うのがよくあるパターンです。

両方ともDLLをアプリに組み込む必要がありますが、説明書にサンプルコードが掲載されていると思います。

id:er7

ProtectKit2 標準価格 68,000円ですね。確かに多機能なのですが、少し高額です。。。。。良い検討対象を教えていただき、ありがとうございます。ただ、できるだけ低コストで実現したいというのもありますので、簡単な日付チェックのサンプルなどあれば教えていただければと思います。

2006/11/26 23:34:31
id:kazu1107 No.3

kazu1107回答回数199ベストアンサー獲得回数142006/11/27 06:21:49

ポイント22pt

#include <iostream>

#include <time.h>

const char* file = "file.dat";

const time_t mask = 0xF0F0F0F0F0F0F0F0; // 時間データのマスクキー(もっとランダムにするべき)


// ファイルからリミットタイムを取得

void GetLimitTime(time_t *limitTime){

FILE *fp = fopen(file, "rb");

if(fp == NULL){

*limitTime = 0;

return;

}

fread(limitTime, sizeof(time_t), 1, fp);

*limitTime ^= mask; // XOR簡易デコード

fclose(fp);

}


// ファイルにリミットタイムを書き込み

bool SetLimitTime(const time_t *limitTime){

FILE *fp = fopen(file, "w");

if(fp == NULL){

return false;

}

time_t t = *limitTime ^ mask; // XOR簡易エンコード

fwrite(&t, sizeof(time_t), 1, fp);

fclose(fp);

return true;

}


int main(){

int probation = 0; // 初めて起動した日を除いた試用期間

// (0を設定すれば起動した日の23:59:59)(day)

time_t nowTime, limitTime;

GetLimitTime(&limitTime);

if(limitTime == 0){

time(&limitTime);

limitTime += 86400 * probation; // 1日の秒数 * 日数

SetLimitTime(&limitTime);

}else{

time(&nowTime);

nowTime += 86400*1;

tm t_now, t_limit;

t_now = *localtime(&nowTime);

t_limit = *localtime(&limitTime);

// nowTimeとlimitTimeの比較でも良いですけど、

// 秒単位でリミットを決めることになります。

// limitTime自体はUCT基準なので、計算や時差取得が面倒でこの方法にしました(汗)

if( (t_limit.tm_year < t_now.tm_year) ||

(t_limit.tm_yday < t_now.tm_yday))

{

std::cout << "試用期間切れです。" << std::endl;

return 0;

}

}


struct tm t_st;

t_st = *localtime(&limitTime);

std::cout <<"試用期間は" <<

t_st.tm_year+1900 << "/"<<

t_st.tm_mon+1 << "/" <<

t_st.tm_mday << " " <<

"までです。" << std::endl;

return 0;

}


先の解答は全く的外れだったようで、ごめんなさい。。。

SetLimitTime,GetLimitTimeの動作はもっと工夫しないと現状ではファイル消されれば一発リセットてなかんじですが。。。

単純な日付計算と判断についてはこんな感じではないでしょうか?

http://q.hatena.ne.jp/

id:er7

ほぼ、このコードで問題ありません。ありがとうございます!ここからは自力でも可能かもしれませんが、以下のような処理のコードも、あれば貼り付けていただけると助かります。ポイントも加算するように致します。

「char[] limit = "2006/11/28"」という感じに試用期限を文字列としてハードコーディングしている場合に、現在日時を取得して上記limitと比較をして、有効期限を確かめるサンプル。ファイルのI/Oが発生しないパターンです。

回答者1人につき3件まで回答できるように変更しました。宜しくお願い致します。

2006/11/28 14:45:48
id:kazu1107 No.4

kazu1107回答回数199ベストアンサー獲得回数142006/11/29 03:21:45

ポイント22pt

#include <iostream>

#include <time.h>


int main(){

char limit[] = "2006/11/29";

int limitYear, limitMon, limitDay;

time_t nowTime;

tm tm_now;

sscanf(limit ,"%d/%d/%d", &limitYear, &limitMon, &limitDay);

// localtimeの仕様にあわせてデータ値を変更

limitYear -= 1900;

limitMon--;

// 現在の日付を取得

time(&nowTime);

tm_now = *localtime(&nowTime);

if( (limitYear < tm_now.tm_year) ||

(limitMon < tm_now.tm_mon) ||

(limitDay < tm_now.tm_mday))

{

std::cout << "使用期限切れです。" << std::endl;

return 0;

}

std::cout << "使用期限は" << limit << "までです。" << std::endl;

return 0;

}

かなりCライクなプログラムなので、VS.NET2005だと警告吐いたりするけど、とりあえず動きます。。。


http://q.hatena.ne.jp/

id:er7

ありがとうございます!大変助かりました!!

2006/11/29 07:30:09
  • id:wm5775
    先日回答したものです。

    コードを書くほどの時間はないので、方法論だけの説明です。

    #すんません

    簡単に実現するにはDLLやレジストリに使用期限を書き込んでおいて比較する方法ですが、これではすぐにクラッキングされてしまう可能性があります。

    これを避けるには、マシンのMACアドレスなどのハードウェア情報と使用期限を暗号化して、ライセンスキーとして配布し、復号化して、マシン情報と使用期限を比較するという方法をとります。

    #プロテクトキットやHASPでは内部でこのような処理をしています。
  • id:er7
    #wm5775さん

    レベルの高いプロテクトの内部処理を解説してありがとうございます。勉強になります。はてな いいですねー。
  • id:er7
    kazu1107さん

    すみません。ポイントを加算する前に自動終了してしまいました。いるか を差し上げれなくてすみません。ポイントの加算は、ポイントを送るか、kazu1107さんようの簡単な質問を作るか考えます。ちょっとお待ちください。
  • id:kazu1107
    あ、もう結構ポイントもらってるみたいなので、お気になさらずに^^
    いるか もあまり意識してませんしね(汗
  • id:er7
    申し訳ないです。まだ残っているこの質問に、コメントだけでも良いので回答を記載していただければ残り分差し上げます。すみません。http://q.hatena.ne.jp/1164717537

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません