2013/03/07
KAICHO: s_naray[at]yahoo[dot]co[dot]jp
※SPAM防止中

吉里吉里/KAGにおける不正コピー防止方法例

■はじめに

本書では、吉里吉里/KAGを利用したゲームにおいて、不正コピーを どうにか防止するための手段について論じる。

とはいえ、のっけからで恐縮だが、デジタルデータである以上、不正コピーを 完全に防ぐことはできない。本書の目的は、「可能な限りそのハードルを 上げて、損失を減少させる」こと……を実現するための、 基本の基本をお知らせすることである。

■まず、切実なる現状を理解する

しょっぱなから超愚痴だけど、まぁこういうバックグランドがあるんだよということで ちょっと書いてみよう。

現在、商業・同人含めPCノベルゲーム業界は極めて厳しい状況にある。 DVDメディア含め、個人で手軽にコピー及びネットを通じた違法な頒布が可能な状態であり、 実際これが横行しているためだ。特に商業では、今回の売り上げを次のゲームの 開発費に充てるのだが、この確保が極めて難しくなってきている。

商用エロゲの売り上げ本数がどのくらいかご存知だろうか。まぁまぁヒットと 呼ばれるもので5000本、下手すると2000本に届かないこともよくある。 売上は一本7000円だとすると、2000本なら1400万円。結構あると思うかもしれないが、 実際には、一本の中堅ノベルゲームを作成するのにかかる金額が (勿論ピンキリだが)大体1000〜2000万円と言われているため、本当にカツカツだ。 逆算すると、7人が月20万円で働いて諸費用が一人10万円/月かかり、8ヶ月で ゲームを作り上げるとすると、それだけで既に1680万円。2000本(=1400万円)だと 大赤字になってしまう。実際には他にもたくさん費用(流通・広告など)が がかかるので、赤字幅は更に拡大。

なんでこんなことに?もちろん、「売れるゲームを作る」のが作り手の大前提だ。 ユーザが喜び、感動し、これなら金を払ってよい、と思えるゲームを作り出すための 努力は惜しんではならない。だがしかし、どんなにスバらしい作品を作っても、 それが心無い一部の人々にコピーされ、ネットの海に放流されてしまうとどうなるか。 コピー品を手にした別ユーザは、製品を改めて買おうとはなかなか思わない。 従って、売り上げが低下する。否、「著しく」低下する。

あるメーカーでは、 4000本売れたゲームの、パッチのダウンロード数が35000回だったそうだ。 ユーザが一人2回パッチをダウンロードしたとしても、単純計算で販売本数の 三倍以上(=(35000/(2*4000))-1)の人が、非正規でゲームを入手している可能性が あることになる。これでは次の開発に費用をかけることなどできようもない。 こんな状況だから、新ブランドが初期費用を回収することも極めて困難だ。 だからブランドが雨後の竹の子のように現れ、カビキラーをかけたお風呂のカビの ように消えていく。本当に、冗談抜きで危機的状況にある。

一方、同人界も酷いものだ。元々、同人ソフトでプロテクトや暗号化を施したものは 殆どない。コピーやデータ抽出などし放題の野放図状態。それをいいことに、 頒布開始翌日には、良作が、何の防衛手段も持たないままどんどんネットの海に 放流されていく。結果、せっかく良作を出したサークルの、次が続かない。開発費用が 回収できなかったり、感想を貰えなかったり。いくら同人でも、そのダメージは 図り知れない。 売り上げや頒布数の増加が製作者のモチベーションを著しく向上させるという 特殊事情もある。 伸びえたかもしれない才能が、そこで無残にも潰えていくのを 見るのは本当に忍びない。

やはり、不正コピーを抑止する手段を考えねばならん。そしてそれは、 ゲーム会社やゲームサークルが個別に頭を捻るのではなく、我輩みたいな 一見あまりそういうののステークホルダーではなさそうな人が(基本を)考えた方が、 色々角が立たずに済みそうな気がする。そういうモチベーションで、以下の 文書は作成されていると思って頂きたい。

以下はオマケ。

