保護済み実行プログラムの作成のためのプログラム、方法及び装置
【課題】部分的に保護した実行コードの作成において、コンパイラの最適化によりコードの実行順序が変更されても、暴走等が起こりにくくする。
【解決手段】ユーザは、対象関数指定部306にて保護したい対象関数を指定する。第1変換部308は、オブジェクトコード304のうち、対象関数の関数名と同じ名前の挿入関数を作成すると共に、その対象関数の関数名を別の関数名に変更する。挿入関数は、対象関数の暗号化を解くための復号コードを含む。リンカ310は、挿入関数とオブジェクトコードとその他のライブラリをリンクする。第2変換部312は、リンカ310が出力する実行コードの中から、挿入関数の情報を用いて対象関数の場所を特定し、対象関数の部分を暗号化する。
【解決手段】ユーザは、対象関数指定部306にて保護したい対象関数を指定する。第1変換部308は、オブジェクトコード304のうち、対象関数の関数名と同じ名前の挿入関数を作成すると共に、その対象関数の関数名を別の関数名に変更する。挿入関数は、対象関数の暗号化を解くための復号コードを含む。リンカ310は、挿入関数とオブジェクトコードとその他のライブラリをリンクする。第2変換部312は、リンカ310が出力する実行コードの中から、挿入関数の情報を用いて対象関数の場所を特定し、対象関数の部分を暗号化する。
【発明の詳細な説明】
【技術分野】
【0001】
本発明は、プログラム内部に含まれる保護対象の内容が読み出されないようにプログラムに部分的に保護(例えば暗号化)を加えるための技術に関する。
【背景技術】
【0002】
この種の従来技術として、特許文献1に示される技術では、概略的には、図1に示すように、ソースコード100の中の保護したい部分114の前後にマーク(又は復号のためのコード)112,116を手作業で挿入し、挿入後のソースコード110をコンパイラに渡してコンパイルさせ、その結果得られたオブジェクトコード120をリンカに渡してリンク処理を行う。そしてリンク後のオブジェクトコード130に対し暗号化ツールを適用する。暗号化ツールは、オブジェクトコード130中のマーク132,136に従い、保護したい部分134を暗号化する(これにより暗号コード144ができる)と共に、マーク132,136を復号処理のためのバイナリコード(復号コード142)に置き換えることで、最終的な実行コード140を生成する。
【0003】
また特許文献2に示される技術は、特許文献1の技術のマークの代わりに、暗号化したコードを復号する復号コードを関数の形でソースコードに挿入するものである。すなわち、この技術では、概略的には図2に示すように、ソースコード200の中の保護したい部分214の前に復号関数212を、後に暗号化部分の終わりを示す関数216を手作業で挿入し、挿入後のソースコード210をコンパイラに渡してコンパイルさせ、その結果得られたオブジェクトコード220をリンカに渡して復号関数のオブジェクトコード230等の必要なコードとリンクさせる。これにより、復号コード246を呼び出す命令242の後に保護したい部分244の平文が並んだオブジェクトコード240が生成される。そしてリンク後のオブジェクトコード240に対し暗号化ツールを適用する。暗号化ツールは、オブジェクトコード240中の保護したい部分244を暗号化する(これにより暗号コード254ができる)ことで、最終的な実行コード250を生成する。実行コードを実行した場合、命令252により復号コード256が呼び出されて実行され、これにより暗号コード254が復号され、実行される。
【0004】
【特許文献1】特許第3033562号明細書
【特許文献2】特開2005−165919号公報
【発明の開示】
【発明が解決しようとする課題】
【0005】
上記従来技術は、いずれも、実行形式のプログラムを部分的に保護するための機能を実現している。しかし、コンパイラは、一般にコード実行順序の最適化を行う。最適化によりコード各部の実行順序が変わるので、例えば暗号化対象のコード部分の中に他のコード部分が紛れ込んだり、逆に暗号化対象のコード部分の一部がその部分の外に出てしまったりすることがある。このようなことが起こると、本来暗号化されるべきでない部分が暗号化対象部分と一緒に暗号化ツールで暗号化されたり、或いは暗号化されるべき部分が暗号化の範囲から外れて暗号化されなかったりすることになり、暴走するなどして正しく動作しないプログラムとなるおそれがあった。最適化によって暗号化対象部分にそのような順序変更が生じないように注意してソースコードを作成することは必ずしも不可能ではないが、プログラマに大きな負担を強いる。
【課題を解決するための手段】
【0006】
本発明の1つの側面では、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、処理をコンピュータシステムに実行させるためのプログラム、が提供される。
【0007】
本発明の別の側面では、コンピュータシステムにより実行される方法であって、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、方法が提供される。
【0008】
本発明の更に別の側面では、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成する手段と、対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する手段と、を備える保護済み実行コード作成装置が提供される。
【発明を実施するための最良の形態】
【0009】
以下、図面を参照して、本発明の実施の形態について説明する。
【0010】
図3は、保護対象のコード部分を暗号化した暗号化プログラムを作成するための暗号化実行プログラム作成システムの一実施例を示す図である。このシステムは、コンパイラ302、対象関数指定部306、第1変換部308、リンカ310、第2変換部312を備える。これら各モジュール302、306、308、310、312は、典型的には、CPU、メモリ、固定記憶装置、表示装置、及びキーボードやマウスなどの入力装置を備えた汎用のコンピュータに対し、以下で説明する各モジュールの機能又は処理内容を記述したプログラムを実行させることにより実現される。このようなプログラムは、CDやDVDなどの可搬型の記録媒体を介して、又はネットワークを介するダウンロードにより、コンピュータにインストールすることができる。なお、それら全てのモジュールが1台のコンピュータ上に実装される必要は必ずしもなく、複数台のコンピュータに分散配置されたそれらモジュールが連携動作してこのシステムを構成してもよい。
【0011】
コンパイラ302は、処理対象のプログラムのソースコード300をコンパイルしてオブジェクトコード304を生成する。コンパイラ302としては、従来からある一般的なものを用いればよい。上述の従来技術ではソースコードに対して手作業でマークや復号関数の呼び出し命令を記述したが、図3の例ではソースコード300には手を加えない。コンパイラ302は、そのソースコード300を従来周知の方式でコンパイルする。
【0012】
対象関数指定部306は、ユーザから、ソースコード300中の保護(この例では暗号化)対象の関数の指定を受け付ける。対象関数指定部306は、例えば、ソースコード300をそのまま画面表示し、その中に含まれる各関数の近傍にそれぞれ例えばチェックボックスを配置し、ユーザがそのチェックボックスをクリック操作などで選択状態とすることにより、保護対象の関数(以下「対象関数」と呼ぶ)を選択できるようにする。なお、ソースコード300をそのまま表示する代わりに、ソースコード300中に含まれる関数を抽出し、抽出した各関数とそれに対応するチェックボックスとを画面表示し、ユーザに選択をさせてもよい。そして対象関数指定部306は、そのようなユーザインタフェース画面を介してユーザが選択した対象関数のリスト(例えば関数名を列挙したリスト)を生成し、出力する。
【0013】
また、この代わりに、対象関数の関数名のリストをユーザがテキストエディタを用いて作成し、このリストを対象関数指定部306が受け取るようにしてもよい。
【0014】
第1変換部308は、コンパイラ302が生成したオブジェクトコード304に対し、対象関数指定部306が生成する対象関数のリストを用いて変換を行う。この変換を「変換1」と呼ぶことにする。変換1では、オブジェクトコード304の中で、対象関数名(或いは当該関数を示すシンボル名)を別の名称に変更する。またこの変換1では、対象関数を適切に暗号化できるようにするため、及び暗号化されたその関数を実行時に適切に復号して実行できるようにするために、挿入関数を作成する。これら関数名の変更と挿入関数の作成については、後で詳しく説明する。
【0015】
第1変換部308は、関数名を変更したオブジェクトコードと、挿入関数とを例えば別々のファイルとして出力する。またこの代わりに、第1変換部308が、関数名を変更したオブジェクトコードのファイルに挿入関数を追加して出力してもよい。このようにして第1変換部308が出力したオブジェクトコードと挿入関数のファイル、又はそれら両者を併せたファイルは、リンカ310へと渡される。
【0016】
リンカ310は、第1変換部308から受け取ったファイル(又は複数のファイル)と、ライブラリなど他の必要な関数とをリンクして1つの実行可能プログラムファイルへとまとめる。リンカ310としては、従来からある一般的なものを用いればよい。
【0017】
第2変換部312は、リンカ310が出力した実行可能プログラムファイルを取得し、そのうちの保護対象の部分を暗号化することで、部分的に暗号化された暗号化実行コード314のファイルを生成する。この第2変換部312が行う処理(暗号化を含む)のことを、以下では「変換2」と呼ぶ。この変換2の内容については、後で詳しく説明する。
【0018】
図4は、図3のシステムが行う処理の流れを模式的に示した図である。この実施例では、ユーザが行う手作業は、保護対象のコード部分を含むソースコード400(図3のソースコード300に対応)を作成する作業と、対象関数指定部306を操作して暗号化したい関数のリスト410を作成する作業である。残りの作業は、ツール化されており、ユーザは何も行わなくてよい。
【0019】
ソースコード400はコンパイラ302によりオブジェクトコード420(図3のオブジェクトコード304に対応)に変換される。この例では、このオブジェクトコード420のうち、関数名"funcA"422で示される関数が対象関数であるとする。
【0020】
このオブジェクトコード420は、第1変換部308により「変換1」の処理を受ける。「変換1」では、対象関数の関数名が別の関数名に変更される。関数名の変更は、オブジェクトコード420内の既存の関数の関数名と重ならず、かつ他の対象関数の変更後の関数名とも重ならない名称へ変更すればよい。例えば、1つの方法として、元の関数名に対し特定の文字列(或いはデータ列)を付加することで変更後の関数名を作成してもよい。付加する文字列として、通常関数名として用いられないものや、十分に長いものなどを用いれば、この付加により他の関数名と重ならない関数名を得ることができる。図示例では、元の関数名"funcA"が、Xという文字列を付加された別の関数名"funcAX"432に変更されている。なお、「変換1」では、このように対象関数の関数定義(関数の実体)における関数名は変更されるが、その対象関数を呼び出す命令の中の関数名は変更されない。
【0021】
また「変換1」では、挿入関数434が作成される。第1変換部308は、この挿入関数434に対し、対象関数の元の関数名と同じ関数名"funcA"を与える。これにより、オブジェクトコード430中にある対象関数"funcA"を呼び出す命令は、対象関数ではなく挿入関数434を呼び出すことになる。
【0022】
図5に、「変換1」が作成する挿入関数434(図5では挿入関数500として示す)の一例を模式的に示す。
【0023】
挿入関数500の先頭には、当該関数500中に記述される復号コード510へのジャンプ命令502がまず配置される。そして、その後に、後述する「変換2」(暗号化)の処理に用いるデータ504,506及び508が配置され、更にその後に復号コード510が配置される。この復号コードの内容は、復号処理のための一以上の命令を含むが、これは固定的なものなので第2変換部312が保持していればよい。復号処理の対象となる暗号化された関数のアドレス等を示す情報は、そのアドレスが決まった後でリンカ310が埋められるよう、リロケーションテーブルにデータを設定しておけばよい(詳細は後述)。ジャンプ命令502のジャンプ先のアドレスは、間にあるデータ504〜508のサイズが既知なので、求めることができる。データ504は、「変換2」の処理でこの関数500を見つけるための特別なマーク情報であり、一般的な実行コード中には表れないデータ列を用いる。データ506は関数"funcAX"(すなわち関数名が変更された秘匿対象関数)のデータサイズを示すデータである。これは、オブジェクトコード420から求めることができる。
【0024】
また、固定データ508は、アドレス情報を格納するのに十分な大きさを持つデータ領域である。この固定データのところに、後のリンカ310の処理により、割り当てられた関数"funcAX"のアドレスが設定される。すなわち、挿入関数"funcA"は、対象関数"funcAX"を復号するためのものなので、この復号の処理や関数呼出のために関数"funcAX"のアドレスが必要になる。しかし、実行時に関数がロードされるアドレスの値は、リンカ310がリンクを行った後でないと判定できない。そこで、ここでは、リンカ310が求めた関数"funcAX"のアドレスを容れる器として、固定データ508の領域をあらかじめ確保しておくのである。
【0025】
以上に説明したデータ504〜508の後に、暗号化した対象関数を復号するための処理を記述した復号コード510が配置される。復号コード510が復号する対象となるコードの位置は、関数"funcAX"の大きさデータ506と、固定データ508の位置に後でリンカ310が書き込む関数"funcAX"の先頭アドレスを参照し、取得するように構成しておく。データ504は、暗号化(変換2)においては用いるが、暗号化したプログラムを実行する際には使用しないので、変換2において削除してかまわない。この挿入関数500の冒頭にはジャンプ命令502が置かれるのは、504から508までのデータを、命令として実行しないようにするためである。そして、復号コード510の後に、関数名を置き換えた対象関数を呼び出すためのコード512が配置される。
【0026】
なお、ジャンプ命令502やデータ506,508,コード510,512などは、マーク504の位置(アドレス)を基準にしてそれぞれ所定の関係となる位置にあればよいので、それらの並び順や順序は図示の例に限らない(ただし、復号コード510と関数呼び出し命令512の並びは、510が実行された後、512が実行されるような順番に配置する必要がある)。
【0027】
また「変換1」は、挿入関数500に付属するリロケーションテーブル520も作成する。このリロケーションテーブル520には、通常のリロケーション情報に加え、データエントリ522及び524が含まれる。データエントリ522には、挿入関数500内の固定データ508のところにリンク時に判明した関数"funcAX"のアドレスをリンカ310に挿入させるためのデータ内容が書き込まれる。また、データエントリ524には、関数"funcAX"を呼び出すための命令コード512のオペランドにリンカ310が関数"funcAX"のアドレスを書き込むようにするためのデータ内容が設定される。これらアドレスの指定は、必要に応じ、相対アドレス指定又は絶対アドレス指定のうち適切な方で行えばよい。以下に、リロケーションテーブルのデータエントリ522及び524の具体例を表で示す。
【0028】
〔表1〕
Offset Type Applied To Index Name
00000012 REL32 00000000 13 _ funcAX
00000056 REL32 00000000 13 _ funcAX
【0029】
これは、Microsoft社のVisualStudioが利用しているCOFFフォーマットでの例である。この表の1行目は、データ項目を示す見出しで、テーブルの内容情報ではない。2行目がデータエントリ522に、3行目がデータエントリ524に相当するデータである。データ項目のうち"Offset"は、アドレスを書き込む場所を、関数の先頭からのオフセット(相対位置)で表現した値である。"Type"は書き込むアドレスの種類で、上の例("REL32")は、32ビットの相対アドレスを書き込むことを示す。"Applied To"は、書き込む先のデータ(固定データ508内のデータおよび、call命令512のオペランド)を示す。これらはリロケーションテーブル内のデータではない。"Index"は、書き込むべきアドレスの対象となるデータのシンボル名のインデックス(シンボルテーブルのエントリの番号)で、この例では、関数funcAXを示す。"Name"は、"Index"が示しているシンボル(ここでは関数名)を、シンボルテーブルを参照して表示しているものであり、実際のリロケーションテーブルには存在しない。
【0030】
表1の例では、00000012は、固定データの位置が、関数の先頭から0x12バイト目にあることを示し、00000056は、call funcAX();命令のオペランドが0x56バイト目にあることを示す。また、Indexの13は、funcAXのシンボルが13のインデックス番号に割り当てられていると仮定している。このように、リロケーションテーブルのエントリは、書き込む先のオフセット、書き込むアドレスの種類、書き込むべきアドレスにあるデータのシンボル(インデックス)の三つ組みで構成される。
【0031】
この第1変換部308の行う「変換1」の処理手順の例を、図6を参照して詳細に説明する。
【0032】
まず第1変換部308は、コンパイラ302が出力したオブジェクトコード(304すなわち430)と、対象関数指定部306が作成した対象関数のリストとを入力として受け取る(S1)。次に、第1変換部308は、対象関数のリストから1つ対象関数を取り出し(S2)、関数リストの最後に到達していなければ(すなわちS3でリストから関数を取り出せれば)(S3)、ステップS4に進む。
【0033】
ステップS4では、オブジェクトコード304をスキャンして、ステップS2で取り出した対象関数を検出する。より詳細には、オブジェクトコード304中のシンボルテーブルの中から、その対象関数の関数名に対応するシンボルを検出し、このシンボルに対応するオブジェクトファイル内のコード位置をシンボルテーブルから読み出す。このコード位置は、例えば、オブジェクトファイル内のセクション番号とそのセクションの先頭からのオフセットの組により表現される。これにより、対象関数が検出できる。
【0034】
次に第1変換部308は、ステップS5でその対象関数の大きさ(データサイズ)を求める。そして、ステップS6では、その対象関数の関数名を他と重ならない別の関数名に変更する。すなわち、特定の文字列を追加するなどにより変更した関数名のシンボルをシンボルテーブルに追加し、その関数の関数定義の指し示すシンボル名がその新たに追加したシンボル名となるようにする。
【0035】
次に第1変換部308は、ステップS7で、その対象関数の元の関数名を持つ挿入関数500をオブジェクトコード304に挿入する。すなわち、対象関数の元の関数名を示すシンボル名を関数名とする新たな関数(挿入関数500)の関数定義を追加する。ここで、挿入関数500のうち対象関数に依存する部分は、対象関数の大きさのデータ506だけであり、これはステップS5で求められているので、挿入関数500は作成できる。そしてステップS8では、挿入関数500の所定の位置に、リンカ310が対象関数のアドレスを設定することができるようにするために、リロケーションテーブルのデータエントリ522及び524を追加する。そしてステップS2に戻る。
【0036】
対象関数のリストに載っている全ての関数について処理が終わるまで、ステップS2〜S8の処理を繰り返す。リストの最後に到達すると(S3)、変換1の処理が完了し、第1変換部308は変換結果のデータをオブジェクトコードのフォーマットに従ったデータ(オブジェクトコード430)として出力する(S9)。これにより、「変換1」の処理が終了する。
【0037】
図4の説明に戻ると、「変換1」により生成されたオブジェクトコード430は、リンカ310により他の必要な関数とリンクされる。リンカ310の処理により、関数"funcAX"のアドレスが決定され、そのアドレスが固定データ508のところに設定され、更にそのアドレスが呼び出し命令コード512のオペランドに設定される。リンカ310が出力する実行コード440には、挿入関数500の挿入コードを呼び出す命令442の後に対象関数のコード444が平文の機械語で記述され、その後に挿入関数434の挿入コード446が来る。なお、呼び出し命令442の後に対象関数のコード444が配置されると行ったのはあくまで一例に過ぎない。実際には、コードの実行順序はリンカが適切に決定するので、呼び出し命令442と対象関数のコード444との並び順はどのような順序でもよい。
【0038】
この実行コード440が、第2変換部312に渡される。第2変換部312は、その実行コード440中の挿入コード446のデータに基づき保護対象のコード444の範囲を特定し、そのコード444を暗号化する。この処理の手順を、図7を参照して説明する。
【0039】
この手順では、第2変換部312はまずリンカ310の出力した平文の実行コード440を入力として受け取る(S11)。次に、「変換1」で埋め込んだマーク504をキーとしてその実行コード440を検索することで、挿入関数500を検出する(S12)。実行コード440の末尾に達しないうちに挿入関数500が見つかれば(S13)、マーク504を基準として、データ506及び508のアドレスを特定し、それら各アドレスから、その挿入関数500に対応する対象関数のサイズ(データ506)とアドレス(データ508)を取得する(S14)。そして、第2変換部312は、検出したマーク504を削除するために、マーク504のところに別のデータ列を上書きする(S15)。これは、暗号化された実行コード450が解析された時に、マーク504が解析の手がかりとなることを防ぐためである。実行コード中の各マークの位置を例えば乱数のように予測のつきにくいそれぞれ互いに異なるデータ列で上書きすれば、マークが存在したことを隠蔽できる。そして、第2変換部312は、実行コード440のうち、ステップS14で取得したアドレス及びサイズが示す範囲(すなわち対象関数のコード部分)を所定の暗号アルゴリズムにより暗号化する(S16)。この後、ステップS12に戻り、実行コード440の最後に達するまで、ステップS12〜S13の処理を繰り返す。ステップS13で実行コード440の最後まで達したと判定されると、その時点で作成されている実行コード450を出力する(S17)。
【0040】
第2変換部312の処理により生成される実行コード450の中には、復号コードの呼び出し命令452と、暗号化された対象関数のコード454とが配置され、その後に復号コード456が、そしてその後に暗号化された対象関数のコード454を呼び出す命令が配置される。ここで、呼び出し命令452とコード454の並び順は、図示の順序に限らず、どのような順序でもよい。この実行コード450をコンピュータシステムで実行すれば、関数"funcA"の呼び出しによりまず復号コード456が呼び出され、その実行の後に暗号化された対象関数のコード454が呼び出されることになる。これにより、暗号化されたコード454が復号され、実行されることになる。
【0041】
以上に説明した例によれば、暗号化対象が関数単位で指定され、関数単位で暗号化が行われるので、従来技術のように暗号化対象のコードの中に別のコードが紛れ込んで暗号化されるなどのような不具合を大幅に低減できる。また、特許文献1では、復号コードやマークなどをソースに挿入するために、プログラム開発環境にインラインアセンブラの機能が必要だが、この実施例では、対象関数の指定をすればよく、そのためのツールとして対象関数指定部306が用意されているので、インラインアセンブラのない環境にも対応できる。また、この例では、ソースコード自体は変更しないので、ソースコードのメンテナンス性が向上するというメリットも得られる。
【0042】
また、1プログラム中の複数の関数を保護する場合、第1変換部308又は第2変換部312で挿入する復号コードを、各対象関数ごとに互いに異なるコード内容とすることも好適である、例えば、同じ復号アルゴリズムを別のコード内容で表現した複数の復号コードを用いてもよいし、異なる暗号アルゴリズムに対応した複数の復号コードを用いてもよい。後者の場合、第1変換部308で復号コードを挿入する構成では、第2変換部312が各復号コードに対応した部分を正しく暗号化するための処理が必要である。例えば、第1変換部308で異なる復号コードを予め定めた順序で適用するようにし、第2変換部312ではその順序に従って各復号コードに対応する暗号アルゴリズムを適用したり、又は第1変換部308でどの暗号アルゴリズムに対応する復号コード化を示すデータを挿入関数中に書き込み、それを第2変換部312が解釈して適切な暗号アルゴリズムを適用したりする方法を用いることができる。
【0043】
また、挿入関数500内において、対象関数の呼び出し命令512の後に、対象関数を再暗号化するためのコードを追加することも好適である。このようにすることで、暗号化実行コードの実行時に復号された対象関数が実行された後、挿入関数500に処理が戻り、実行された対象関数の再暗号化が行われる。これにより、実行後にメインメモリ上に対象関数が残る場合にも、その内容を秘匿することができる。なお、再暗号化のコードには、メモリアドレス上のどの範囲を暗号化するかを示す情報が必要であるが、これは対象関数の大きさデータ506やアドレスデータ(固定データ508のところにリンカ310が書き込むデータ)等の情報を用いて、リンカ310が解決することができる。
【0044】
次に、図8を参照して、「変換1」がオブジェクトコード304に挿入する挿入関数の別の例を説明する。
【0045】
挿入関数800のうちマーク802、データ806及び808は、図5の挿入関数500におけるマーク504、データ506及び508とそれぞれ同じものでよい。また、リロケーションテーブル820に追加するデータエントリ822及び824も、図5のリロケーションテーブル520内のデータエントリ522及び524と同じものでよい。図5の挿入関数と500と異なる点は、挿入関数800にこの挿入関数800自身の大きさを示すデータ804が含まれることと、復号コード510の代わりに、後でその復号コードを挿入するためのエリア810が確保されているところである。
【0046】
挿入関数800自身の大きさのデータ804は、この挿入関数800自体も一部暗号化して保護する場合に利用できる。すなわち、復号コードなど挿入関数800内に含まれるデータ内容が解析されると、暗号化したコードの安全性が脅かされるので、挿入関数のうち平文である必要がある部分(例えばこのデータ804及び暗号化した復号コードを復号するコード)以外を暗号化することが考えられる。すなわちこの場合、対象関数を復号する本来の復号コード(第1復号コードと呼ぶ)と、その復号コードを暗号化したものを復号するための復号コード(第2復号コードと呼ぶ)が必要である。この場合、例えば、第2復号コード、第1復号コードを暗号化したもの、の順にコードを配列する。また、この場合、挿入関数の末尾がどこか分からないと実行時にどこまでを復号化したらよいか分からないが、このデータ804を用いれば末尾の位置を求められる。
【0047】
また、エリア810には、後の「変換2」の処理の中で復号コード(及び復号した対象関数を呼び出すコード)を挿入する。このように、復号コード等を「変換2」で挿入する構成とすることで、復号コードが平文状態で人の目に入る可能性を低減できるので、暗号化したコードの安全性を向上させることができる。
【0048】
また、このように挿入した復号コード等の部分を「変換2」の処理で暗号化することで、復号コードを保護することができ、ひいては対象関数の安全性の向上も図れる。
【0049】
なお、「変換1」でエリア810を確保するだけで、復号コード等の暗号化は行わない構成でも、復号コードの保護効果はある程度得られる。
【0050】
次に、対象関数に対して暗号化を多重的に施すことで、暗号強度を高める例について説明する。
【0051】
図9には、1重の暗号化処理ごとに、復号のための関数を別関数として挿入する方式の例を模式的に示す。この例では、実行コード900の中の対象関数"funcA()"を3重に暗号化している。この例では、暗号化が1重増えるごとに、関数名の後ろに所定の文字列(この例では"X")を1つずつ足していくという規則性に従い、関数名を変更している。すなわち、この例では3重の暗号化を施すので、対象関数名は"funcAXXX"(関数904)と変更されている。3重の暗号化のうちの外側の暗号化を解くための復号関数908が、元の対象関数と同じ関数名"funcA"を受け継ぐ。この関数908は、外側の暗号化に対応する復号コード910と、中間の暗号化を解くための復号関数914"funcAX"を呼び出す命令912とを含む。中間の復号関数914は、中間の暗号化を解く復号コード916と内側の復号関数920"funcAXX"を呼び出す命令918とを含む。内側の復号関数920は、内側の暗号化を解くための復号コード922と、対象関数904"funcAXXX"を呼び出す命令924とを含む。ここで、復号コード910,916及び922は、互いに異なるコード内容とすることが、暗号破りを難しくするという観点から見て好適である。これは、同じ復号アルゴリズムを別のコード内容で表現したものでもよい(この場合、内側、中間、外側の暗号化アルゴリズムは同じ)。また、内側、中間、外側の暗号化アルゴリズムを異ならせ、各復号コード910,916及び922をそれに応じて異なったものとしてもよい。
【0052】
対象関数の関数名の変更規則や、各段階の復号関数の命名規則は、例示したものに限らない。実行コード中で一意に区別でき、かつ対象関数の呼び出しにより最外側の復号関数が呼び出され、最内側の復号関数の中から名称変更後の対象関数が呼び出されるようになるならば、どのような規則で関数名を決めてもよい。
【0053】
このような実行コード900を作成するため、第1変換部308は、オブジェクトコード中の対象関数の関数定義の冒頭にある関数名を規則に従って変更すると共に、外側、中間、内側の復号関数を作成する。図示は省略したが、各復号関数には図5に示したようなマーク504や大きさデータ506、固定データ508、リロケーションテーブルのエントリ522,524が含まれる。第1変換部308が追加するリロケーションテーブルのデータエントリには、変換により追加される各関数名"funcAX"、"funcAXX"及び"funcAXXX"についてリンカ310で決定される各アドレスが、それぞれオブジェクトコード内の必要な箇所(図5の例で言えば固定データ508や呼び出し命令510のオペランド)に設定されるようにするためのデータが含まれる。関数名が変更されたオブジェクトコードと、外側、中間、及び内側の復号関数とは、リンカ310により1つの実行コードへと結合され、このとき、各関数"funcAX"、"funcAXX"及び"funcAXXX"についてのアドレス解決が行われる。
【0054】
第2変換部312は、リンカ310の出力した実行コードから復号関数908,914,920を検出し、それら関数間の呼び出し関係から復号関数の順序(内側、中間、外側)を特定すると共に、保護対象のコード906の範囲を特定する。そして、内側から順に暗号化を行う。内側の暗号化は、保護対象のコード906と、対象関数904を呼び出す命令924に対して施す。命令924は定型的なものであり、第1変換部308が作成するのでサイズや位置は分かっている。または、図5の例と同様、コード922内に、対象関数904の位置と関数920のサイズとが含まれるので、それらの情報から暗号化に必要な情報を得ることもできる。したがって、第2変換部312は命令924の位置及びサイズの示す範囲を暗号化すればよい。中間の暗号化は、保護対象のコード906(ただし内側の暗号化を受けたもの)と、内側の復号関数920を呼び出す命令918及び内側の復号関数920とに対して施す。命令918及び内側の復号関数920も第1変換部308が作成するため位置及びサイズが既知なので、暗号化できる。外側の暗号化は、保護対象のコード906(ただし内側及び中間の暗号化を受けたもの)と、中間側の復号関数914を呼び出す命令912と、中間及び内側の復号関数914及び920とに対して施す。この処理により作成される実行コード900では、外側の暗号化に対応する復号コード910は平文であるが、中間及び内側の暗号化に対応する復号コード916,918は暗号化されている。また保護対象のコード906は3重に暗号化されている。
【0055】
このように対象関数904が多重的に暗号化された実行コード900をコンピュータシステムにて実行した場合、呼び出し命令902によりまず外側の復号関数908が呼び出されて外側の暗号が解かれ、これにより中間の暗号化の復号コード916が平文になる。次に、中間の復号関数920が呼び出され、平文の復号コード916が実行されることで、中間の暗号が解かれる。そして同様にして内側の暗号が解かれることで、保護対象のコード906が平文となり、命令924によりそのコード906が呼び出されて実行される。
【0056】
多重暗号化の別の例を、図10を参照して説明する。この例では、1つの復号関数(挿入関数)1008内に多重に外側用、中間用、及び内側用の復号コード1010、1012、及び1014をその順に組み込んでいる。保護対象のコード1006を含んだ対象関数1004は、元の関数名"funcA"とは異なる関数名"funcAX"に変更され、復号関数1008には対象関数1004の元の関数名"funcA"が与えられている。復号コード1010〜1014のコード内容やサイズは第1変換部308が知っている(あるいは図5の例の方式と同様にして各復号コード内に書き込まれた情報から求めることができる)ので、第1変換部308は内側の復号コード1014が中間の暗号化で、中間の復号コード1012が外側の暗号化で、それぞれ暗号化されるように、オブジェクトコードに組み込むことができる。第2変換部312は、保護対象のコード1006及び対象関数1004を呼び出す命令1016を内側の暗号化処理で暗号化し、その暗号化結果と内側用の復号コード1014とを中間の暗号化処理で暗号化し、その暗号化結果と中間の復号コードとを外側の暗号化処理で暗号化する。
【0057】
このような処理で作成された実行コード1000をコンピュータシステムが実行した場合、対象関数1004を呼び出す命令1002により復号関数1008が呼び出され、まず外側の復号コード1010が実行されることで外側の暗号化が解かれ、これによって平文となった中間の復号コード1012が実行されることで中間の暗号化が解かれる。そして、その結果平文となった内側の復号コード1014が実行されることで内側の暗号化が解かれ、命令1016と保護対象コード1006が平文となる。この後、命令1016が実行されることにより、保護対象コード1006が呼び出されて実行される。
【0058】
図9及び図10の例に示したように、復号コードを複数用意し、内側の復号コードから順に、各復号コードに対応する暗号化により順に他の復号コードを入れ子式に暗号化していくことにより、対象関数を復号するためのコードの多くの部分を暗号化することができる。これにより、解析に対しより耐性の高い保護が実現できる。
【0059】
図9及び図10の例では、保護対象のコード906及び1006に対し、内側、中間、外側の暗号化を順に施したが、これに限らず、保護対象のコードには内側の暗号化のみを施し、その内側の暗号化を解除するための復号コードを中間及び外側の暗号化で保護するようにしてもよい。
【0060】
また、以上の例ではユーザの指定に応じて対象関数指定部が対象関数のリストを作成し、このリストに基づき第1変換部308が対象関数の関数名を変更した。ただし、これは必須のことではない。この代わりに、ユーザ(プログラマ)が、ソースコード中の対象関数名を、所定の修飾の付加により変更する方式もある。この方式では、ユーザが、エディタなどを用い、ソースコードの中で保護対象とする関数の関数定義の関数名に対し所定の規則に従った修飾を付加する。例えば"funcA"なる関数名の後に、あらかじめ定めた"_x"なる文字列を付加して"funcA_x"と変更するなどである。
【0061】
ただし、変更した関数名がプログラム内で一意になるようにするには、人間にとっては覚えにくく、入力しにくく、また後で読んで認識しにくいような、長く複雑な修飾文字列を付加する必要が出てくることも考えられる。そこで、関数名の変更作業を支援するために、ソースコードを前処理するプリプロセッサのマクロ機能を用いることも好適である。すなわち、この場合、人間にとって分かりやすく比較的入力しやすい修飾を、コンピュータにとって識別しやすく一意性が得られる確率の高い修飾に置換するためのマクロをユーザが作成してソースコードに追加する。そして、ユーザは、エディタ等を用いてソースコード中の対象関数の定義の関数名に人間用の修飾を付加する。この修飾付加済みのソースコードをプリプロセッサに処理させれば、対象関数の定義の関数名をコンピュータ用の修飾付きのものに変更することができる。このとき、仮に修飾を付けて変更した関数名が他の関数の関数名と重複してしまった場合は、プリプロセッサがその重複の事実を検出して警告を発するので、これに応じユーザは対象関数の関数名に与える人間用修飾を別のものに変更するなどの対処ができる。また、この例のようにマクロで修飾を与える場合、マクロを削除又は変更するだけで、それまでの修飾を解除することができる。したがって、複数の関数を保護対象に指定する場合に、保護の有効化/無効化の切り換え作業が容易になるという利点もある。
【0062】
この場合、図3のシステムでは、対象関数指定部306が不要となる。第1変換部308は、挿入関数の作成は行うが、関数名の変更処理は行う必要がない。挿入関数の作成に当たり、第1変換部308は、オブジェクトコード304のなかから、対象関数に対応する所定の修飾(コンピュータ用修飾)を持った関数の定義を見つけ出し、その関数定義の関数名からその修飾を削除したものを挿入関数の関数名とする。挿入関数の内容は上述の例と同様でよい。リンカ310及び第2変換部312は図3の例と同様のものでよい。
【0063】
このように、ソースコード上でプログラマ自身が対象関数の関数名を変更するようにすれば、暗号化の指定の有効化及び解除が容易に切り換えられ、デバッグやソースコードの変更、メンテナンスのしやすさを維持したまま関数名の修飾ができる。また、図3の例では、第1変換部308が対象関数の関数名を自動的に変更するので、プログラマが予期しない副作用が生じる可能性があるが、プログラマ自身が必要な関数名を変更する方式ならば、予期しない副作用のリスクは低減できる。
【0064】
なお、ソースコード中の対象関数の関数名をユーザが変更する方式は、ソースコードをユーザが改変するという点で従来技術と一致しているが、次のような相違がある。すなわち、従来技術ではソースコード中の関数の中に復号コードや復号関数を挿入するなど、関数の内部に対して改変を行っていたため、コンパイラの最適化によりコードの実行順序に予期せぬ変更が加えられ、想定する動作と異なった動作をする場合があった。これに対し、本方式では、関数定義の関数名しか変更しないので、そのような不具合は生じにくい。
【0065】
次に、図3、図4の装置により生成された暗号化実行コード314をコンピュータシステム上で実行する場合における、挿入関数434から暗号化した対象関数432を呼び出す際の関数の引数の引き渡しについて説明する。
【0066】
図3、図4の装置では、元々対象関数432を呼び出していた呼び出し命令430により挿入関数434が呼び出される。このため、呼び出し命令430に指定された関数の引数は、挿入関数434に渡されることになる。これら引数は、挿入関数434を実行して暗号化した対象関数432を復号した後、復号された対象関数432に正しく引き渡される必要がある。
【0067】
引数には、レジスタに設定されるものとスタックに積まれるものとがある。レジスタに設定されるものについては、利用されているレジスタを挿入関数内で破壊する場合には、破壊する前にそのレジスタの値を他の場所(例えばメインメモリのデータ領域、或いはローカル変数等の形でスタック上)に退避しておき、退避した値を対象関数の呼び出しの直前に同じレジスタに設定し直せばよい。挿入関数434には、このようなレジスタの退避と復帰のためのコードを組み込んでおく。
【0068】
また、スタックに積まれた引数の引き渡しの方法としては、図11及び図12に示すようなものがある。
【0069】
図11の例は、挿入関数のために新たにスタックを積み直す方式である。図11に示すように、挿入関数が呼び出された直後は、スタック1100の先頭部分には、呼び出し元への戻りアドレス1102と、呼び出し命令に指定された引数a1104,引数b1106,・・・及び呼び出し元の作業領域1108が格納されている。その後、挿入関数を実行して復号した対象関数を呼び出す段階で、元のスタックの内容は残したまま、スタック1100の先頭に挿入関数の作業領域1118を積み、更に引数a1104,引数b1106,・・・をコピーして引数a1114,1116,・・・として積んだところで、対象関数を呼び出すと、挿入関数への戻りアドレス1112が積まれる。このようにすることで、挿入関数から呼び出された対象関数は呼び出し元に指定された引数a,b,・・・を用いて計算を行えるようになる。なお、このようにするために、第1変換部308は、作成する挿入関数中の対象関数を呼び出す前の位置に、このようにスタック内容のコピーを行うコードを組み込んでおくことで、対象関数への引数の受け渡しが可能となる。なお、広く普及しているインテル社のPentium(登録商標)系のプロセッサでは、呼び出し命令が実行されるとスタックに戻りアドレスが自動的に積まれるので、挿入関数に組み込むコードは、挿入関数への戻りアドレス1112以外のデータを積む処理を示すコードであればよい。
【0070】
ここで、例えば、C++等のような言語では、コンパイラが、関数名に対し引数などの情報を付加した名前修飾を行うので、その修飾の情報から引数が幾つあり、各引数のデータサイズがどれだけあるかが分かるので、第1変換部308は、スタックの先頭からどこまでをコピーすればよいかが判定できる。
【0071】
図12の方式は、挿入関数のために新たなスタックを積むことはせずに、元のスタック内容を維持して挿入関数のために流用する方式である。図12の例では、挿入関数が呼び出された直後のスタック1200は、図11の場合と同様である。そして、挿入関数を実行して復号した対象関数を呼び出す段階で、呼び出し元への戻りアドレス1202を安全な退避場所1210に退避する。退避場所1210としては、例えばメインメモリのデータ領域、破壊されないことが分かっているレジスタ、あるいはメインメモリ上のデータ領域又はコード領域に用意した場所(例えば図5の固定データ508の領域と合わせて確保するなど)などを用いることができる。そして、対象関数を呼び出すことで、挿入関数への戻りアドレス1204が積まれる。そして、復号した対象関数の実行が終わって処理が挿入関数に戻ってきた時に、対象関数からの戻り値は維持したまま、処理は退避場所1210にある呼び出し元への戻りアドレス1202へとジャンプする。このジャンプは、分岐命令を用いることで実現できる。また、別の方法として、退避場所1210の戻りアドレスをスタックの先頭に積み直してから、挿入関数からの戻り命令(例えばret命令)を実行する方法もある。なお、このようにするために、第1変換部308は、作成する挿入関数中の対象関数を呼び出す命令の前に呼出元アドレス1202の退避を指示するコードを、対象関数を呼び出す命令の後ろに、退避した呼び出し元への戻りアドレスへ処理をジャンプさせるためのコードを組み込めばよい。
【0072】
また、リンカが生成する実行コード中のプログラムの関数の呼び出し構造として、一般には、関数を直接呼び出す方式と、ジャンプテーブルを介して呼び出す方式とがある。そして、これらの方式は、1つのプログラム中で混在して用いられる可能性がある。ジャンプテーブルを介する呼び出しの場合、上述の関数呼び出し命令の指す先はジャンプテーブル上の1つのジャンプ命令である。したがって、図4で説明した変換処理のように、呼び出し命令が指し示す先を暗号化するという方式では、ジャンプ命令が暗号化されることになりかねない。ところが、暗号化したいのは、ジャンプテーブルではなく、そのジャンプ先にある関数の実体(関数定義)である。そこで、「変換2」において、対象関数のアドレスを取得するときに、そのアドレスがジャンプテーブルであった場合には、ジャンプ先である関数本体のコードを見つけて暗号化する必要がある。
【0073】
このために、第2変換部312は、簡便には、図13に示すように参照先アドレス(すなわち固定データ508のところにリンカ310がセットするアドレス)の命令を調べ(S21)、その命令がジャンプ命令でなければ(S22)、その参照先アドレスが対象関数を指すものと判断し(S24)、そのアドレスを起点として暗号化を行う。これに対し、参照先アドレスの命令がジャンプ命令であれば(S22)、その命令が示すジャンプ先のアドレスが対象関数の先頭と判断し(S23)、そのアドレスを起点として暗号化を行う。この方式は、ジャンプテーブルのエントリはジャンプ命令そのものであるのに対し、関数実体の先頭にジャンプ命令が来ることは稀であるという事実に基づいている。
【0074】
ただし、関数定義の先頭にジャンプ命令が来ることは皆無とは言えない。このような稀な場合も考慮した処理方式として、例えば次のような処理方式も考えられる。すなわち、この処理方式では、第1変換部308は、ユーザが指定した対象関数の実体(例えばその関数の先頭の所定数の命令など)の一部又は全体を複写して対象関数データベースに保存しておき、これを第2変換部312が参照する。第1変換部308は、対象関数指定部306から与えられる情報からどの関数実体が保護対象かが判別でき、その関数の実体の情報を取得することができる。保存する対象関数の実体の一部は、実体の所定の位置(例えば先頭)の所定サイズのコードであってもよいし、その対象関数の実体のハッシュ値であってもよい。第2変換部312は、図14に示すように、参照先アドレスの命令を調べ(S31)、その命令が対象関数データベースに記録されているものと同じか否かを判定する(S32)。記録されていれば、その参照先アドレスが対象関数を指すものと判断し(S33)、そのアドレスを起点として暗号化を行う。記録されていなければ、その参照先アドレスの指すコードの先頭がジャンプ命令であるか否かを判定する(S34)。ここで参照先アドレスの先頭の命令がジャンプ命令であれば、その命令が示すジャンプ先のアドレスが対象関数の先頭と判断し(S35)、そのアドレスを起点として暗号化を行う。ジャンプ命令でなければ、参照先アドレスに対象関数もなければ、その対象関数に対してジャンプする命令もないので、結局、正しい対象関数が見つからないということになる。そこで、この場合は、正しい対象関数が見つからない場合の所定のエラー処理を実行する(S36)。
【0075】
以上の様々な例では、対象関数を保護する手段として暗号化を用いた。しかし、関数の保護手段は暗号化に限らない。例えば、デバッガなどのツールを用いて対象関数が解析されることを防止又は低減するための保護手段が考えられる。この保護手段としては、例えば、そのようなツールによる解析が行われていることを検知する処理と、検知した場合にはそのツールの実行を止めるなどして対象関数の解析をできなくする処理と、を記述した解析対策用の挿入関数をプログラムに組み込むことが1つの方法である。
【0076】
すなわち、この例では、対象関数の関数名を変更すると共に、その対象関数の元の関数名"funcA"を持つ図15に示すような挿入関数1500を作成する。この挿入関数1500は、上述のように、ツールによる解析されていることを検出する処理と、解析されていることを検出した場合はツールの実行を止める処理とを記述した解析対策コード1502を含む。解析されていない場合は、ツールを止める処理を行わずに解析対策コード1502の実行は終了し、対応する対象関数"funcAX"を呼び出す命令1504が実行される。挿入関す1500に付随するリロケーションテーブル1510には、命令1504が正しい呼び出し命令として機能するようにするために、そのオペランドにリンカが対象関数"funcAX"をセットするようにするためのデータエントリ1512が含まれる。このような保護をプログラムに対して施すためのシステムを、図16を参照して説明する。
【0077】
図16のシステムにおいて、コンパイラ1602及びリンカ1610は、従来からある通常のものでよい。コンパイラ1602は、ソースコード1600をオブジェクトコード1604に変換する。対象関数指定部1606は、図3のシステムの対象関数指定部306と同様の働きをし、ユーザはこの対象関数指定部1606に対し保護対象の関数を指定する。コード変換部1608は、図3における第1変換部308に類似の処理を行う手段であり、オブジェクトコード1604の中の各対象関数の関数実体の関数名を変更し、各対象関数の元の関数名を持つ挿入関数1500をオブジェクトコード1604に挿入する。リンカ1610は、挿入関数1500とオブジェクトコード1604、他のライブラリ関数などとリンクし、このときアドレス解決などの必要な処理を行う。このリンク処理により、保護済みの実行コード1614が生成される。この保護済み実行コード1614は、普通に実行されている状態であれば対象関数も実行される。これに対し、デバッガなどの解析ツールで解析を行いながら実行されている場合は、挿入関数1500がその解析の事実を検出し、例えば実行を即時停止するなど、解析ツールが対象関数のところに進めないように制御する。これにより、対象関数が解析ツールに読み込まれることを防止できる。
【0078】
以上、対象関数の保護の例として、暗号化と、デバッガによる解析に対する保護を例示したが、対象関数の保護の方法には様々なやり方があり、図15及び図16を用いて説明した方法はそれら様々なやり方に対して適用可能である。
【図面の簡単な説明】
【0079】
【図1】従来の暗号化プログラム作成システムの処理を説明するための図である。
【図2】別の従来の暗号化プログラム作成システムの処理を説明するための図である。
【図3】保護対象のコード部分を暗号化した暗号化プログラムを作成するための暗号化実行プログラム作成システムの一実施例を示す図である。
【図4】図3のシステムが行う処理の流れを模式的に示した図である。
【図5】挿入関数の内容の一例を模式的に示す図である。
【図6】第1変換部の処理手順の例を示す図である。
【図7】第2変換部の処理手順の例を示す図である。
【図8】挿入関数の内容の別の例を模式的に示す図である。
【図9】多重的な暗号化の例を説明するための図である。
【図10】多重的な暗号化の別の例を説明するための図である。
【図11】挿入関数と対象関数との間での引数の引き渡し方式の一例を説明するための図である。
【図12】挿入関数と対象関数との間での引数の引き渡し方式の別の一例を説明するための図である。
【図13】ジャンプテーブルを介した関数呼び出しを考慮した場合の「変換2」の処理手順の例を示す図である。
【図14】ジャンプテーブルを介した関数呼び出しを考慮した場合の「変換2」の処理手順の別の例を示す図である。
【図15】デバッガ等のツールによるコード解析に対する対策のための挿入関数の例を示す図である。
【図16】デバッガ等のツールによるコード解析に対する対策のための保護を施すためのシステムの例を示す図である。
【符号の説明】
【0080】
300 ソースコード、302 コンパイラ、304 オブジェクトコード、308 第1変換部、310 リンカ、312 第2変換部、314 暗号化実行コード。
【技術分野】
【0001】
本発明は、プログラム内部に含まれる保護対象の内容が読み出されないようにプログラムに部分的に保護(例えば暗号化)を加えるための技術に関する。
【背景技術】
【0002】
この種の従来技術として、特許文献1に示される技術では、概略的には、図1に示すように、ソースコード100の中の保護したい部分114の前後にマーク(又は復号のためのコード)112,116を手作業で挿入し、挿入後のソースコード110をコンパイラに渡してコンパイルさせ、その結果得られたオブジェクトコード120をリンカに渡してリンク処理を行う。そしてリンク後のオブジェクトコード130に対し暗号化ツールを適用する。暗号化ツールは、オブジェクトコード130中のマーク132,136に従い、保護したい部分134を暗号化する(これにより暗号コード144ができる)と共に、マーク132,136を復号処理のためのバイナリコード(復号コード142)に置き換えることで、最終的な実行コード140を生成する。
【0003】
また特許文献2に示される技術は、特許文献1の技術のマークの代わりに、暗号化したコードを復号する復号コードを関数の形でソースコードに挿入するものである。すなわち、この技術では、概略的には図2に示すように、ソースコード200の中の保護したい部分214の前に復号関数212を、後に暗号化部分の終わりを示す関数216を手作業で挿入し、挿入後のソースコード210をコンパイラに渡してコンパイルさせ、その結果得られたオブジェクトコード220をリンカに渡して復号関数のオブジェクトコード230等の必要なコードとリンクさせる。これにより、復号コード246を呼び出す命令242の後に保護したい部分244の平文が並んだオブジェクトコード240が生成される。そしてリンク後のオブジェクトコード240に対し暗号化ツールを適用する。暗号化ツールは、オブジェクトコード240中の保護したい部分244を暗号化する(これにより暗号コード254ができる)ことで、最終的な実行コード250を生成する。実行コードを実行した場合、命令252により復号コード256が呼び出されて実行され、これにより暗号コード254が復号され、実行される。
【0004】
【特許文献1】特許第3033562号明細書
【特許文献2】特開2005−165919号公報
【発明の開示】
【発明が解決しようとする課題】
【0005】
上記従来技術は、いずれも、実行形式のプログラムを部分的に保護するための機能を実現している。しかし、コンパイラは、一般にコード実行順序の最適化を行う。最適化によりコード各部の実行順序が変わるので、例えば暗号化対象のコード部分の中に他のコード部分が紛れ込んだり、逆に暗号化対象のコード部分の一部がその部分の外に出てしまったりすることがある。このようなことが起こると、本来暗号化されるべきでない部分が暗号化対象部分と一緒に暗号化ツールで暗号化されたり、或いは暗号化されるべき部分が暗号化の範囲から外れて暗号化されなかったりすることになり、暴走するなどして正しく動作しないプログラムとなるおそれがあった。最適化によって暗号化対象部分にそのような順序変更が生じないように注意してソースコードを作成することは必ずしも不可能ではないが、プログラマに大きな負担を強いる。
【課題を解決するための手段】
【0006】
本発明の1つの側面では、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、処理をコンピュータシステムに実行させるためのプログラム、が提供される。
【0007】
本発明の別の側面では、コンピュータシステムにより実行される方法であって、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、方法が提供される。
【0008】
本発明の更に別の側面では、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成する手段と、対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する手段と、を備える保護済み実行コード作成装置が提供される。
【発明を実施するための最良の形態】
【0009】
以下、図面を参照して、本発明の実施の形態について説明する。
【0010】
図3は、保護対象のコード部分を暗号化した暗号化プログラムを作成するための暗号化実行プログラム作成システムの一実施例を示す図である。このシステムは、コンパイラ302、対象関数指定部306、第1変換部308、リンカ310、第2変換部312を備える。これら各モジュール302、306、308、310、312は、典型的には、CPU、メモリ、固定記憶装置、表示装置、及びキーボードやマウスなどの入力装置を備えた汎用のコンピュータに対し、以下で説明する各モジュールの機能又は処理内容を記述したプログラムを実行させることにより実現される。このようなプログラムは、CDやDVDなどの可搬型の記録媒体を介して、又はネットワークを介するダウンロードにより、コンピュータにインストールすることができる。なお、それら全てのモジュールが1台のコンピュータ上に実装される必要は必ずしもなく、複数台のコンピュータに分散配置されたそれらモジュールが連携動作してこのシステムを構成してもよい。
【0011】
コンパイラ302は、処理対象のプログラムのソースコード300をコンパイルしてオブジェクトコード304を生成する。コンパイラ302としては、従来からある一般的なものを用いればよい。上述の従来技術ではソースコードに対して手作業でマークや復号関数の呼び出し命令を記述したが、図3の例ではソースコード300には手を加えない。コンパイラ302は、そのソースコード300を従来周知の方式でコンパイルする。
【0012】
対象関数指定部306は、ユーザから、ソースコード300中の保護(この例では暗号化)対象の関数の指定を受け付ける。対象関数指定部306は、例えば、ソースコード300をそのまま画面表示し、その中に含まれる各関数の近傍にそれぞれ例えばチェックボックスを配置し、ユーザがそのチェックボックスをクリック操作などで選択状態とすることにより、保護対象の関数(以下「対象関数」と呼ぶ)を選択できるようにする。なお、ソースコード300をそのまま表示する代わりに、ソースコード300中に含まれる関数を抽出し、抽出した各関数とそれに対応するチェックボックスとを画面表示し、ユーザに選択をさせてもよい。そして対象関数指定部306は、そのようなユーザインタフェース画面を介してユーザが選択した対象関数のリスト(例えば関数名を列挙したリスト)を生成し、出力する。
【0013】
また、この代わりに、対象関数の関数名のリストをユーザがテキストエディタを用いて作成し、このリストを対象関数指定部306が受け取るようにしてもよい。
【0014】
第1変換部308は、コンパイラ302が生成したオブジェクトコード304に対し、対象関数指定部306が生成する対象関数のリストを用いて変換を行う。この変換を「変換1」と呼ぶことにする。変換1では、オブジェクトコード304の中で、対象関数名(或いは当該関数を示すシンボル名)を別の名称に変更する。またこの変換1では、対象関数を適切に暗号化できるようにするため、及び暗号化されたその関数を実行時に適切に復号して実行できるようにするために、挿入関数を作成する。これら関数名の変更と挿入関数の作成については、後で詳しく説明する。
【0015】
第1変換部308は、関数名を変更したオブジェクトコードと、挿入関数とを例えば別々のファイルとして出力する。またこの代わりに、第1変換部308が、関数名を変更したオブジェクトコードのファイルに挿入関数を追加して出力してもよい。このようにして第1変換部308が出力したオブジェクトコードと挿入関数のファイル、又はそれら両者を併せたファイルは、リンカ310へと渡される。
【0016】
リンカ310は、第1変換部308から受け取ったファイル(又は複数のファイル)と、ライブラリなど他の必要な関数とをリンクして1つの実行可能プログラムファイルへとまとめる。リンカ310としては、従来からある一般的なものを用いればよい。
【0017】
第2変換部312は、リンカ310が出力した実行可能プログラムファイルを取得し、そのうちの保護対象の部分を暗号化することで、部分的に暗号化された暗号化実行コード314のファイルを生成する。この第2変換部312が行う処理(暗号化を含む)のことを、以下では「変換2」と呼ぶ。この変換2の内容については、後で詳しく説明する。
【0018】
図4は、図3のシステムが行う処理の流れを模式的に示した図である。この実施例では、ユーザが行う手作業は、保護対象のコード部分を含むソースコード400(図3のソースコード300に対応)を作成する作業と、対象関数指定部306を操作して暗号化したい関数のリスト410を作成する作業である。残りの作業は、ツール化されており、ユーザは何も行わなくてよい。
【0019】
ソースコード400はコンパイラ302によりオブジェクトコード420(図3のオブジェクトコード304に対応)に変換される。この例では、このオブジェクトコード420のうち、関数名"funcA"422で示される関数が対象関数であるとする。
【0020】
このオブジェクトコード420は、第1変換部308により「変換1」の処理を受ける。「変換1」では、対象関数の関数名が別の関数名に変更される。関数名の変更は、オブジェクトコード420内の既存の関数の関数名と重ならず、かつ他の対象関数の変更後の関数名とも重ならない名称へ変更すればよい。例えば、1つの方法として、元の関数名に対し特定の文字列(或いはデータ列)を付加することで変更後の関数名を作成してもよい。付加する文字列として、通常関数名として用いられないものや、十分に長いものなどを用いれば、この付加により他の関数名と重ならない関数名を得ることができる。図示例では、元の関数名"funcA"が、Xという文字列を付加された別の関数名"funcAX"432に変更されている。なお、「変換1」では、このように対象関数の関数定義(関数の実体)における関数名は変更されるが、その対象関数を呼び出す命令の中の関数名は変更されない。
【0021】
また「変換1」では、挿入関数434が作成される。第1変換部308は、この挿入関数434に対し、対象関数の元の関数名と同じ関数名"funcA"を与える。これにより、オブジェクトコード430中にある対象関数"funcA"を呼び出す命令は、対象関数ではなく挿入関数434を呼び出すことになる。
【0022】
図5に、「変換1」が作成する挿入関数434(図5では挿入関数500として示す)の一例を模式的に示す。
【0023】
挿入関数500の先頭には、当該関数500中に記述される復号コード510へのジャンプ命令502がまず配置される。そして、その後に、後述する「変換2」(暗号化)の処理に用いるデータ504,506及び508が配置され、更にその後に復号コード510が配置される。この復号コードの内容は、復号処理のための一以上の命令を含むが、これは固定的なものなので第2変換部312が保持していればよい。復号処理の対象となる暗号化された関数のアドレス等を示す情報は、そのアドレスが決まった後でリンカ310が埋められるよう、リロケーションテーブルにデータを設定しておけばよい(詳細は後述)。ジャンプ命令502のジャンプ先のアドレスは、間にあるデータ504〜508のサイズが既知なので、求めることができる。データ504は、「変換2」の処理でこの関数500を見つけるための特別なマーク情報であり、一般的な実行コード中には表れないデータ列を用いる。データ506は関数"funcAX"(すなわち関数名が変更された秘匿対象関数)のデータサイズを示すデータである。これは、オブジェクトコード420から求めることができる。
【0024】
また、固定データ508は、アドレス情報を格納するのに十分な大きさを持つデータ領域である。この固定データのところに、後のリンカ310の処理により、割り当てられた関数"funcAX"のアドレスが設定される。すなわち、挿入関数"funcA"は、対象関数"funcAX"を復号するためのものなので、この復号の処理や関数呼出のために関数"funcAX"のアドレスが必要になる。しかし、実行時に関数がロードされるアドレスの値は、リンカ310がリンクを行った後でないと判定できない。そこで、ここでは、リンカ310が求めた関数"funcAX"のアドレスを容れる器として、固定データ508の領域をあらかじめ確保しておくのである。
【0025】
以上に説明したデータ504〜508の後に、暗号化した対象関数を復号するための処理を記述した復号コード510が配置される。復号コード510が復号する対象となるコードの位置は、関数"funcAX"の大きさデータ506と、固定データ508の位置に後でリンカ310が書き込む関数"funcAX"の先頭アドレスを参照し、取得するように構成しておく。データ504は、暗号化(変換2)においては用いるが、暗号化したプログラムを実行する際には使用しないので、変換2において削除してかまわない。この挿入関数500の冒頭にはジャンプ命令502が置かれるのは、504から508までのデータを、命令として実行しないようにするためである。そして、復号コード510の後に、関数名を置き換えた対象関数を呼び出すためのコード512が配置される。
【0026】
なお、ジャンプ命令502やデータ506,508,コード510,512などは、マーク504の位置(アドレス)を基準にしてそれぞれ所定の関係となる位置にあればよいので、それらの並び順や順序は図示の例に限らない(ただし、復号コード510と関数呼び出し命令512の並びは、510が実行された後、512が実行されるような順番に配置する必要がある)。
【0027】
また「変換1」は、挿入関数500に付属するリロケーションテーブル520も作成する。このリロケーションテーブル520には、通常のリロケーション情報に加え、データエントリ522及び524が含まれる。データエントリ522には、挿入関数500内の固定データ508のところにリンク時に判明した関数"funcAX"のアドレスをリンカ310に挿入させるためのデータ内容が書き込まれる。また、データエントリ524には、関数"funcAX"を呼び出すための命令コード512のオペランドにリンカ310が関数"funcAX"のアドレスを書き込むようにするためのデータ内容が設定される。これらアドレスの指定は、必要に応じ、相対アドレス指定又は絶対アドレス指定のうち適切な方で行えばよい。以下に、リロケーションテーブルのデータエントリ522及び524の具体例を表で示す。
【0028】
〔表1〕
Offset Type Applied To Index Name
00000012 REL32 00000000 13 _ funcAX
00000056 REL32 00000000 13 _ funcAX
【0029】
これは、Microsoft社のVisualStudioが利用しているCOFFフォーマットでの例である。この表の1行目は、データ項目を示す見出しで、テーブルの内容情報ではない。2行目がデータエントリ522に、3行目がデータエントリ524に相当するデータである。データ項目のうち"Offset"は、アドレスを書き込む場所を、関数の先頭からのオフセット(相対位置)で表現した値である。"Type"は書き込むアドレスの種類で、上の例("REL32")は、32ビットの相対アドレスを書き込むことを示す。"Applied To"は、書き込む先のデータ(固定データ508内のデータおよび、call命令512のオペランド)を示す。これらはリロケーションテーブル内のデータではない。"Index"は、書き込むべきアドレスの対象となるデータのシンボル名のインデックス(シンボルテーブルのエントリの番号)で、この例では、関数funcAXを示す。"Name"は、"Index"が示しているシンボル(ここでは関数名)を、シンボルテーブルを参照して表示しているものであり、実際のリロケーションテーブルには存在しない。
【0030】
表1の例では、00000012は、固定データの位置が、関数の先頭から0x12バイト目にあることを示し、00000056は、call funcAX();命令のオペランドが0x56バイト目にあることを示す。また、Indexの13は、funcAXのシンボルが13のインデックス番号に割り当てられていると仮定している。このように、リロケーションテーブルのエントリは、書き込む先のオフセット、書き込むアドレスの種類、書き込むべきアドレスにあるデータのシンボル(インデックス)の三つ組みで構成される。
【0031】
この第1変換部308の行う「変換1」の処理手順の例を、図6を参照して詳細に説明する。
【0032】
まず第1変換部308は、コンパイラ302が出力したオブジェクトコード(304すなわち430)と、対象関数指定部306が作成した対象関数のリストとを入力として受け取る(S1)。次に、第1変換部308は、対象関数のリストから1つ対象関数を取り出し(S2)、関数リストの最後に到達していなければ(すなわちS3でリストから関数を取り出せれば)(S3)、ステップS4に進む。
【0033】
ステップS4では、オブジェクトコード304をスキャンして、ステップS2で取り出した対象関数を検出する。より詳細には、オブジェクトコード304中のシンボルテーブルの中から、その対象関数の関数名に対応するシンボルを検出し、このシンボルに対応するオブジェクトファイル内のコード位置をシンボルテーブルから読み出す。このコード位置は、例えば、オブジェクトファイル内のセクション番号とそのセクションの先頭からのオフセットの組により表現される。これにより、対象関数が検出できる。
【0034】
次に第1変換部308は、ステップS5でその対象関数の大きさ(データサイズ)を求める。そして、ステップS6では、その対象関数の関数名を他と重ならない別の関数名に変更する。すなわち、特定の文字列を追加するなどにより変更した関数名のシンボルをシンボルテーブルに追加し、その関数の関数定義の指し示すシンボル名がその新たに追加したシンボル名となるようにする。
【0035】
次に第1変換部308は、ステップS7で、その対象関数の元の関数名を持つ挿入関数500をオブジェクトコード304に挿入する。すなわち、対象関数の元の関数名を示すシンボル名を関数名とする新たな関数(挿入関数500)の関数定義を追加する。ここで、挿入関数500のうち対象関数に依存する部分は、対象関数の大きさのデータ506だけであり、これはステップS5で求められているので、挿入関数500は作成できる。そしてステップS8では、挿入関数500の所定の位置に、リンカ310が対象関数のアドレスを設定することができるようにするために、リロケーションテーブルのデータエントリ522及び524を追加する。そしてステップS2に戻る。
【0036】
対象関数のリストに載っている全ての関数について処理が終わるまで、ステップS2〜S8の処理を繰り返す。リストの最後に到達すると(S3)、変換1の処理が完了し、第1変換部308は変換結果のデータをオブジェクトコードのフォーマットに従ったデータ(オブジェクトコード430)として出力する(S9)。これにより、「変換1」の処理が終了する。
【0037】
図4の説明に戻ると、「変換1」により生成されたオブジェクトコード430は、リンカ310により他の必要な関数とリンクされる。リンカ310の処理により、関数"funcAX"のアドレスが決定され、そのアドレスが固定データ508のところに設定され、更にそのアドレスが呼び出し命令コード512のオペランドに設定される。リンカ310が出力する実行コード440には、挿入関数500の挿入コードを呼び出す命令442の後に対象関数のコード444が平文の機械語で記述され、その後に挿入関数434の挿入コード446が来る。なお、呼び出し命令442の後に対象関数のコード444が配置されると行ったのはあくまで一例に過ぎない。実際には、コードの実行順序はリンカが適切に決定するので、呼び出し命令442と対象関数のコード444との並び順はどのような順序でもよい。
【0038】
この実行コード440が、第2変換部312に渡される。第2変換部312は、その実行コード440中の挿入コード446のデータに基づき保護対象のコード444の範囲を特定し、そのコード444を暗号化する。この処理の手順を、図7を参照して説明する。
【0039】
この手順では、第2変換部312はまずリンカ310の出力した平文の実行コード440を入力として受け取る(S11)。次に、「変換1」で埋め込んだマーク504をキーとしてその実行コード440を検索することで、挿入関数500を検出する(S12)。実行コード440の末尾に達しないうちに挿入関数500が見つかれば(S13)、マーク504を基準として、データ506及び508のアドレスを特定し、それら各アドレスから、その挿入関数500に対応する対象関数のサイズ(データ506)とアドレス(データ508)を取得する(S14)。そして、第2変換部312は、検出したマーク504を削除するために、マーク504のところに別のデータ列を上書きする(S15)。これは、暗号化された実行コード450が解析された時に、マーク504が解析の手がかりとなることを防ぐためである。実行コード中の各マークの位置を例えば乱数のように予測のつきにくいそれぞれ互いに異なるデータ列で上書きすれば、マークが存在したことを隠蔽できる。そして、第2変換部312は、実行コード440のうち、ステップS14で取得したアドレス及びサイズが示す範囲(すなわち対象関数のコード部分)を所定の暗号アルゴリズムにより暗号化する(S16)。この後、ステップS12に戻り、実行コード440の最後に達するまで、ステップS12〜S13の処理を繰り返す。ステップS13で実行コード440の最後まで達したと判定されると、その時点で作成されている実行コード450を出力する(S17)。
【0040】
第2変換部312の処理により生成される実行コード450の中には、復号コードの呼び出し命令452と、暗号化された対象関数のコード454とが配置され、その後に復号コード456が、そしてその後に暗号化された対象関数のコード454を呼び出す命令が配置される。ここで、呼び出し命令452とコード454の並び順は、図示の順序に限らず、どのような順序でもよい。この実行コード450をコンピュータシステムで実行すれば、関数"funcA"の呼び出しによりまず復号コード456が呼び出され、その実行の後に暗号化された対象関数のコード454が呼び出されることになる。これにより、暗号化されたコード454が復号され、実行されることになる。
【0041】
以上に説明した例によれば、暗号化対象が関数単位で指定され、関数単位で暗号化が行われるので、従来技術のように暗号化対象のコードの中に別のコードが紛れ込んで暗号化されるなどのような不具合を大幅に低減できる。また、特許文献1では、復号コードやマークなどをソースに挿入するために、プログラム開発環境にインラインアセンブラの機能が必要だが、この実施例では、対象関数の指定をすればよく、そのためのツールとして対象関数指定部306が用意されているので、インラインアセンブラのない環境にも対応できる。また、この例では、ソースコード自体は変更しないので、ソースコードのメンテナンス性が向上するというメリットも得られる。
【0042】
また、1プログラム中の複数の関数を保護する場合、第1変換部308又は第2変換部312で挿入する復号コードを、各対象関数ごとに互いに異なるコード内容とすることも好適である、例えば、同じ復号アルゴリズムを別のコード内容で表現した複数の復号コードを用いてもよいし、異なる暗号アルゴリズムに対応した複数の復号コードを用いてもよい。後者の場合、第1変換部308で復号コードを挿入する構成では、第2変換部312が各復号コードに対応した部分を正しく暗号化するための処理が必要である。例えば、第1変換部308で異なる復号コードを予め定めた順序で適用するようにし、第2変換部312ではその順序に従って各復号コードに対応する暗号アルゴリズムを適用したり、又は第1変換部308でどの暗号アルゴリズムに対応する復号コード化を示すデータを挿入関数中に書き込み、それを第2変換部312が解釈して適切な暗号アルゴリズムを適用したりする方法を用いることができる。
【0043】
また、挿入関数500内において、対象関数の呼び出し命令512の後に、対象関数を再暗号化するためのコードを追加することも好適である。このようにすることで、暗号化実行コードの実行時に復号された対象関数が実行された後、挿入関数500に処理が戻り、実行された対象関数の再暗号化が行われる。これにより、実行後にメインメモリ上に対象関数が残る場合にも、その内容を秘匿することができる。なお、再暗号化のコードには、メモリアドレス上のどの範囲を暗号化するかを示す情報が必要であるが、これは対象関数の大きさデータ506やアドレスデータ(固定データ508のところにリンカ310が書き込むデータ)等の情報を用いて、リンカ310が解決することができる。
【0044】
次に、図8を参照して、「変換1」がオブジェクトコード304に挿入する挿入関数の別の例を説明する。
【0045】
挿入関数800のうちマーク802、データ806及び808は、図5の挿入関数500におけるマーク504、データ506及び508とそれぞれ同じものでよい。また、リロケーションテーブル820に追加するデータエントリ822及び824も、図5のリロケーションテーブル520内のデータエントリ522及び524と同じものでよい。図5の挿入関数と500と異なる点は、挿入関数800にこの挿入関数800自身の大きさを示すデータ804が含まれることと、復号コード510の代わりに、後でその復号コードを挿入するためのエリア810が確保されているところである。
【0046】
挿入関数800自身の大きさのデータ804は、この挿入関数800自体も一部暗号化して保護する場合に利用できる。すなわち、復号コードなど挿入関数800内に含まれるデータ内容が解析されると、暗号化したコードの安全性が脅かされるので、挿入関数のうち平文である必要がある部分(例えばこのデータ804及び暗号化した復号コードを復号するコード)以外を暗号化することが考えられる。すなわちこの場合、対象関数を復号する本来の復号コード(第1復号コードと呼ぶ)と、その復号コードを暗号化したものを復号するための復号コード(第2復号コードと呼ぶ)が必要である。この場合、例えば、第2復号コード、第1復号コードを暗号化したもの、の順にコードを配列する。また、この場合、挿入関数の末尾がどこか分からないと実行時にどこまでを復号化したらよいか分からないが、このデータ804を用いれば末尾の位置を求められる。
【0047】
また、エリア810には、後の「変換2」の処理の中で復号コード(及び復号した対象関数を呼び出すコード)を挿入する。このように、復号コード等を「変換2」で挿入する構成とすることで、復号コードが平文状態で人の目に入る可能性を低減できるので、暗号化したコードの安全性を向上させることができる。
【0048】
また、このように挿入した復号コード等の部分を「変換2」の処理で暗号化することで、復号コードを保護することができ、ひいては対象関数の安全性の向上も図れる。
【0049】
なお、「変換1」でエリア810を確保するだけで、復号コード等の暗号化は行わない構成でも、復号コードの保護効果はある程度得られる。
【0050】
次に、対象関数に対して暗号化を多重的に施すことで、暗号強度を高める例について説明する。
【0051】
図9には、1重の暗号化処理ごとに、復号のための関数を別関数として挿入する方式の例を模式的に示す。この例では、実行コード900の中の対象関数"funcA()"を3重に暗号化している。この例では、暗号化が1重増えるごとに、関数名の後ろに所定の文字列(この例では"X")を1つずつ足していくという規則性に従い、関数名を変更している。すなわち、この例では3重の暗号化を施すので、対象関数名は"funcAXXX"(関数904)と変更されている。3重の暗号化のうちの外側の暗号化を解くための復号関数908が、元の対象関数と同じ関数名"funcA"を受け継ぐ。この関数908は、外側の暗号化に対応する復号コード910と、中間の暗号化を解くための復号関数914"funcAX"を呼び出す命令912とを含む。中間の復号関数914は、中間の暗号化を解く復号コード916と内側の復号関数920"funcAXX"を呼び出す命令918とを含む。内側の復号関数920は、内側の暗号化を解くための復号コード922と、対象関数904"funcAXXX"を呼び出す命令924とを含む。ここで、復号コード910,916及び922は、互いに異なるコード内容とすることが、暗号破りを難しくするという観点から見て好適である。これは、同じ復号アルゴリズムを別のコード内容で表現したものでもよい(この場合、内側、中間、外側の暗号化アルゴリズムは同じ)。また、内側、中間、外側の暗号化アルゴリズムを異ならせ、各復号コード910,916及び922をそれに応じて異なったものとしてもよい。
【0052】
対象関数の関数名の変更規則や、各段階の復号関数の命名規則は、例示したものに限らない。実行コード中で一意に区別でき、かつ対象関数の呼び出しにより最外側の復号関数が呼び出され、最内側の復号関数の中から名称変更後の対象関数が呼び出されるようになるならば、どのような規則で関数名を決めてもよい。
【0053】
このような実行コード900を作成するため、第1変換部308は、オブジェクトコード中の対象関数の関数定義の冒頭にある関数名を規則に従って変更すると共に、外側、中間、内側の復号関数を作成する。図示は省略したが、各復号関数には図5に示したようなマーク504や大きさデータ506、固定データ508、リロケーションテーブルのエントリ522,524が含まれる。第1変換部308が追加するリロケーションテーブルのデータエントリには、変換により追加される各関数名"funcAX"、"funcAXX"及び"funcAXXX"についてリンカ310で決定される各アドレスが、それぞれオブジェクトコード内の必要な箇所(図5の例で言えば固定データ508や呼び出し命令510のオペランド)に設定されるようにするためのデータが含まれる。関数名が変更されたオブジェクトコードと、外側、中間、及び内側の復号関数とは、リンカ310により1つの実行コードへと結合され、このとき、各関数"funcAX"、"funcAXX"及び"funcAXXX"についてのアドレス解決が行われる。
【0054】
第2変換部312は、リンカ310の出力した実行コードから復号関数908,914,920を検出し、それら関数間の呼び出し関係から復号関数の順序(内側、中間、外側)を特定すると共に、保護対象のコード906の範囲を特定する。そして、内側から順に暗号化を行う。内側の暗号化は、保護対象のコード906と、対象関数904を呼び出す命令924に対して施す。命令924は定型的なものであり、第1変換部308が作成するのでサイズや位置は分かっている。または、図5の例と同様、コード922内に、対象関数904の位置と関数920のサイズとが含まれるので、それらの情報から暗号化に必要な情報を得ることもできる。したがって、第2変換部312は命令924の位置及びサイズの示す範囲を暗号化すればよい。中間の暗号化は、保護対象のコード906(ただし内側の暗号化を受けたもの)と、内側の復号関数920を呼び出す命令918及び内側の復号関数920とに対して施す。命令918及び内側の復号関数920も第1変換部308が作成するため位置及びサイズが既知なので、暗号化できる。外側の暗号化は、保護対象のコード906(ただし内側及び中間の暗号化を受けたもの)と、中間側の復号関数914を呼び出す命令912と、中間及び内側の復号関数914及び920とに対して施す。この処理により作成される実行コード900では、外側の暗号化に対応する復号コード910は平文であるが、中間及び内側の暗号化に対応する復号コード916,918は暗号化されている。また保護対象のコード906は3重に暗号化されている。
【0055】
このように対象関数904が多重的に暗号化された実行コード900をコンピュータシステムにて実行した場合、呼び出し命令902によりまず外側の復号関数908が呼び出されて外側の暗号が解かれ、これにより中間の暗号化の復号コード916が平文になる。次に、中間の復号関数920が呼び出され、平文の復号コード916が実行されることで、中間の暗号が解かれる。そして同様にして内側の暗号が解かれることで、保護対象のコード906が平文となり、命令924によりそのコード906が呼び出されて実行される。
【0056】
多重暗号化の別の例を、図10を参照して説明する。この例では、1つの復号関数(挿入関数)1008内に多重に外側用、中間用、及び内側用の復号コード1010、1012、及び1014をその順に組み込んでいる。保護対象のコード1006を含んだ対象関数1004は、元の関数名"funcA"とは異なる関数名"funcAX"に変更され、復号関数1008には対象関数1004の元の関数名"funcA"が与えられている。復号コード1010〜1014のコード内容やサイズは第1変換部308が知っている(あるいは図5の例の方式と同様にして各復号コード内に書き込まれた情報から求めることができる)ので、第1変換部308は内側の復号コード1014が中間の暗号化で、中間の復号コード1012が外側の暗号化で、それぞれ暗号化されるように、オブジェクトコードに組み込むことができる。第2変換部312は、保護対象のコード1006及び対象関数1004を呼び出す命令1016を内側の暗号化処理で暗号化し、その暗号化結果と内側用の復号コード1014とを中間の暗号化処理で暗号化し、その暗号化結果と中間の復号コードとを外側の暗号化処理で暗号化する。
【0057】
このような処理で作成された実行コード1000をコンピュータシステムが実行した場合、対象関数1004を呼び出す命令1002により復号関数1008が呼び出され、まず外側の復号コード1010が実行されることで外側の暗号化が解かれ、これによって平文となった中間の復号コード1012が実行されることで中間の暗号化が解かれる。そして、その結果平文となった内側の復号コード1014が実行されることで内側の暗号化が解かれ、命令1016と保護対象コード1006が平文となる。この後、命令1016が実行されることにより、保護対象コード1006が呼び出されて実行される。
【0058】
図9及び図10の例に示したように、復号コードを複数用意し、内側の復号コードから順に、各復号コードに対応する暗号化により順に他の復号コードを入れ子式に暗号化していくことにより、対象関数を復号するためのコードの多くの部分を暗号化することができる。これにより、解析に対しより耐性の高い保護が実現できる。
【0059】
図9及び図10の例では、保護対象のコード906及び1006に対し、内側、中間、外側の暗号化を順に施したが、これに限らず、保護対象のコードには内側の暗号化のみを施し、その内側の暗号化を解除するための復号コードを中間及び外側の暗号化で保護するようにしてもよい。
【0060】
また、以上の例ではユーザの指定に応じて対象関数指定部が対象関数のリストを作成し、このリストに基づき第1変換部308が対象関数の関数名を変更した。ただし、これは必須のことではない。この代わりに、ユーザ(プログラマ)が、ソースコード中の対象関数名を、所定の修飾の付加により変更する方式もある。この方式では、ユーザが、エディタなどを用い、ソースコードの中で保護対象とする関数の関数定義の関数名に対し所定の規則に従った修飾を付加する。例えば"funcA"なる関数名の後に、あらかじめ定めた"_x"なる文字列を付加して"funcA_x"と変更するなどである。
【0061】
ただし、変更した関数名がプログラム内で一意になるようにするには、人間にとっては覚えにくく、入力しにくく、また後で読んで認識しにくいような、長く複雑な修飾文字列を付加する必要が出てくることも考えられる。そこで、関数名の変更作業を支援するために、ソースコードを前処理するプリプロセッサのマクロ機能を用いることも好適である。すなわち、この場合、人間にとって分かりやすく比較的入力しやすい修飾を、コンピュータにとって識別しやすく一意性が得られる確率の高い修飾に置換するためのマクロをユーザが作成してソースコードに追加する。そして、ユーザは、エディタ等を用いてソースコード中の対象関数の定義の関数名に人間用の修飾を付加する。この修飾付加済みのソースコードをプリプロセッサに処理させれば、対象関数の定義の関数名をコンピュータ用の修飾付きのものに変更することができる。このとき、仮に修飾を付けて変更した関数名が他の関数の関数名と重複してしまった場合は、プリプロセッサがその重複の事実を検出して警告を発するので、これに応じユーザは対象関数の関数名に与える人間用修飾を別のものに変更するなどの対処ができる。また、この例のようにマクロで修飾を与える場合、マクロを削除又は変更するだけで、それまでの修飾を解除することができる。したがって、複数の関数を保護対象に指定する場合に、保護の有効化/無効化の切り換え作業が容易になるという利点もある。
【0062】
この場合、図3のシステムでは、対象関数指定部306が不要となる。第1変換部308は、挿入関数の作成は行うが、関数名の変更処理は行う必要がない。挿入関数の作成に当たり、第1変換部308は、オブジェクトコード304のなかから、対象関数に対応する所定の修飾(コンピュータ用修飾)を持った関数の定義を見つけ出し、その関数定義の関数名からその修飾を削除したものを挿入関数の関数名とする。挿入関数の内容は上述の例と同様でよい。リンカ310及び第2変換部312は図3の例と同様のものでよい。
【0063】
このように、ソースコード上でプログラマ自身が対象関数の関数名を変更するようにすれば、暗号化の指定の有効化及び解除が容易に切り換えられ、デバッグやソースコードの変更、メンテナンスのしやすさを維持したまま関数名の修飾ができる。また、図3の例では、第1変換部308が対象関数の関数名を自動的に変更するので、プログラマが予期しない副作用が生じる可能性があるが、プログラマ自身が必要な関数名を変更する方式ならば、予期しない副作用のリスクは低減できる。
【0064】
なお、ソースコード中の対象関数の関数名をユーザが変更する方式は、ソースコードをユーザが改変するという点で従来技術と一致しているが、次のような相違がある。すなわち、従来技術ではソースコード中の関数の中に復号コードや復号関数を挿入するなど、関数の内部に対して改変を行っていたため、コンパイラの最適化によりコードの実行順序に予期せぬ変更が加えられ、想定する動作と異なった動作をする場合があった。これに対し、本方式では、関数定義の関数名しか変更しないので、そのような不具合は生じにくい。
【0065】
次に、図3、図4の装置により生成された暗号化実行コード314をコンピュータシステム上で実行する場合における、挿入関数434から暗号化した対象関数432を呼び出す際の関数の引数の引き渡しについて説明する。
【0066】
図3、図4の装置では、元々対象関数432を呼び出していた呼び出し命令430により挿入関数434が呼び出される。このため、呼び出し命令430に指定された関数の引数は、挿入関数434に渡されることになる。これら引数は、挿入関数434を実行して暗号化した対象関数432を復号した後、復号された対象関数432に正しく引き渡される必要がある。
【0067】
引数には、レジスタに設定されるものとスタックに積まれるものとがある。レジスタに設定されるものについては、利用されているレジスタを挿入関数内で破壊する場合には、破壊する前にそのレジスタの値を他の場所(例えばメインメモリのデータ領域、或いはローカル変数等の形でスタック上)に退避しておき、退避した値を対象関数の呼び出しの直前に同じレジスタに設定し直せばよい。挿入関数434には、このようなレジスタの退避と復帰のためのコードを組み込んでおく。
【0068】
また、スタックに積まれた引数の引き渡しの方法としては、図11及び図12に示すようなものがある。
【0069】
図11の例は、挿入関数のために新たにスタックを積み直す方式である。図11に示すように、挿入関数が呼び出された直後は、スタック1100の先頭部分には、呼び出し元への戻りアドレス1102と、呼び出し命令に指定された引数a1104,引数b1106,・・・及び呼び出し元の作業領域1108が格納されている。その後、挿入関数を実行して復号した対象関数を呼び出す段階で、元のスタックの内容は残したまま、スタック1100の先頭に挿入関数の作業領域1118を積み、更に引数a1104,引数b1106,・・・をコピーして引数a1114,1116,・・・として積んだところで、対象関数を呼び出すと、挿入関数への戻りアドレス1112が積まれる。このようにすることで、挿入関数から呼び出された対象関数は呼び出し元に指定された引数a,b,・・・を用いて計算を行えるようになる。なお、このようにするために、第1変換部308は、作成する挿入関数中の対象関数を呼び出す前の位置に、このようにスタック内容のコピーを行うコードを組み込んでおくことで、対象関数への引数の受け渡しが可能となる。なお、広く普及しているインテル社のPentium(登録商標)系のプロセッサでは、呼び出し命令が実行されるとスタックに戻りアドレスが自動的に積まれるので、挿入関数に組み込むコードは、挿入関数への戻りアドレス1112以外のデータを積む処理を示すコードであればよい。
【0070】
ここで、例えば、C++等のような言語では、コンパイラが、関数名に対し引数などの情報を付加した名前修飾を行うので、その修飾の情報から引数が幾つあり、各引数のデータサイズがどれだけあるかが分かるので、第1変換部308は、スタックの先頭からどこまでをコピーすればよいかが判定できる。
【0071】
図12の方式は、挿入関数のために新たなスタックを積むことはせずに、元のスタック内容を維持して挿入関数のために流用する方式である。図12の例では、挿入関数が呼び出された直後のスタック1200は、図11の場合と同様である。そして、挿入関数を実行して復号した対象関数を呼び出す段階で、呼び出し元への戻りアドレス1202を安全な退避場所1210に退避する。退避場所1210としては、例えばメインメモリのデータ領域、破壊されないことが分かっているレジスタ、あるいはメインメモリ上のデータ領域又はコード領域に用意した場所(例えば図5の固定データ508の領域と合わせて確保するなど)などを用いることができる。そして、対象関数を呼び出すことで、挿入関数への戻りアドレス1204が積まれる。そして、復号した対象関数の実行が終わって処理が挿入関数に戻ってきた時に、対象関数からの戻り値は維持したまま、処理は退避場所1210にある呼び出し元への戻りアドレス1202へとジャンプする。このジャンプは、分岐命令を用いることで実現できる。また、別の方法として、退避場所1210の戻りアドレスをスタックの先頭に積み直してから、挿入関数からの戻り命令(例えばret命令)を実行する方法もある。なお、このようにするために、第1変換部308は、作成する挿入関数中の対象関数を呼び出す命令の前に呼出元アドレス1202の退避を指示するコードを、対象関数を呼び出す命令の後ろに、退避した呼び出し元への戻りアドレスへ処理をジャンプさせるためのコードを組み込めばよい。
【0072】
また、リンカが生成する実行コード中のプログラムの関数の呼び出し構造として、一般には、関数を直接呼び出す方式と、ジャンプテーブルを介して呼び出す方式とがある。そして、これらの方式は、1つのプログラム中で混在して用いられる可能性がある。ジャンプテーブルを介する呼び出しの場合、上述の関数呼び出し命令の指す先はジャンプテーブル上の1つのジャンプ命令である。したがって、図4で説明した変換処理のように、呼び出し命令が指し示す先を暗号化するという方式では、ジャンプ命令が暗号化されることになりかねない。ところが、暗号化したいのは、ジャンプテーブルではなく、そのジャンプ先にある関数の実体(関数定義)である。そこで、「変換2」において、対象関数のアドレスを取得するときに、そのアドレスがジャンプテーブルであった場合には、ジャンプ先である関数本体のコードを見つけて暗号化する必要がある。
【0073】
このために、第2変換部312は、簡便には、図13に示すように参照先アドレス(すなわち固定データ508のところにリンカ310がセットするアドレス)の命令を調べ(S21)、その命令がジャンプ命令でなければ(S22)、その参照先アドレスが対象関数を指すものと判断し(S24)、そのアドレスを起点として暗号化を行う。これに対し、参照先アドレスの命令がジャンプ命令であれば(S22)、その命令が示すジャンプ先のアドレスが対象関数の先頭と判断し(S23)、そのアドレスを起点として暗号化を行う。この方式は、ジャンプテーブルのエントリはジャンプ命令そのものであるのに対し、関数実体の先頭にジャンプ命令が来ることは稀であるという事実に基づいている。
【0074】
ただし、関数定義の先頭にジャンプ命令が来ることは皆無とは言えない。このような稀な場合も考慮した処理方式として、例えば次のような処理方式も考えられる。すなわち、この処理方式では、第1変換部308は、ユーザが指定した対象関数の実体(例えばその関数の先頭の所定数の命令など)の一部又は全体を複写して対象関数データベースに保存しておき、これを第2変換部312が参照する。第1変換部308は、対象関数指定部306から与えられる情報からどの関数実体が保護対象かが判別でき、その関数の実体の情報を取得することができる。保存する対象関数の実体の一部は、実体の所定の位置(例えば先頭)の所定サイズのコードであってもよいし、その対象関数の実体のハッシュ値であってもよい。第2変換部312は、図14に示すように、参照先アドレスの命令を調べ(S31)、その命令が対象関数データベースに記録されているものと同じか否かを判定する(S32)。記録されていれば、その参照先アドレスが対象関数を指すものと判断し(S33)、そのアドレスを起点として暗号化を行う。記録されていなければ、その参照先アドレスの指すコードの先頭がジャンプ命令であるか否かを判定する(S34)。ここで参照先アドレスの先頭の命令がジャンプ命令であれば、その命令が示すジャンプ先のアドレスが対象関数の先頭と判断し(S35)、そのアドレスを起点として暗号化を行う。ジャンプ命令でなければ、参照先アドレスに対象関数もなければ、その対象関数に対してジャンプする命令もないので、結局、正しい対象関数が見つからないということになる。そこで、この場合は、正しい対象関数が見つからない場合の所定のエラー処理を実行する(S36)。
【0075】
以上の様々な例では、対象関数を保護する手段として暗号化を用いた。しかし、関数の保護手段は暗号化に限らない。例えば、デバッガなどのツールを用いて対象関数が解析されることを防止又は低減するための保護手段が考えられる。この保護手段としては、例えば、そのようなツールによる解析が行われていることを検知する処理と、検知した場合にはそのツールの実行を止めるなどして対象関数の解析をできなくする処理と、を記述した解析対策用の挿入関数をプログラムに組み込むことが1つの方法である。
【0076】
すなわち、この例では、対象関数の関数名を変更すると共に、その対象関数の元の関数名"funcA"を持つ図15に示すような挿入関数1500を作成する。この挿入関数1500は、上述のように、ツールによる解析されていることを検出する処理と、解析されていることを検出した場合はツールの実行を止める処理とを記述した解析対策コード1502を含む。解析されていない場合は、ツールを止める処理を行わずに解析対策コード1502の実行は終了し、対応する対象関数"funcAX"を呼び出す命令1504が実行される。挿入関す1500に付随するリロケーションテーブル1510には、命令1504が正しい呼び出し命令として機能するようにするために、そのオペランドにリンカが対象関数"funcAX"をセットするようにするためのデータエントリ1512が含まれる。このような保護をプログラムに対して施すためのシステムを、図16を参照して説明する。
【0077】
図16のシステムにおいて、コンパイラ1602及びリンカ1610は、従来からある通常のものでよい。コンパイラ1602は、ソースコード1600をオブジェクトコード1604に変換する。対象関数指定部1606は、図3のシステムの対象関数指定部306と同様の働きをし、ユーザはこの対象関数指定部1606に対し保護対象の関数を指定する。コード変換部1608は、図3における第1変換部308に類似の処理を行う手段であり、オブジェクトコード1604の中の各対象関数の関数実体の関数名を変更し、各対象関数の元の関数名を持つ挿入関数1500をオブジェクトコード1604に挿入する。リンカ1610は、挿入関数1500とオブジェクトコード1604、他のライブラリ関数などとリンクし、このときアドレス解決などの必要な処理を行う。このリンク処理により、保護済みの実行コード1614が生成される。この保護済み実行コード1614は、普通に実行されている状態であれば対象関数も実行される。これに対し、デバッガなどの解析ツールで解析を行いながら実行されている場合は、挿入関数1500がその解析の事実を検出し、例えば実行を即時停止するなど、解析ツールが対象関数のところに進めないように制御する。これにより、対象関数が解析ツールに読み込まれることを防止できる。
【0078】
以上、対象関数の保護の例として、暗号化と、デバッガによる解析に対する保護を例示したが、対象関数の保護の方法には様々なやり方があり、図15及び図16を用いて説明した方法はそれら様々なやり方に対して適用可能である。
【図面の簡単な説明】
【0079】
【図1】従来の暗号化プログラム作成システムの処理を説明するための図である。
【図2】別の従来の暗号化プログラム作成システムの処理を説明するための図である。
【図3】保護対象のコード部分を暗号化した暗号化プログラムを作成するための暗号化実行プログラム作成システムの一実施例を示す図である。
【図4】図3のシステムが行う処理の流れを模式的に示した図である。
【図5】挿入関数の内容の一例を模式的に示す図である。
【図6】第1変換部の処理手順の例を示す図である。
【図7】第2変換部の処理手順の例を示す図である。
【図8】挿入関数の内容の別の例を模式的に示す図である。
【図9】多重的な暗号化の例を説明するための図である。
【図10】多重的な暗号化の別の例を説明するための図である。
【図11】挿入関数と対象関数との間での引数の引き渡し方式の一例を説明するための図である。
【図12】挿入関数と対象関数との間での引数の引き渡し方式の別の一例を説明するための図である。
【図13】ジャンプテーブルを介した関数呼び出しを考慮した場合の「変換2」の処理手順の例を示す図である。
【図14】ジャンプテーブルを介した関数呼び出しを考慮した場合の「変換2」の処理手順の別の例を示す図である。
【図15】デバッガ等のツールによるコード解析に対する対策のための挿入関数の例を示す図である。
【図16】デバッガ等のツールによるコード解析に対する対策のための保護を施すためのシステムの例を示す図である。
【符号の説明】
【0080】
300 ソースコード、302 コンパイラ、304 オブジェクトコード、308 第1変換部、310 リンカ、312 第2変換部、314 暗号化実行コード。
【特許請求の範囲】
【請求項1】
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、
対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、
処理をコンピュータシステムに実行させるためのプログラム。
【請求項2】
請求項1記載のプログラムであって、
前記挿入関数は、前記保護に関連する処理として暗号化された対象関数を復号する処理を示す復号コードを含み、
前記保護済み実行コードの生成は、前記対象関数を暗号化する処理を含む、
ことを特徴とするプログラム。
【請求項3】
請求項2記載のプログラムであって、
前記保護済み実行コードを生成する処理は、
前記対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、をリンカにリンクさせる処理と、
該リンカが出力する実行コードのうちの対象関数を暗号化することで保護済み実行コードを生成する処理と、
を含むことを特徴とするプログラム。
【請求項4】
請求項2記載のプログラムであって、
前記保護済み実行コードを生成する処理は、
前記挿入関数から前記復号コードを除きその代わりに後で復号コードを挿入する予約領域が設けられたものと、前記対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、をリンカにリンクさせる処理と、
該リンカが出力する実行コードのうちの前記予約領域に前記復号コードを挿入すると共に、該実行コード内の対象関数を暗号化することで保護済み実行コードを生成する処理と、
を含むことを特徴とするプログラム。
【請求項5】
請求項3又は4に記載のプログラムであって、
前記挿入関数は、
固定データと、
前記固定データの場所に対して対応する対象関数のアドレスを書き込む処理を前記リンカに実行させるための第1のリロケーション情報と、
を含むことを特徴とするプログラム。
【請求項6】
請求項3又は4に記載のプログラムであって、
前記挿入関数は、
前記呼び出し命令のオペランドに対して対応する対象関数のアドレスを書き込む処理を前記リンカに実行させるための第2のリロケーション情報、
を含むことを特徴とするプログラム。
【請求項7】
請求項2記載のプログラムであって、
前記挿入関数は、前記対象関数を暗号化する処理において当該挿入関数を見つけるためのマーク情報を含む、
ことを特徴とするプログラム。
【請求項8】
請求項2記載のプログラムであって、
前記挿入関数は、対応する対象関数の大きさを示すデータを含む、
ことを特徴とするプログラム。
【請求項9】
請求項2記載のプログラムであって、
前記復号コードは、各々が対応する暗号化を解く複数のサブ復号コードを含み、
前記対象関数を暗号化する処理では、それらサブ復号コードのうちの少なくとも1つに対応する暗号化処理により前記対象関数を暗号化すると共に、前記対象関数の暗号化処理に対応するサブ復号コードを他のサブ復号コードにより多重的に暗号化する、
ことを特徴とするプログラム。
【請求項10】
請求項2記載のプログラムであって、
複数の異なる復号コードを備え、異なる対象関数に対して異なる復号コードを挿入する、
ことを特徴とするプログラム。
【請求項11】
請求項10記載のプログラムであって、
前記複数の異なる復号コードは、それぞれ異なる暗号アルゴリズムに対応し、
前記暗号化実行プログラムを作成する処理では、挿入された復号コードに対応する暗号アルゴリズムを用いて、該復号コードに対応する対象関数を暗号化する、
ことを特徴とするプログラム。
【請求項12】
請求項2記載のプログラムであって、
前記挿入関数は、前記呼び出し命令の後に、前記対象関数を再暗号化するためのコードを更に備える、ことを特徴とするプログラム。
【請求項13】
請求項1記載のプログラムであって、
前記挿入関数は、
該挿入関数内で破壊するレジスタの値を該破壊を伴う処理が実行される前に所定の退避領域に退避するためのコードと、
前記保護に関連する処理の後前記対象関数を呼び出す前に、前記退避領域に退避していた値を前記レジスタに書き戻すためのコードと、
を含むことを特徴とするプログラム。
【請求項14】
請求項1記載のプログラムであって、
前記挿入関数は、
前記保護に関連する処理の後前記対象関数を呼び出す前に、該挿入関数を呼び出した命令の実行により積まれたスタックから引数をコピーして新たにスタックに積み、該挿入関数への戻りアドレスを新たにスタックに積むためのコード、
を含むことを特徴とするプログラム。
【請求項15】
請求項1記載のプログラムであって、
前記挿入関数は、
前記保護に関連する処理の後前記対象関数を呼び出す前に、該挿入関数の呼び出し元への戻りアドレスを所定の退避領域に退避するためのコードと、
前記保護に関連する処理の後に前記対象関数の実行が終わり、処理が前記挿入関数に戻ってきた後で、前記退避領域に退避していた戻りアドレスに処理を戻すためのコードと、
を含むことを特徴とするプログラム。
【請求項16】
請求項1記載のプログラムであって、
対象関数の指定をユーザから受け付け、
オブジェクトコードのうち対象関数として指定されたものの関数定義の関数名を、所定の規則に従って第2の関数名に変更する、
処理を更に前記コンピュータシステムに実行させることにより、前記対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードを生成する、ことを特徴とするプログラム。
【請求項17】
請求項1記載のプログラムであって、
前記挿入関数は、前記保護に関連する処理として、前記保護済み実行コードがツールにより解析されていることを検知する処理と、解析を検知した場合に前記対象関数の解析を阻止する処理と、を示すコードを含む、
ことを特徴とするプログラム。
【請求項18】
コンピュータシステムにより実行される方法であって、
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、
対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、
方法。
【請求項19】
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成する手段と、
対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する手段と、
を備える保護済み実行コード作成装置。
【請求項1】
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、
対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、
処理をコンピュータシステムに実行させるためのプログラム。
【請求項2】
請求項1記載のプログラムであって、
前記挿入関数は、前記保護に関連する処理として暗号化された対象関数を復号する処理を示す復号コードを含み、
前記保護済み実行コードの生成は、前記対象関数を暗号化する処理を含む、
ことを特徴とするプログラム。
【請求項3】
請求項2記載のプログラムであって、
前記保護済み実行コードを生成する処理は、
前記対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、をリンカにリンクさせる処理と、
該リンカが出力する実行コードのうちの対象関数を暗号化することで保護済み実行コードを生成する処理と、
を含むことを特徴とするプログラム。
【請求項4】
請求項2記載のプログラムであって、
前記保護済み実行コードを生成する処理は、
前記挿入関数から前記復号コードを除きその代わりに後で復号コードを挿入する予約領域が設けられたものと、前記対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、をリンカにリンクさせる処理と、
該リンカが出力する実行コードのうちの前記予約領域に前記復号コードを挿入すると共に、該実行コード内の対象関数を暗号化することで保護済み実行コードを生成する処理と、
を含むことを特徴とするプログラム。
【請求項5】
請求項3又は4に記載のプログラムであって、
前記挿入関数は、
固定データと、
前記固定データの場所に対して対応する対象関数のアドレスを書き込む処理を前記リンカに実行させるための第1のリロケーション情報と、
を含むことを特徴とするプログラム。
【請求項6】
請求項3又は4に記載のプログラムであって、
前記挿入関数は、
前記呼び出し命令のオペランドに対して対応する対象関数のアドレスを書き込む処理を前記リンカに実行させるための第2のリロケーション情報、
を含むことを特徴とするプログラム。
【請求項7】
請求項2記載のプログラムであって、
前記挿入関数は、前記対象関数を暗号化する処理において当該挿入関数を見つけるためのマーク情報を含む、
ことを特徴とするプログラム。
【請求項8】
請求項2記載のプログラムであって、
前記挿入関数は、対応する対象関数の大きさを示すデータを含む、
ことを特徴とするプログラム。
【請求項9】
請求項2記載のプログラムであって、
前記復号コードは、各々が対応する暗号化を解く複数のサブ復号コードを含み、
前記対象関数を暗号化する処理では、それらサブ復号コードのうちの少なくとも1つに対応する暗号化処理により前記対象関数を暗号化すると共に、前記対象関数の暗号化処理に対応するサブ復号コードを他のサブ復号コードにより多重的に暗号化する、
ことを特徴とするプログラム。
【請求項10】
請求項2記載のプログラムであって、
複数の異なる復号コードを備え、異なる対象関数に対して異なる復号コードを挿入する、
ことを特徴とするプログラム。
【請求項11】
請求項10記載のプログラムであって、
前記複数の異なる復号コードは、それぞれ異なる暗号アルゴリズムに対応し、
前記暗号化実行プログラムを作成する処理では、挿入された復号コードに対応する暗号アルゴリズムを用いて、該復号コードに対応する対象関数を暗号化する、
ことを特徴とするプログラム。
【請求項12】
請求項2記載のプログラムであって、
前記挿入関数は、前記呼び出し命令の後に、前記対象関数を再暗号化するためのコードを更に備える、ことを特徴とするプログラム。
【請求項13】
請求項1記載のプログラムであって、
前記挿入関数は、
該挿入関数内で破壊するレジスタの値を該破壊を伴う処理が実行される前に所定の退避領域に退避するためのコードと、
前記保護に関連する処理の後前記対象関数を呼び出す前に、前記退避領域に退避していた値を前記レジスタに書き戻すためのコードと、
を含むことを特徴とするプログラム。
【請求項14】
請求項1記載のプログラムであって、
前記挿入関数は、
前記保護に関連する処理の後前記対象関数を呼び出す前に、該挿入関数を呼び出した命令の実行により積まれたスタックから引数をコピーして新たにスタックに積み、該挿入関数への戻りアドレスを新たにスタックに積むためのコード、
を含むことを特徴とするプログラム。
【請求項15】
請求項1記載のプログラムであって、
前記挿入関数は、
前記保護に関連する処理の後前記対象関数を呼び出す前に、該挿入関数の呼び出し元への戻りアドレスを所定の退避領域に退避するためのコードと、
前記保護に関連する処理の後に前記対象関数の実行が終わり、処理が前記挿入関数に戻ってきた後で、前記退避領域に退避していた戻りアドレスに処理を戻すためのコードと、
を含むことを特徴とするプログラム。
【請求項16】
請求項1記載のプログラムであって、
対象関数の指定をユーザから受け付け、
オブジェクトコードのうち対象関数として指定されたものの関数定義の関数名を、所定の規則に従って第2の関数名に変更する、
処理を更に前記コンピュータシステムに実行させることにより、前記対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードを生成する、ことを特徴とするプログラム。
【請求項17】
請求項1記載のプログラムであって、
前記挿入関数は、前記保護に関連する処理として、前記保護済み実行コードがツールにより解析されていることを検知する処理と、解析を検知した場合に前記対象関数の解析を阻止する処理と、を示すコードを含む、
ことを特徴とするプログラム。
【請求項18】
コンピュータシステムにより実行される方法であって、
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、
対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、
方法。
【請求項19】
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成する手段と、
対象関数の関数定義の関数名が第2の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する手段と、
を備える保護済み実行コード作成装置。
【図1】
【図2】
【図3】
【図4】
【図5】
【図6】
【図7】
【図8】
【図9】
【図10】
【図11】
【図12】
【図13】
【図14】
【図15】
【図16】
【図2】
【図3】
【図4】
【図5】
【図6】
【図7】
【図8】
【図9】
【図10】
【図11】
【図12】
【図13】
【図14】
【図15】
【図16】
【公開番号】特開2007−148575(P2007−148575A)
【公開日】平成19年6月14日(2007.6.14)
【国際特許分類】
【出願番号】特願2005−339269(P2005−339269)
【出願日】平成17年11月24日(2005.11.24)
【出願人】(000005496)富士ゼロックス株式会社 (21,908)
【Fターム(参考)】
【公開日】平成19年6月14日(2007.6.14)
【国際特許分類】
【出願日】平成17年11月24日(2005.11.24)
【出願人】(000005496)富士ゼロックス株式会社 (21,908)
【Fターム(参考)】
[ Back to top ]