データ流出はどうなんよ、という話もある。これは直接的には売り上げに関わらない ように思うかもしれない。しかし、 実際には流出したデータを再構成して同等なゲームを他プラットフォーム(例えば PSP)上で遊べるようにしてしまうパワフルな人々がいて、そういう再構成された ゲームが無料頒布されたりすると、やぱり売り上げに関わってくる。また、 シナリオを読ませるゲームなら、シナリオのクライマックスだけが流出 するだけで頒布量に影響するし、エロゲならエロシーンが流出すれば言わずもがな。 加えて、素材を作った人が、「データ流出があったから、もうお前んトコには 素材を提供せん」とか、「今後はもっとお高いお値段で」とか言い始めている。 同人サークルにはかなり厳しい。 だから、我輩は、データ流出も可能な限り防止すべきだ、という立場。

同じ理由で、プレイ動画についても我輩は否定的だ。結局、ゲームはコンテンツだ。 コンテンツが流出してしまえば、ゲームのマスター価値は著しく低下する。 映画を考えてみよう。「解説しながら映画を流した動画をニコ動にuploadする」 行為が、その映画の売り上げに絶対影響しないか?そんなこたないだろう。

「そういう二次利用が新しい文化を生み出すことがある、だからある程度は 認めて欲しい」と主張する人々がいる。オーケー、二次利用が文化発展に 貢献することがあるのは認めよう。だったら、ちゃんと許諾を取ろうよ。 二次利用したいならちゃんと著作者にその旨を問い合わせようよ。 義務を果たさず権利だけを要求するのは子供のワガママだ。上の主張は、 「文化の発展のためだから、他人の家に押し入って金品を根こそぎ強奪してもいい、 結果その家の人が飢え死にしようが知ったこっちゃない」に等しい。 そうじゃなくて、まずは玄関の呼び鈴を押し、「申し訳ありませんが 少しお金を分けていただけませんか」とお願いする、そういう謙虚な姿勢で臨もう。
※フランスみたいに法律でパロディを規定してればこんな問題はないと思うのだが、 残念ながらニッポンジンはそういうの苦手みたいだ。これは本当に残念だと思う。

ことほど左様に状況が逼迫していることを、本当にマヂで皆様には理解して欲しい。 心から。だからどうしろとは言わない。でも理解はしておいて欲しい。

■ロジカルシンキン

かような現状を打破するために、本書では、不正コピー防止を目標とし、 まずロジカルシンキンのHOWツリーを使ってその方法を考えてみる。 ざらっと考えて出てきたHOWツリーは以下のとおり。 太字のものは対策として使えそうなもの。 ここでは同人ソフトを対象にしているので、 普通の人ができそうにないこと(ドングルとかメディアに細工とか)は省いているが、 メーカーがプロテクトかけるなら(批判はあるかもしれないが) そのくらいのことは考えてもいいと思う。メディアに細工とかは一般的だしね。

とりあえず思いつくのはこんなものだろうか。

■それぞれをもう少し考えてみる

というわけで、上のロジカルツリーを基にして、各項目について、以下で少し 考えてみる。 注意すべきは、以下の方法は一つだけでは全然ダメで、いくつかを組み合わせる 必要があること。そうすることで飛躍的に不正コピーや不正展開に対する強度は 向上する。

●不正コピー防止(=検出)

何故不正コピーされてしまうかといえば、こちらもやっぱり簡単にコピーでき、 簡単に頒布可能で、しかもそれを誰もチェックしていないからだ。だったら 簡単、頒布を不可能にするか、不正に頒布されたものかどうかをチェックすればよい。

・メディアID比較(DVD-IDなどのチェック)
もし製品がDVD-ROMでのみ配布であれば、これが使える。DVD-ROMにはDVD-ROMの メディアIDというのがメディア最内周に書き込まれていて、これは「読み込み できるが書き込めないデータ」だ。DVD-RなどではDVD-RのメディアIDがあらかじめ 書き込まれており、変更できない(正確には、ちょっとイリーガルな方法で 変更できるのだが、まぁ…いいでしょ)。従って、このメディアIDをチェック すれば、少なくともそのメディアがDVD-ROMであるかないかはチェックできる。 当然、違えばコピー品として扱うことができる。 同様のIDにManufacture IDなどがあり、これらも利用可能だ。もちろん、 プレス業者の都合でゲームメディアが途中で変更されないという前提が必要。

これらをチェックするには、直接メディアの最内周データを読み込まなければ ならないため、SPTI (SCSI Pass-Through Interface) を使うか、 CreateFile('\\.\ドライブ名:')してReadFile()する必要がある。 Vista以降は書き込み指定 できなくなったようだ(なんでそういうことをしてしまうのかMS)が、 まぁ関係ないだろう。

・ローカルアクティベーション
アクティベーションには、ローカル(ユーザの手元)で行うものとネット経由の ものがある。 やり方は簡単、初回起動時にユーザに数値を要求し、ある一定の規則で作成された IDのみを受け取るとゲームをプレイ可能とする、というものだ。パッケージごとに 個別のIDを示す紙を貼り付ける必要があるのが難点。

ただし、ローカルアクティベーションでは、どうしてもIDの正当性をローカルで チェックする必要がある。一つでもIDが流出すればプロテクトの意味が 無くなるし、解析によりIDの規則性が流出すれば、同じ手法が二度と使えなく なってしまうことに注意。

・ネットワークアクティベーション
唯一性をチェックできるという意味で、ネット経由のアクティベーションの方が 安全性が高い。既に一度アクティベートされたIDが再びアクティベート試行された 時は、コピーの可能性が高いとして弾けばよい。

アクティベーション時、「製品の個別IDとユーザのメールアドレスを 登録すると、アクティベーションし、アクティベーション無効化のパスワードを 通知する」ようなシステムになっていれば、ユーザの特定、 製品の個別IDとアクティベーションIDの対応などがメーカー側で 一括管理できるため、不正コピーをかなり防止することができる。ユーザも 任意でアクティベーションを無効化できるので、別のPCにインストールする時や (あんま感心しないが)中古屋へ売る時にも安心。

ただし、この方法では、以下の条件が必要になる。

  1. ユーザはネットワークに接続でき、メールアドレスを持っていること
  2. メーカーがアクティベーションサーバを用意し、未来永劫維持し続けること

いまや1.は無視可能と思うが、2.はかなり難しい。 解決策としては、ネットワークアクティベーションの必要性を時限式とし、 発売から一定期間(一年くらい?)が 経過したら、ローカルアクティベーションだけでゲームを遊べるように、 最初からチェックルーチンを作りこんでおくことだ。 同人ソフトにしても商業ゲームにしても、一年を経過して売れ続ける ようなことはまず無いし、そこまで待ってでも(ローカルアクティベーションの ID流出による)コピー品をプレイしたいという人は更に少ない。従って、 このような制限で必要十分。…だと信じたい。

注意点としては、アクティベート済みのイメージがごっそり流出してしまえば、 結局コピー同様となってしまうこと。ユーザのメールアドレスがあればある程度 流出者を特定できるので、抑止力とはなりうるが、捨てメールアドレスなどを 利用されれば完全ではないことに注意。これを防止するには、他の方法と 組み合わせる必要がある。

ネットワークアクティベーション時に、ゲームに必要なファイルをメーカーから ダウンロードさせるようにしておくと、更に安全性が向上する。反面ユーザの 利便性は低下するけどね……。

・ユーザ毎に個別のIDを与え、そのPCでのみ遊べるようにする
ここまでやる必要あるか?と問われるとまぁアレなのだが、たとえば以下のような ユーザ個別の ID を、アクティベーション時に取得しておく。 そして、ゲーム中にこれらを適宜確認することで、同じ ハードウェア上で遊ばれているかをチェックし、別のハードウェア上だと 判断すれば再びアクティベーションからやりなおし、みたいな仕組みを 作っておけばよい。

後述するが、これらのIDをファイル暗号化のキーに使えば、更に強固な暗号化が 可能となる。というか同一マザー上でないとプレイできなくなる。なかなか酷い。

・ゲーム起動毎にネットを通じてユーザ特定する
上のようなチェックを、ゲーム起動時、あるいはゲーム中にちょくちょく 実行する。これにより、たとえば万一解析により一つだけ処理がスキップされても 「まだまだ!」とチェックを繰り出すことができ、解析者を諦めさせることが 可能となる。

しかし、そのたびにネットに接続していたのでは、ウィルスチェックソフトに 怒られたり、スパイウェアだと罵られたりする可能性がある。マニュアルなどで 先にその旨詳らかにしておくことを忘れずに。また、実際ネット接続できない時は プレイできないと、オンラインゲームと何が違うのかわかんなくなっちゃうことにも 注意が必要。

ホットキーの禁止
これ、ちょっと悩ましい。完全に防止するには、吉里吉里本体をリコンパイルする 必要がある。しかし、それはさすがに面倒だという方のために、 こんな方法があることを ご紹介。吉里吉里は起動オプションで -debugwin=no を指定されるとデバッグ ウィンドウを表示しない(Shift+F4とかでも表示されなくなる)ので、こうやって 起動スクリプト中で無理矢理指定しておけば大丈夫。
krkrconf.exeから設定できたりもするけど、そんなの知ってる人だったら あっという間に回避しちゃうので、だったらいっそのこと 吉里吉里から(少なくともデバッグウィンドウとコンソール開くような) ホットキーの機能を落とすバイナリパッチを書こうかなぁ、なんて思ったりも。 要求多ければ書くので知らせて欲しい。

●データ不正頒布防止

画像・シナリオ・音楽データの不正頒布を防止するには、 データの暗号化が一番だ(こちらで述べている)。 暗号化は、不正コピー防止の各方法と組み合わせて使うことで、より強固となりうる。

.tpmファイル、プラグイン追加を禁止・各ファイルのMD5sum・signature チェック
これは別ドキュメントで述べているので割愛。 しかし、改竄防止は、他の全ての対策の基本となるものである(解析により プロテクトの回避方法が漏洩したとしても、改竄できなければ回避策が恒久的に 施されることはないため)ので、必ず実施しておきたいところ。…でも、カンペキに 実装するには、やっぱりそういう仕組みを作りこんだ吉里吉里全体をリコンパイルする 必要があるのであった…。

必要ファイルをネット上に配置し、逐次download
必要なファイルがネット上にあって、それを逐次downloadしながら動作する ゲームであれば、そのファイルの書き換えや展開は飛躍的に困難になる(アタリマエ)。 …それはネットゲームと何が違うのか、というツッコミを期待するところ。

当然ネットワークに接続しないとプレイできないので、ローカルプレイできなくて 困るユーザが出てしまうことに留意すると、 現実的にはこの方法はそのままは使えない。 アクティベーションの時に、必要なファイルをローカルIDでエンコードした後 メーカーからダウンロードさせるようにすれば、 プロテクトの一種として使えなくもない。
そのために必要な、「ある.xp3ファイルだけ別のデコードをするための方法」は 別ドキュメントの下の方ででこっそり紹介済み。

シナリオ中で複数の箇所からコピーチェックルーチンを呼び出すようにし、シナリオを全部チェックしないと解除できなくする
チェックルーチンを複数用意(内容は全く同じでもよい)し、複数箇所からこれらを ばらばらに呼び出すようにすると、解析してこれらをスキップさせる処理を 組み込むようなクラッカーに対し、有効な手段となる。100個の別名を持つ チェックルーチンが、シナリオ中10000箇所から呼ばれていたら、それを 手動でどうこうしようという意欲は著しく萎えるだろう。 当然、機械的に解除できないように、呼び出す側も工夫しておく必要があるが。 なお、サブルーチン化は極力しない。そうすると一箇所の対策で全チェックが スキップされてしまう可能性がある。「サブルーチン化しない」というアナクロな 対策が、実は結構ズシリと効いてくるのであるよ。

■具体的な方法をひねり出す

色々考えることはあると思うが、 ここで目指すのは「同人レベルの対策」ということで、まず、 そんなに煩雑ではない「ローカルアクティベーション+α」という方法を考えてみる。 即ち、「完全に違法コピーを防止することはできないが、抑止力にはなりえる」 方法を考えてみる。ユーザに優しく、メーカー・サークルに優しく、実装には そんなに時間やりソースがかからない、そんな方法が理想。

●方針1──ローカルアクティベーション

まずは最も単純な「ローカルアクティベーション」のコピープロテクトを考えよう。 以下のような方針で実施する。

  1. 頒布メディアにユニークキーを一つ添付する
  2. ゲーム起動直後、ユニークキーを入力することで、ゲームが遊べるようになる
  3. ユニークキーがなくとも、ゲームは途中までプレイ可能とする(体験版的に)

簡単だ。ネットワークとか全然使わないし、ユーザもメディア(と ユニークキー)を保存するだけで済む。 ユーザローカルではインストールし放題だし、一度ユニークキーがもれちゃうと 全く何のプロテクトにもならないけれど、まぁ基本ということで。

頒布メディア添付のユニークキー
これは、メディアごとに別の値を持つキーだ。 ユニーク(一意)であればなんでもいいが、 「ユーザに推測されない値」でなければならないため、 シリアルNo.のように連続していてはいけない。 単純に乱数で生成してもよい。 ただし、ゲーム添付のプロテクトチェックルーチンで正当性を判断するため、 メーカ側ではどのような値だったかはリストアップして保存しておく必要がある。

・ユニークキーの確認方法

ユニークキーは、ゲーム側で正当かどうかを確認する必要がある。単純に ユニークキーのリストをゲーム側に持っていると、解析されてあっという間に ユニークキーが全部放流されてしまうので、ここはちょっと捻ろう。 具体的には、「ゲーム側でリストを持っているのは ユニークキーのハッシュ値」にすればよい。 つまり、ゲーム側(ユーザのローカル)では、用意されている全てのユニークキーの ハッシュ値リストを持っておき、与えられたユニークキーのハッシュ値と これを比較することで、正当であるかどうかを判断すればよい。例えば、md5値を ハッシュとするならこんな。

与えられたユニークキーそのハッシュ値ゲーム側で持っているハッシュ値リスト
"ccc"9df62e693988eb4e1e1444ece0578579 47bce5c74f589f4867dbd57e9ca9f808
08f8e0260c64418510cefb2b06eee5cd
9df62e693988eb4e1e1444ece0578579(これが同じ)
77963b7a931377ad4ab5ad6a9cd718aa

キーからハッシュ値を求めるのは簡単だが、ハッシュ値からキーを求めるのは 極めて難しい(ことになっている)。だから、ハッシュ値をユーザ側でリストして いても、それとマッチするキーをユーザが推測することは不可能に近い。嘘だと 思うなら、上のハッシュ値リストについて、残りの三つの元キーをひねり出そうと してみるといい。ほーら、難しいでしょ?正解は、それぞれ"aaa"、"bbb"、"ddd" でしたとさ。
従って、このように、ユーザ側にユニークキーのハッシュ値リストを持って いたとしても、ユニークキーそのものが大量に漏出することはまずない。反面、別の ユニークキーのハッシュ値がどれかと重なる可能性(衝突という)もあるにはあるが、 母数が10000だとしても、md5が重なる可能性は極めて低いので、それは無視可能だ。
とはいえ、最近md5は衝突する値を探し出すのが現実的な時間で 可能になったという話を聞く。カンペキではないということだ。代わりにsha512 とかにしてもいいが、そうすると今度はチェックのためのハッシュ値リストが 巨大になったりする(512bit=64byteなので、10000キー用意すると640KBになる)ので、 どっかで見切りをつけて割り切る必要がある。

・実装例

…というようなのを実装するには、以下のようなファイルが必要となる。 ユーザ側(ゲーム側)に配置するのはaaaaaaaa.tpmとaaaaaaaa.datの二つのみで、 これらをゲームのplugin/ディレクトリ以下に置いて、ゲームスクリプトから TJS関数を呼び出し、戻り値を判断する。

以下のファイルを元に、ローカルアクティベーションの実現方法を示す。

  1. makehashdata1.plを実行して、ハッシュ値リストファイルaaaaaaaa.dat(適当な名前に変更)を作成
  2. aaaaaaaa.tpm(適当な名前に変更)とハッシュ値リストファイルaaaaaaaa.dat(適当な名前に変更)をゲームのplugin/に配置
  3. ゲームスクリプト中いたるところから、TJSスクリプト checkUniqKey(hashlistfile, uniqkeyfile)を呼び出してキーをチェックする

これにより、ゲーム起動後、checkUniqKey() が実行される度に、 ユニークキーの存在がチェックされ、必要であればダイアログボックスを開いて ユニークキーを確認するようになる。

機能ファイルソースコード説明
キーチェックdllaaaaaaaa.tpm ゲームのplugin/ディレクトリ以下になんとか.tpmという名前で配置
これは、TJSの関数 checkUniqKey(hashlistfile, uniqkeyfile) を定義する吉里吉里 プラグインだ。関数詳細は以下の通り。

関数概要
bool checkUniqKey(hashlistfile, uniqkeyfile)

機能
ユニークキー入力を促すダイアログを開き、入力された値の正当性をチェックする。 hashlistfileの中と入力された値のハッシュ値を比較し、合致するものがあれば true を返し、uniqkeyfileにその値を書き込む。次回以降は uniqkeyfile が存在し、それが正しければ二度とダイアログを開かない。

引数
hashlistfile ... 次項で説明するハッシュ値リストファイルを指定
uniqkeyfile .... 入力したユニークキーを保存するファイル名を指定

いずれの引数も文字列であり、環境変数(例えば%APPDATA%)も使用可能。環境変数は この関数内で適当に展開される。

返り値
入力したユニークキーが正しいと、関数はtrueを返す。 ユニークキーを入力せずにキャンセルすると、関数は false を返す。 それをどうするかはスクリプト側で判断すること(falseが返ってきたら、タイトルに 戻るとかすぐゲームを終わるとか)。

使用例
最も簡単な使用方法として、ユニークキーが正しく入力されなかったら ゲームを強制終了しちゃうというのがアツい。 KAGからだと、例えば以下のように書く(ここではハッシュ値リストファイルを "plugin\\a.dll"、ユニークキーファイルを "%APPDATA%\gamename\uniqkey.dat" としている)。パス区切り文字の '\' は、文字列中 '\\' と書く必要があることに注意。

[close ask=false cond="!checkUniqKey('plugin\\a.dll', '%APPDATA%\\gamename\\uniqkey.dat')"]

ハッシュ値リストaaaaaaaa.dat- 上の checkUniqKey() に指定するfileの実体。だから、ファイル名と配置位置は 適宜変更すること。ヘンな名前にすれば、クラッカーを欺ける可能性あり (拡張子を.dllにしたりしてるのはそのため)。 中身はユニークキーのハッシュ値リスト(バイナリ)。上のaaaaaaaa.tpmが読み込み、 ユニークキーが正しいかどうかチェックするために利用する。

これはテスト用のものであり、以下の五つのユニークキーに対するハッシュ値が 格納されている。従って、このデータを使うと、以下五つのユニークキーのみを 受け付ける。
d4c07356507b9256a5a9efd08dfd206a
347a7ac440bec83edb2a84281293a2c6
5e21e1e50f458c9f183047f055cc8d4c
66d98980922b24533d5065c5b3a781dd
5957ad82caff95f1cc4ae8a0ae164a04

ユニークキーをばらしちゃってるので、 この頒布されているハッシュ値リストファイルを、 テスト目的以外では使わないこと。 実際には、次のプログラムmakehashdata1.plから自動生成されるものを使えばよい。

ユニークキー・ハッシュ値リスト生成スクリプト makehashdata1.pl - 以下のように実行することで、 上のハッシュ値リストファイルを(500人分)自動生成することができる。 cygwin上でも実行できるし、ヘンなライブラリとか使ってないから、perlが動けば フツーにどこででも使えるんじゃなかろうか。
※500などの数値はそのゲームで見込まれるユーザ数のmaxを 必ず越える値にすること!今の仕組みだと途中で追加できないし、生成する度に ユニークキーは全く別のものになるから、一度組み込んじゃうと変更できないため

# perl makehashdata1.pl ハッシュ値リストファイル ゲーム名.txt 500

ユニークキーのリスト(500個分)はゲーム名.txt中に記録され、それに対応する ハッシュ値リストが「ハッシュ値リストファイル」に格納される。 ゲーム名.txt 中のユニークキーを個々に印刷して、頒布媒体一枚一枚に添付すれば よい。スゲータイヘンだけど。
当然、ゲーム名.txtはメーカー側だけに 保存すること。コレが漏洩したらプロテクトとか何の意味もない。

どうだろう。案外簡単に実装はできることがわかっただろうか。 まだまだ捻らないとプロテクトとは言えないが、 最も基本的な考え方はこんなカンジだ。 KAG/TJS上でプロテクトをかけることの是非を問う声もあるが、我輩は、柔軟性も 考えてそれでもいいと思う。 別頁で述べているXP3ファイルの暗号化を併用することで、 書き換えられる可能性も低くなるし。

●方針2──簡単なネットワークアクティベーション

次のコピープロテクトは、もう少しハードルの高いネットワークアクティベーションを 考えてみる。ユーザのメールアドレスも一緒に登録させることで、 「誰が」ユニークキーを保持しているかを「メーカー側で把握」し、 再登録や無制限のコピーを(倫理的に)防ぐというカンジだ。
ユーザにまぁ優しく、メーカー側の負担も小さく、 コピーへのハードルはちょっと高い、 (同人ゲーム向けであれば)バランス取れた方法だと思う。

  1. 頒布メディアにユニークキー1を一つ添付する
  2. ユーザはメーカーWebPageにアクセス、ユニークキー1とメールアドレスを 入力すると、メーカーからメール経由でユニークキー2が送られてくる
  3. ゲーム起動直後、ユニークキー2を入力することで、ゲームが遊べるようになる
  4. ユニークキー2がなくとも、ゲームは途中までプレイ可能とする(体験版的に)

できるメーカーなら、2.と3.は「ゲーム起動したら自動的にユーザに問い合わせ、 メーカーに情報を送り、メーカーからのユニークキー2を自動的に記録する」 ように作れば、ユーザの負担は極めて少なくなるだろうが、まぁそこまでしなくても いいだろう(それだとメールアドレスの有効性確認もイマイチだし)。

頒布メディア添付のユニークキー1
方針1で述べたものと同じように、メディアに添付する一意な値を持つキー。 この値は、ユーザが間違いなくメディアを持っているかどうかの確認に使用するため、 そのユニークキー1が確かに存在しており、一意に利用されているかどうかを メーカー側で確認しなければならない。

メールアドレス
これがこの方法のキモ。ユーザには、自分のメールアドレスとユニークキー1を メーカー側に送ってもらう。その後メールでユーザにユニークキー2を通知する。 ということは、以下三点が確認できるということだ。

  1. ユニークキー1が正当なものであるかどうか(逆に言えば、既に誰かが使っているなら不正コピーの可能性が高い)
  2. メールアドレスが正当なものである(到達可能)かどうか
  3. ユニークキー1・ユニークキー2とメールアドレスの対応

これらにより、同じユニークキー1と別のメールアドレスの組が 申請されたら、「こいつコピーしてるー!」というカンジのことが判断可能になるし、 正当でないユニークキー1が何度も入力されるならクラックされてる可能性を 判断できる。加えて、メールアドレスをメーカーに晒すことは、違法コピーの 抑止力となりうる。たとえ捨てアドレスだったとしても、履歴が残る以上足が完全に 消えるわけではないので、抑止力としての効果は高い(と信じたい)。
反面、メーカー側にはこのメールアドレスを漏洩しないための仕組みが必要に なるのであるが。

ユニークキー2
これもユニークキー1と同じく、メーカーが予め用意していた無作為の文字列。 上のユニークキー1、メールアドレスと組として、メーカー側でその組み合わせを 保管することになる。
ユーザは、このユニークキー2を保存することで、もう二度とメーカーに接続する 必要はなくなる。本当はゲーム中で何度もメーカーサイトに接続して正当性を 常にチェックする…みたいなこともやってもいいかと思うが、ユーザが インターネットリーチャボーでなかったりした時のことを考えて、そういう 意地悪は極力しないようにする。

登録済みのユニークキー2が漏洩した場合、ユーザサイドでの無制限のコピーを 防ぐ手段はないが、メーカー側にはユーザのメールアドレスがあるわけで、 どのユーザがユニークキー2を漏洩したかが確認可能。これも抑止力としての 効果を期待する。

・実装例

以下のファイルを元に、ネットワークアクティベーションの実現方法を示す。

  1. makehashdata2.plを実行して、ハッシュ値リストファイルaaaaaaaa.dat(適当な名前に変更)とゲーム名.csvを作成
  2. aaaaaaaa.tpm(適当な名前に変更)とハッシュ値リストファイルaaaaaaaa.dat(適当な名前に変更)をゲームのplugin/に配置
  3. メーカーのhttpsサーバ上にゲーム名.cgiとゲーム名.csvを配置
  4. ゲームスクリプト中いたるところから、TJSスクリプト checkUniqKey(hashlistfile, uniqkeyfile)を呼び出してキーをチェックする

これにより、ゲーム起動後、checkUniqKey() が実行される度に、 ユニークキー2の存在がチェックされ、必要であればダイアログボックスを開いて ユニークキー2を確認するようになる。ユニークキー2は、メーカーのCGIページに アクセスして、ユニークキー1とユーザのメールアドレスを入力することで メーカーからメールで送られてくる。

機能ファイルソースコード説明
キーチェックdllaaaaaaaa.tpm 方針1のものと全く同じ。ユニークキー2を入力するとゲームができるようになる。
ハッシュ値リストaaaaaaaa.dat- これも方針1のものと全く同じ。確認するのがユニークキー2に変わっただけ。 次のプログラムmakehashdata2.plで自動生成されるものを使うこと。
ユニークキー・ハッシュ値リスト生成スクリプトmakehashdata2.pl- 以下のように実行することで、上のハッシュ値リストファイルと、 ユーザデータリストcsv(の初期値)を500個分自動生成する。
※500などの数値はそのゲームで見込まれるユーザ数のmaxを 必ず越える値にすること!今の仕組みだと途中で追加できないし、生成する度に ユニークキーは全く別のものになるため、一度組み込んじゃうとやり直しは 効かないため

# perl makehashdata2.pl ハッシュ値リストファイル ゲーム名.csv ゲーム名.txt 500

ユニークキー1、2のリスト(500個分)は、「ゲーム名.txt」中に記録され、 それに対応するハッシュ値リストを持つ「ハッシュ値リストファイル」を作成する。 「ゲーム名.txt」中のユニークキー1を個々に印刷して、 頒布媒体一枚一枚に添付すること。生成された「ゲーム名.csv」は、 ユーザ情報を扱うデータとしてメーカーのアクティベーションページで使用する。 当然、「ゲーム名.txt」及び「ゲーム名.csv」はメーカー側だけに 保存すること。

アクティベーションCGIゲーム名.cgi- https(httpじゃダメよ!)サーバ上に配置。 ユニークキー1とメールアドレスを受け取り、 それらが正当であればユニークキー2を記したメールを返す。やることは以下の通り。 これらは全て、メーカーのhttpsサーバ上で実行する。

  • まずアクティベーションページを表示し、ユーザにユニークキー1とメールアドレスの入力を促す
  • ユニークキー1とメールアドレスが入力されたら、データファイル「ゲーム名.csv」を開く
  • ユニークキー1が正当かどうかチェック
  • メールアドレス(二度入力)が合致するか、メールアドレスとして適当かチェック
  • ユニークキー1が既に別ユーザに使用されていないかチェック
  • ユニークキー2を選択して、ユニークキー1・メールアドレスと共に「ゲーム名.csv」に記録
  • ユーザにユニークキー2を通知するメールを送付
    ※OSや設定ごとにメール送付の方法は全く異なるため、このスクリプト中ではコメントアウトしてある

一応、ユーザのメールアドレスは、ゲーム名.csv が漏洩してしまった時のことを考えて、生テキストでは持たない ようにbase64エンコードしている(ここでバラしたら意味ないけど)。md5hashに しちゃうと、元のメールアドレスがわかんなくなっちゃうので、可逆なエンコード 方法を使わないとダメなのが歯がゆい。

以下のパラメータがデフォルトで設定されている。環境に合わせて適当に変更すること。 例えば /var/lib/gamename/gamename.csv や /var/log/gamename.log、 /var/lock/gamename.lck は、 CGIの実行者(Linuxならapache.apache)の権限で上書きできないといけないので注意。

$GAMENAME    = "gamename";
$USERDATFILE = "/var/lib/$GAMENAME/$GAMENAME.csv";
$LOGFILE     = "/var/log/$GAMENAME.log";
$CONFFILE    = "/etc/$GAMENAME.conf"; # 存在しなくてもよい
$LOCKFILE    = "/var/lock/$GAMENAME.lck";
$CONTACTTO   = 'webmaster@your.maker.com';

●注意事項

これらのプロテクトは、「ユーザサイドのデータを、クラッカーが書き換えることが できないこと」によってのみその威力を発揮する。ユーザサイドでデータが 書きかえられちゃうと、もう全く意味がなく、プロテクトなんかさくさくと 解除されてしまう。というわけで、 吉里吉里/KAGでのデータ暗号化(実践編)で頒布しているような、改竄防止の 仕組みも必ず併用すること。「こうすればプロテクト回避できるのがわかってるのに 書き換えられないー!」という葛藤を、ライトクラッカーに味合わせることができて ちょっとスッキリ、かもしれない。

本当は、暗号化と不正コピー防止プロテクトは複雑に絡めた方がいいんだけど、 ここでは説明のための単純化のため、分離して説明している。

■おわりに

というわけで、とっても簡単で効果もそこそこなコピープロテクトの手法を一つ 紹介した。ホンモノのクラッカーからすればこんなものは子供だましで、(ついでに 方法も具体的に示しているから、)ハナクソほじりながら回避されちゃうのであるが、 少なくともライトユーザのライトコピーくらいは防げるよな、ということで一つ。