(57)【特許請求の範囲】
【請求項１】
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、
対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、
処理をコンピュータシステムに実行させるためのプログラム。
【請求項２】
請求項１記載のプログラムであって、
前記挿入関数は、前記保護に関連する処理として暗号化された対象関数を復号する処理を示す復号コードを含み、
前記保護済み実行コードの生成は、前記対象関数を暗号化する処理を含む、
ことを特徴とするプログラム。
【請求項３】
請求項２記載のプログラムであって、
前記保護済み実行コードを生成する処理は、
前記対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、挿入関数と、をリンカにリンクさせる処理と、
該リンカが出力する実行コードのうちの対象関数を暗号化することで保護済み実行コードを生成する処理と、
を含むことを特徴とするプログラム。
【請求項４】
請求項２記載のプログラムであって、
前記保護済み実行コードを生成する処理は、
前記挿入関数から前記復号コードを除きその代わりに後で復号コードを挿入する予約領域が設けられたものと、前記対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、をリンカにリンクさせる処理と、
該リンカが出力する実行コードのうちの前記予約領域に前記復号コードを挿入すると共に、該実行コード内の対象関数を暗号化することで保護済み実行コードを生成する処理と、
を含むことを特徴とするプログラム。
【請求項５】
請求項３又は４に記載のプログラムであって、
前記挿入関数は、
固定データと、
前記固定データの場所に対して対応する対象関数のアドレスを書き込む処理を前記リンカに実行させるための第１のリロケーション情報と、
を含むことを特徴とするプログラム。
【請求項６】
請求項３又は４に記載のプログラムであって、
前記挿入関数は、
前記呼び出し命令のオペランドに対して対応する対象関数のアドレスを書き込む処理を前記リンカに実行させるための第２のリロケーション情報、
を含むことを特徴とするプログラム。
【請求項７】
請求項２記載のプログラムであって、
前記挿入関数は、前記対象関数を暗号化する処理において当該挿入関数を見つけるためのマーク情報を含む、
ことを特徴とするプログラム。
【請求項８】
請求項２記載のプログラムであって、
前記挿入関数は、対応する対象関数の大きさを示すデータを含む、
ことを特徴とするプログラム。
【請求項９】
請求項２記載のプログラムであって、
前記復号コードは、各々が対応する暗号化を解く複数のサブ復号コードを含み、
前記対象関数を暗号化する処理では、それらサブ復号コードのうちの少なくとも１つに対応する暗号化処理により前記対象関数を暗号化すると共に、前記対象関数の暗号化処理に対応するサブ復号コードを他のサブ復号コードにより多重的に暗号化する、
ことを特徴とするプログラム。
【請求項１０】
請求項２記載のプログラムであって、
複数の異なる復号コードを備え、異なる対象関数に対して異なる復号コードを挿入する、
ことを特徴とするプログラム。
【請求項１１】
請求項１０記載のプログラムであって、
前記複数の異なる復号コードは、それぞれ異なる暗号アルゴリズムに対応し、
前記暗号化実行プログラムを作成する処理では、挿入された復号コードに対応する暗号アルゴリズムを用いて、該復号コードに対応する対象関数を暗号化する、
ことを特徴とするプログラム。
【請求項１２】
請求項２記載のプログラムであって、
前記挿入関数は、前記呼び出し命令の後に、前記対象関数を再暗号化するためのコードを更に備える、ことを特徴とするプログラム。
【請求項１３】
請求項１記載のプログラムであって、
前記挿入関数は、
該挿入関数内で破壊するレジスタの値を該破壊を伴う処理が実行される前に所定の退避領域に退避するためのコードと、
前記保護に関連する処理の後前記対象関数を呼び出す前に、前記退避領域に退避していた値を前記レジスタに書き戻すためのコードと、
を含むことを特徴とするプログラム。
【請求項１４】
請求項１記載のプログラムであって、
前記挿入関数は、
前記保護に関連する処理の後前記対象関数を呼び出す前に、該挿入関数を呼び出した命令の実行により積まれたスタックから引数をコピーして新たにスタックに積み、該挿入関数への戻りアドレスを新たにスタックに積むためのコード、
を含むことを特徴とするプログラム。
【請求項１５】
請求項１記載のプログラムであって、
前記挿入関数は、
前記保護に関連する処理の後前記対象関数を呼び出す前に、該挿入関数の呼び出し元への戻りアドレスを所定の退避領域に退避するためのコードと、
前記保護に関連する処理の後に前記対象関数の実行が終わり、処理が前記挿入関数に戻ってきた後で、前記退避領域に退避していた戻りアドレスに処理を戻すためのコードと、
を含むことを特徴とするプログラム。
【請求項１６】
請求項１記載のプログラムであって、
対象関数の指定をユーザから受け付け、
オブジェクトコードのうち対象関数として指定されたものの関数定義の関数名を、所定の規則に従って第２の関数名に変更する、
処理を更に前記コンピュータシステムに実行させることにより、前記対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードを生成する、ことを特徴とするプログラム。
【請求項１７】
請求項１記載のプログラムであって、
前記挿入関数は、前記保護に関連する処理として、前記保護済み実行コードがツールにより解析されていることを検知する処理と、解析を検知した場合に前記対象関数の解析を阻止する処理と、を示すコードを含む、
ことを特徴とするプログラム。
【請求項１８】
コンピュータシステムにより実行される方法であって、
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、
対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、
方法。
【請求項１９】
保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成する手段と、
対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する手段と、
を備える保護済み実行コード作成装置。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、プログラム内部に含まれる保護対象の内容が読み出されないようにプログラムに部分的に保護（例えば暗号化）を加えるための技術に関する。
【背景技術】
【０００２】
この種の従来技術として、特許文献１に示される技術では、概略的には、図１に示すように、ソースコード１００の中の保護したい部分１１４の前後にマーク（又は復号のためのコード）１１２，１１６を手作業で挿入し、挿入後のソースコード１１０をコンパイラに渡してコンパイルさせ、その結果得られたオブジェクトコード１２０をリンカに渡してリンク処理を行う。そしてリンク後のオブジェクトコード１３０に対し暗号化ツールを適用する。暗号化ツールは、オブジェクトコード１３０中のマーク１３２，１３６に従い、保護したい部分１３４を暗号化する（これにより暗号コード１４４ができる）と共に、マーク１３２，１３６を復号処理のためのバイナリコード（復号コード１４２）に置き換えることで、最終的な実行コード１４０を生成する。
【０００３】
また特許文献２に示される技術は、特許文献１の技術のマークの代わりに、暗号化したコードを復号する復号コードを関数の形でソースコードに挿入するものである。すなわち、この技術では、概略的には図２に示すように、ソースコード２００の中の保護したい部分２１４の前に復号関数２１２を、後に暗号化部分の終わりを示す関数２１６を手作業で挿入し、挿入後のソースコード２１０をコンパイラに渡してコンパイルさせ、その結果得られたオブジェクトコード２２０をリンカに渡して復号関数のオブジェクトコード２３０等の必要なコードとリンクさせる。これにより、復号コード２４６を呼び出す命令２４２の後に保護したい部分２４４の平文が並んだオブジェクトコード２４０が生成される。そしてリンク後のオブジェクトコード２４０に対し暗号化ツールを適用する。暗号化ツールは、オブジェクトコード２４０中の保護したい部分２４４を暗号化する（これにより暗号コード２５４ができる）ことで、最終的な実行コード２５０を生成する。実行コードを実行した場合、命令２５２により復号コード２５６が呼び出されて実行され、これにより暗号コード２５４が復号され、実行される。
【０００４】
【特許文献１】特許第３０３３５６２号明細書
【特許文献２】特開２００５−１６５９１９号公報
【発明の開示】
【発明が解決しようとする課題】
【０００５】
上記従来技術は、いずれも、実行形式のプログラムを部分的に保護するための機能を実現している。しかし、コンパイラは、一般にコード実行順序の最適化を行う。最適化によりコード各部の実行順序が変わるので、例えば暗号化対象のコード部分の中に他のコード部分が紛れ込んだり、逆に暗号化対象のコード部分の一部がその部分の外に出てしまったりすることがある。このようなことが起こると、本来暗号化されるべきでない部分が暗号化対象部分と一緒に暗号化ツールで暗号化されたり、或いは暗号化されるべき部分が暗号化の範囲から外れて暗号化されなかったりすることになり、暴走するなどして正しく動作しないプログラムとなるおそれがあった。最適化によって暗号化対象部分にそのような順序変更が生じないように注意してソースコードを作成することは必ずしも不可能ではないが、プログラマに大きな負担を強いる。
【課題を解決するための手段】
【０００６】
本発明の１つの側面では、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、処理をコンピュータシステムに実行させるためのプログラム、が提供される。
【０００７】
本発明の別の側面では、コンピュータシステムにより実行される方法であって、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成し、対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する、方法が提供される。
【０００８】
本発明の更に別の側面では、保護対象である対象関数の関数名と同じ関数名を持つ挿入関数であって、対象関数の保護に関連する処理のコードと、該処理の後に対象関数を呼び出す呼び出し命令とを含む挿入関数を生成する手段と、対象関数の関数定義の関数名が第２の関数名に変更されたオブジェクトコードと、挿入関数と、に基づき保護済み実行コードを生成する手段と、を備える保護済み実行コード作成装置が提供される。
【発明を実施するための最良の形態】
【０００９】
以下、図面を参照して、本発明の実施の形態について説明する。
【００１０】
図３は、保護対象のコード部分を暗号化した暗号化プログラムを作成するための暗号化実行プログラム作成システムの一実施例を示す図である。このシステムは、コンパイラ３０２、対象関数指定部３０６、第１変換部３０８、リンカ３１０、第２変換部３１２を備える。これら各モジュール３０２、３０６、３０８、３１０、３１２は、典型的には、ＣＰＵ、メモリ、固定記憶装置、表示装置、及びキーボードやマウスなどの入力装置を備えた汎用のコンピュータに対し、以下で説明する各モジュールの機能又は処理内容を記述したプログラムを実行させることにより実現される。このようなプログラムは、ＣＤやＤＶＤなどの可搬型の記録媒体を介して、又はネットワークを介するダウンロードにより、コンピュータにインストールすることができる。なお、それら全てのモジュールが１台のコンピュータ上に実装される必要は必ずしもなく、複数台のコンピュータに分散配置されたそれらモジュールが連携動作してこのシステムを構成してもよい。
【００１１】
コンパイラ３０２は、処理対象のプログラムのソースコード３００をコンパイルしてオブジェクトコード３０４を生成する。コンパイラ３０２としては、従来からある一般的なものを用いればよい。上述の従来技術ではソースコードに対して手作業でマークや復号関数の呼び出し命令を記述したが、図３の例ではソースコード３００には手を加えない。コンパイラ３０２は、そのソースコード３００を従来周知の方式でコンパイルする。
【００１２】
対象関数指定部３０６は、ユーザから、ソースコード３００中の保護（この例では暗号化）対象の関数の指定を受け付ける。対象関数指定部３０６は、例えば、ソースコード３００をそのまま画面表示し、その中に含まれる各関数の近傍にそれぞれ例えばチェックボックスを配置し、ユーザがそのチェックボックスをクリック操作などで選択状態とすることにより、保護対象の関数（以下「対象関数」と呼ぶ）を選択できるようにする。なお、ソースコード３００をそのまま表示する代わりに、ソースコード３００中に含まれる関数を抽出し、抽出した各関数とそれに対応するチェックボックスとを画面表示し、ユーザに選択をさせてもよい。そして対象関数指定部３０６は、そのようなユーザインタフェース画面を介してユーザが選択した対象関数のリスト（例えば関数名を列挙したリスト）を生成し、出力する。
【００１３】
また、この代わりに、対象関数の関数名のリストをユーザがテキストエディタを用いて作成し、このリストを対象関数指定部３０６が受け取るようにしてもよい。
【００１４】
第１変換部３０８は、コンパイラ３０２が生成したオブジェクトコード３０４に対し、対象関数指定部３０６が生成する対象関数のリストを用いて変換を行う。この変換を「変換１」と呼ぶことにする。変換１では、オブジェクトコード３０４の中で、対象関数名（或いは当該関数を示すシンボル名）を別の名称に変更する。またこの変換１では、対象関数を適切に暗号化できるようにするため、及び暗号化されたその関数を実行時に適切に復号して実行できるようにするために、挿入関数を作成する。これら関数名の変更と挿入関数の作成については、後で詳しく説明する。
【００１５】
第１変換部３０８は、関数名を変更したオブジェクトコードと、挿入関数とを例えば別々のファイルとして出力する。またこの代わりに、第１変換部３０８が、関数名を変更したオブジェクトコードのファイルに挿入関数を追加して出力してもよい。このようにして第１変換部３０８が出力したオブジェクトコードと挿入関数のファイル、又はそれら両者を併せたファイルは、リンカ３１０へと渡される。
【００１６】
リンカ３１０は、第１変換部３０８から受け取ったファイル（又は複数のファイル）と、ライブラリなど他の必要な関数とをリンクして１つの実行可能プログラムファイルへとまとめる。リンカ３１０としては、従来からある一般的なものを用いればよい。
【００１７】
第２変換部３１２は、リンカ３１０が出力した実行可能プログラムファイルを取得し、そのうちの保護対象の部分を暗号化することで、部分的に暗号化された暗号化実行コード３１４のファイルを生成する。この第２変換部３１２が行う処理（暗号化を含む）のことを、以下では「変換２」と呼ぶ。この変換２の内容については、後で詳しく説明する。
【００１８】
図４は、図３のシステムが行う処理の流れを模式的に示した図である。この実施例では、ユーザが行う手作業は、保護対象のコード部分を含むソースコード４００（図３のソースコード３００に対応）を作成する作業と、対象関数指定部３０６を操作して暗号化したい関数のリスト４１０を作成する作業である。残りの作業は、ツール化されており、ユーザは何も行わなくてよい。
【００１９】
ソースコード４００はコンパイラ３０２によりオブジェクトコード４２０（図３のオブジェクトコード３０４に対応）に変換される。この例では、このオブジェクトコード４２０のうち、関数名"funcA"４２２で示される関数が対象関数であるとする。
【００２０】
このオブジェクトコード４２０は、第１変換部３０８により「変換１」の処理を受ける。「変換１」では、対象関数の関数名が別の関数名に変更される。関数名の変更は、オブジェクトコード４２０内の既存の関数の関数名と重ならず、かつ他の対象関数の変更後の関数名とも重ならない名称へ変更すればよい。例えば、１つの方法として、元の関数名に対し特定の文字列（或いはデータ列）を付加することで変更後の関数名を作成してもよい。付加する文字列として、通常関数名として用いられないものや、十分に長いものなどを用いれば、この付加により他の関数名と重ならない関数名を得ることができる。図示例では、元の関数名"funcA"が、Xという文字列を付加された別の関数名"funcAX"４３２に変更されている。なお、「変換１」では、このように対象関数の関数定義（関数の実体）における関数名は変更されるが、その対象関数を呼び出す命令の中の関数名は変更されない。
【００２１】
また「変換１」では、挿入関数４３４が作成される。第１変換部３０８は、この挿入関数４３４に対し、対象関数の元の関数名と同じ関数名"funcA"を与える。これにより、オブジェクトコード４３０中にある対象関数"funcA"を呼び出す命令は、対象関数ではなく挿入関数４３４を呼び出すことになる。
【００２２】
図５に、「変換１」が作成する挿入関数４３４（図５では挿入関数５００として示す）の一例を模式的に示す。
【００２３】
挿入関数５００の先頭には、当該関数５００中に記述される復号コード５１０へのジャンプ命令５０２がまず配置される。そして、その後に、後述する「変換２」（暗号化）の処理に用いるデータ５０４，５０６及び５０８が配置され、更にその後に復号コード５１０が配置される。この復号コードの内容は、復号処理のための一以上の命令を含むが、これは固定的なものなので第２変換部３１２が保持していればよい。復号処理の対象となる暗号化された関数のアドレス等を示す情報は、そのアドレスが決まった後でリンカ３１０が埋められるよう、リロケーションテーブルにデータを設定しておけばよい（詳細は後述）。ジャンプ命令５０２のジャンプ先のアドレスは、間にあるデータ５０４〜５０８のサイズが既知なので、求めることができる。データ５０４は、「変換２」の処理でこの関数５００を見つけるための特別なマーク情報であり、一般的な実行コード中には表れないデータ列を用いる。データ５０６は関数"funcAX"（すなわち関数名が変更された秘匿対象関数）のデータサイズを示すデータである。これは、オブジェクトコード４２０から求めることができる。
【００２４】
また、固定データ５０８は、アドレス情報を格納するのに十分な大きさを持つデータ領域である。この固定データのところに、後のリンカ３１０の処理により、割り当てられた関数"funcAX"のアドレスが設定される。すなわち、挿入関数"funcA"は、対象関数"funcAX"を復号するためのものなので、この復号の処理や関数呼出のために関数"funcAX"のアドレスが必要になる。しかし、実行時に関数がロードされるアドレスの値は、リンカ３１０がリンクを行った後でないと判定できない。そこで、ここでは、リンカ３１０が求めた関数"funcAX"のアドレスを容れる器として、固定データ５０８の領域をあらかじめ確保しておくのである。
【００２５】
以上に説明したデータ５０４〜５０８の後に、暗号化した対象関数を復号するための処理を記述した復号コード５１０が配置される。復号コード５１０が復号する対象となるコードの位置は、関数"funcAX"の大きさデータ５０６と、固定データ５０８の位置に後でリンカ３１０が書き込む関数"funcAX"の先頭アドレスを参照し、取得するように構成しておく。データ５０４は、暗号化（変換２）においては用いるが、暗号化したプログラムを実行する際には使用しないので、変換２において削除してかまわない。この挿入関数５００の冒頭にはジャンプ命令５０２が置かれるのは、５０４から５０８までのデータを、命令として実行しないようにするためである。そして、復号コード５１０の後に、関数名を置き換えた対象関数を呼び出すためのコード５１２が配置される。
【００２６】
なお、ジャンプ命令５０２やデータ５０６，５０８，コード５１０，５１２などは、マーク５０４の位置（アドレス）を基準にしてそれぞれ所定の関係となる位置にあればよいので、それらの並び順や順序は図示の例に限らない（ただし、復号コード５１０と関数呼び出し命令５１２の並びは、５１０が実行された後、５１２が実行されるような順番に配置する必要がある）。
【００２７】
また「変換１」は、挿入関数５００に付属するリロケーションテーブル５２０も作成する。このリロケーションテーブル５２０には、通常のリロケーション情報に加え、データエントリ５２２及び５２４が含まれる。データエントリ５２２には、挿入関数５００内の固定データ５０８のところにリンク時に判明した関数"funcAX"のアドレスをリンカ３１０に挿入させるためのデータ内容が書き込まれる。また、データエントリ５２４には、関数"funcAX"を呼び出すための命令コード５１２のオペランドにリンカ３１０が関数"funcAX"のアドレスを書き込むようにするためのデータ内容が設定される。これらアドレスの指定は、必要に応じ、相対アドレス指定又は絶対アドレス指定のうち適切な方で行えばよい。以下に、リロケーションテーブルのデータエントリ５２２及び５２４の具体例を表で示す。
【００２８】
〔表１〕
Offset    Type          Applied To     Index     Name
00000012  REL32        00000000        13  _     funcAX
00000056  REL32        00000000        13  _     funcAX
【００２９】
これは、Microsoft社のVisualStudioが利用しているCOFFフォーマットでの例である。この表の１行目は、データ項目を示す見出しで、テーブルの内容情報ではない。２行目がデータエントリ５２２に、３行目がデータエントリ５２４に相当するデータである。データ項目のうち"Offset"は、アドレスを書き込む場所を、関数の先頭からのオフセット(相対位置)で表現した値である。"Type"は書き込むアドレスの種類で、上の例("REL32")は、32ビットの相対アドレスを書き込むことを示す。"Applied To"は、書き込む先のデータ(固定データ５０８内のデータおよび、call命令５１２のオペランド)を示す。これらはリロケーションテーブル内のデータではない。"Index"は、書き込むべきアドレスの対象となるデータのシンボル名のインデックス(シンボルテーブルのエントリの番号)で、この例では、関数funcAXを示す。"Name"は、"Index"が示しているシンボル(ここでは関数名)を、シンボルテーブルを参照して表示しているものであり、実際のリロケーションテーブルには存在しない。
【００３０】
表１の例では、00000012は、固定データの位置が、関数の先頭から0x12バイト目にあることを示し、00000056は、call funcAX();命令のオペランドが0x56バイト目にあることを示す。また、Indexの13は、funcAXのシンボルが13のインデックス番号に割り当てられていると仮定している。このように、リロケーションテーブルのエントリは、書き込む先のオフセット、書き込むアドレスの種類、書き込むべきアドレスにあるデータのシンボル(インデックス)の三つ組みで構成される。
【００３１】
この第１変換部３０８の行う「変換１」の処理手順の例を、図６を参照して詳細に説明する。
【００３２】
まず第１変換部３０８は、コンパイラ３０２が出力したオブジェクトコード（３０４すなわち４３０）と、対象関数指定部３０６が作成した対象関数のリストとを入力として受け取る（Ｓ１）。次に、第１変換部３０８は、対象関数のリストから１つ対象関数を取り出し（Ｓ２）、関数リストの最後に到達していなければ（すなわちＳ３でリストから関数を取り出せれば）（Ｓ３）、ステップＳ４に進む。
【００３３】
ステップＳ４では、オブジェクトコード３０４をスキャンして、ステップＳ２で取り出した対象関数を検出する。より詳細には、オブジェクトコード３０４中のシンボルテーブルの中から、その対象関数の関数名に対応するシンボルを検出し、このシンボルに対応するオブジェクトファイル内のコード位置をシンボルテーブルから読み出す。このコード位置は、例えば、オブジェクトファイル内のセクション番号とそのセクションの先頭からのオフセットの組により表現される。これにより、対象関数が検出できる。
【００３４】
次に第１変換部３０８は、ステップＳ５でその対象関数の大きさ（データサイズ）を求める。そして、ステップＳ６では、その対象関数の関数名を他と重ならない別の関数名に変更する。すなわち、特定の文字列を追加するなどにより変更した関数名のシンボルをシンボルテーブルに追加し、その関数の関数定義の指し示すシンボル名がその新たに追加したシンボル名となるようにする。
【００３５】
次に第１変換部３０８は、ステップＳ７で、その対象関数の元の関数名を持つ挿入関数５００をオブジェクトコード３０４に挿入する。すなわち、対象関数の元の関数名を示すシンボル名を関数名とする新たな関数（挿入関数５００）の関数定義を追加する。ここで、挿入関数５００のうち対象関数に依存する部分は、対象関数の大きさのデータ５０６だけであり、これはステップＳ５で求められているので、挿入関数５００は作成できる。そしてステップＳ８では、挿入関数５００の所定の位置に、リンカ３１０が対象関数のアドレスを設定することができるようにするために、リロケーションテーブルのデータエントリ５２２及び５２４を追加する。そしてステップＳ２に戻る。
【００３６】
対象関数のリストに載っている全ての関数について処理が終わるまで、ステップＳ２〜Ｓ８の処理を繰り返す。リストの最後に到達すると（Ｓ３）、変換１の処理が完了し、第１変換部３０８は変換結果のデータをオブジェクトコードのフォーマットに従ったデータ（オブジェクトコード４３０）として出力する（Ｓ９）。これにより、「変換１」の処理が終了する。
【００３７】
図４の説明に戻ると、「変換１」により生成されたオブジェクトコード４３０は、リンカ３１０により他の必要な関数とリンクされる。リンカ３１０の処理により、関数"funcAX"のアドレスが決定され、そのアドレスが固定データ５０８のところに設定され、更にそのアドレスが呼び出し命令コード５１２のオペランドに設定される。リンカ３１０が出力する実行コード４４０には、挿入関数５００の挿入コードを呼び出す命令４４２の後に対象関数のコード４４４が平文の機械語で記述され、その後に挿入関数４３４の挿入コード４４６が来る。なお、呼び出し命令４４２の後に対象関数のコード４４４が配置されると行ったのはあくまで一例に過ぎない。実際には、コードの実行順序はリンカが適切に決定するので、呼び出し命令４４２と対象関数のコード４４４との並び順はどのような順序でもよい。
【００３８】
この実行コード４４０が、第２変換部３１２に渡される。第２変換部３１２は、その実行コード４４０中の挿入コード４４６のデータに基づき保護対象のコード４４４の範囲を特定し、そのコード４４４を暗号化する。この処理の手順を、図７を参照して説明する。
【００３９】
この手順では、第２変換部３１２はまずリンカ３１０の出力した平文の実行コード４４０を入力として受け取る（Ｓ１１）。次に、「変換１」で埋め込んだマーク５０４をキーとしてその実行コード４４０を検索することで、挿入関数５００を検出する（Ｓ１２）。実行コード４４０の末尾に達しないうちに挿入関数５００が見つかれば（Ｓ１３）、マーク５０４を基準として、データ５０６及び５０８のアドレスを特定し、それら各アドレスから、その挿入関数５００に対応する対象関数のサイズ（データ５０６）とアドレス（データ５０８）を取得する（Ｓ１４）。そして、第２変換部３１２は、検出したマーク５０４を削除するために、マーク５０４のところに別のデータ列を上書きする（Ｓ１５）。これは、暗号化された実行コード４５０が解析された時に、マーク５０４が解析の手がかりとなることを防ぐためである。実行コード中の各マークの位置を例えば乱数のように予測のつきにくいそれぞれ互いに異なるデータ列で上書きすれば、マークが存在したことを隠蔽できる。そして、第２変換部３１２は、実行コード４４０のうち、ステップＳ１４で取得したアドレス及びサイズが示す範囲（すなわち対象関数のコード部分）を所定の暗号アルゴリズムにより暗号化する（Ｓ１６）。この後、ステップＳ１２に戻り、実行コード４４０の最後に達するまで、ステップＳ１２〜Ｓ１３の処理を繰り返す。ステップＳ１３で実行コード４４０の最後まで達したと判定されると、その時点で作成されている実行コード４５０を出力する（Ｓ１７）。
【００４０】
第２変換部３１２の処理により生成される実行コード４５０の中には、復号コードの呼び出し命令４５２と、暗号化された対象関数のコード４５４とが配置され、その後に復号コード４５６が、そしてその後に暗号化された対象関数のコード４５４を呼び出す命令が配置される。ここで、呼び出し命令４５２とコード４５４の並び順は、図示の順序に限らず、どのような順序でもよい。この実行コード４５０をコンピュータシステムで実行すれば、関数"funcA"の呼び出しによりまず復号コード４５６が呼び出され、その実行の後に暗号化された対象関数のコード４５４が呼び出されることになる。これにより、暗号化されたコード４５４が復号され、実行されることになる。
【００４１】
以上に説明した例によれば、暗号化対象が関数単位で指定され、関数単位で暗号化が行われるので、従来技術のように暗号化対象のコードの中に別のコードが紛れ込んで暗号化されるなどのような不具合を大幅に低減できる。また、特許文献１では、復号コードやマークなどをソースに挿入するために、プログラム開発環境にインラインアセンブラの機能が必要だが、この実施例では、対象関数の指定をすればよく、そのためのツールとして対象関数指定部３０６が用意されているので、インラインアセンブラのない環境にも対応できる。また、この例では、ソースコード自体は変更しないので、ソースコードのメンテナンス性が向上するというメリットも得られる。
【００４２】
また、１プログラム中の複数の関数を保護する場合、第１変換部３０８又は第２変換部３１２で挿入する復号コードを、各対象関数ごとに互いに異なるコード内容とすることも好適である、例えば、同じ復号アルゴリズムを別のコード内容で表現した複数の復号コードを用いてもよいし、異なる暗号アルゴリズムに対応した複数の復号コードを用いてもよい。後者の場合、第１変換部３０８で復号コードを挿入する構成では、第２変換部３１２が各復号コードに対応した部分を正しく暗号化するための処理が必要である。例えば、第１変換部３０８で異なる復号コードを予め定めた順序で適用するようにし、第２変換部３１２ではその順序に従って各復号コードに対応する暗号アルゴリズムを適用したり、又は第１変換部３０８でどの暗号アルゴリズムに対応する復号コード化を示すデータを挿入関数中に書き込み、それを第２変換部３１２が解釈して適切な暗号アルゴリズムを適用したりする方法を用いることができる。
【００４３】
また、挿入関数５００内において、対象関数の呼び出し命令５１２の後に、対象関数を再暗号化するためのコードを追加することも好適である。このようにすることで、暗号化実行コードの実行時に復号された対象関数が実行された後、挿入関数５００に処理が戻り、実行された対象関数の再暗号化が行われる。これにより、実行後にメインメモリ上に対象関数が残る場合にも、その内容を秘匿することができる。なお、再暗号化のコードには、メモリアドレス上のどの範囲を暗号化するかを示す情報が必要であるが、これは対象関数の大きさデータ５０６やアドレスデータ（固定データ５０８のところにリンカ３１０が書き込むデータ）等の情報を用いて、リンカ３１０が解決することができる。
【００４４】
次に、図８を参照して、「変換１」がオブジェクトコード３０４に挿入する挿入関数の別の例を説明する。
【００４５】
挿入関数８００のうちマーク８０２、データ８０６及び８０８は、図５の挿入関数５００におけるマーク５０４、データ５０６及び５０８とそれぞれ同じものでよい。また、リロケーションテーブル８２０に追加するデータエントリ８２２及び８２４も、図５のリロケーションテーブル５２０内のデータエントリ５２２及び５２４と同じものでよい。図５の挿入関数と５００と異なる点は、挿入関数８００にこの挿入関数８００自身の大きさを示すデータ８０４が含まれることと、復号コード５１０の代わりに、後でその復号コードを挿入するためのエリア８１０が確保されているところである。
【００４６】
挿入関数８００自身の大きさのデータ８０４は、この挿入関数８００自体も一部暗号化して保護する場合に利用できる。すなわち、復号コードなど挿入関数８００内に含まれるデータ内容が解析されると、暗号化したコードの安全性が脅かされるので、挿入関数のうち平文である必要がある部分（例えばこのデータ８０４及び暗号化した復号コードを復号するコード）以外を暗号化することが考えられる。すなわちこの場合、対象関数を復号する本来の復号コード（第１復号コードと呼ぶ）と、その復号コードを暗号化したものを復号するための復号コード（第２復号コードと呼ぶ）が必要である。この場合、例えば、第２復号コード、第１復号コードを暗号化したもの、の順にコードを配列する。また、この場合、挿入関数の末尾がどこか分からないと実行時にどこまでを復号化したらよいか分からないが、このデータ８０４を用いれば末尾の位置を求められる。
【００４７】
また、エリア８１０には、後の「変換２」の処理の中で復号コード（及び復号した対象関数を呼び出すコード）を挿入する。このように、復号コード等を「変換２」で挿入する構成とすることで、復号コードが平文状態で人の目に入る可能性を低減できるので、暗号化したコードの安全性を向上させることができる。
【００４８】
また、このように挿入した復号コード等の部分を「変換２」の処理で暗号化することで、復号コードを保護することができ、ひいては対象関数の安全性の向上も図れる。
【００４９】
なお、「変換１」でエリア８１０を確保するだけで、復号コード等の暗号化は行わない構成でも、復号コードの保護効果はある程度得られる。
【００５０】
次に、対象関数に対して暗号化を多重的に施すことで、暗号強度を高める例について説明する。
【００５１】
図９には、１重の暗号化処理ごとに、復号のための関数を別関数として挿入する方式の例を模式的に示す。この例では、実行コード９００の中の対象関数"funcA()"を３重に暗号化している。この例では、暗号化が１重増えるごとに、関数名の後ろに所定の文字列（この例では"X"）を１つずつ足していくという規則性に従い、関数名を変更している。すなわち、この例では３重の暗号化を施すので、対象関数名は"funcAXXX"（関数９０４）と変更されている。３重の暗号化のうちの外側の暗号化を解くための復号関数９０８が、元の対象関数と同じ関数名"funcA"を受け継ぐ。この関数９０８は、外側の暗号化に対応する復号コード９１０と、中間の暗号化を解くための復号関数９１４"funcAX"を呼び出す命令９１２とを含む。中間の復号関数９１４は、中間の暗号化を解く復号コード９１６と内側の復号関数９２０"funcAXX"を呼び出す命令９１８とを含む。内側の復号関数９２０は、内側の暗号化を解くための復号コード９２２と、対象関数９０４"funcAXXX"を呼び出す命令９２４とを含む。ここで、復号コード９１０，９１６及び９２２は、互いに異なるコード内容とすることが、暗号破りを難しくするという観点から見て好適である。これは、同じ復号アルゴリズムを別のコード内容で表現したものでもよい（この場合、内側、中間、外側の暗号化アルゴリズムは同じ）。また、内側、中間、外側の暗号化アルゴリズムを異ならせ、各復号コード９１０，９１６及び９２２をそれに応じて異なったものとしてもよい。
【００５２】
対象関数の関数名の変更規則や、各段階の復号関数の命名規則は、例示したものに限らない。実行コード中で一意に区別でき、かつ対象関数の呼び出しにより最外側の復号関数が呼び出され、最内側の復号関数の中から名称変更後の対象関数が呼び出されるようになるならば、どのような規則で関数名を決めてもよい。
【００５３】
このような実行コード９００を作成するため、第１変換部３０８は、オブジェクトコード中の対象関数の関数定義の冒頭にある関数名を規則に従って変更すると共に、外側、中間、内側の復号関数を作成する。図示は省略したが、各復号関数には図５に示したようなマーク５０４や大きさデータ５０６、固定データ５０８、リロケーションテーブルのエントリ５２２，５２４が含まれる。第１変換部３０８が追加するリロケーションテーブルのデータエントリには、変換により追加される各関数名"funcAX"、"funcAXX"及び"funcAXXX"についてリンカ３１０で決定される各アドレスが、それぞれオブジェクトコード内の必要な箇所（図５の例で言えば固定データ５０８や呼び出し命令５１０のオペランド）に設定されるようにするためのデータが含まれる。関数名が変更されたオブジェクトコードと、外側、中間、及び内側の復号関数とは、リンカ３１０により１つの実行コードへと結合され、このとき、各関数"funcAX"、"funcAXX"及び"funcAXXX"についてのアドレス解決が行われる。
【００５４】
第２変換部３１２は、リンカ３１０の出力した実行コードから復号関数９０８，９１４，９２０を検出し、それら関数間の呼び出し関係から復号関数の順序（内側、中間、外側）を特定すると共に、保護対象のコード９０６の範囲を特定する。そして、内側から順に暗号化を行う。内側の暗号化は、保護対象のコード９０６と、対象関数９０４を呼び出す命令９２４に対して施す。命令９２４は定型的なものであり、第１変換部３０８が作成するのでサイズや位置は分かっている。または、図５の例と同様、コード９２２内に、対象関数９０４の位置と関数９２０のサイズとが含まれるので、それらの情報から暗号化に必要な情報を得ることもできる。したがって、第２変換部３１２は命令９２４の位置及びサイズの示す範囲を暗号化すればよい。中間の暗号化は、保護対象のコード９０６（ただし内側の暗号化を受けたもの）と、内側の復号関数９２０を呼び出す命令９１８及び内側の復号関数９２０とに対して施す。命令９１８及び内側の復号関数９２０も第１変換部３０８が作成するため位置及びサイズが既知なので、暗号化できる。外側の暗号化は、保護対象のコード９０６（ただし内側及び中間の暗号化を受けたもの）と、中間側の復号関数９１４を呼び出す命令９１２と、中間及び内側の復号関数９１４及び９２０とに対して施す。この処理により作成される実行コード９００では、外側の暗号化に対応する復号コード９１０は平文であるが、中間及び内側の暗号化に対応する復号コード９１６，９１８は暗号化されている。また保護対象のコード９０６は３重に暗号化されている。
【００５５】
このように対象関数９０４が多重的に暗号化された実行コード９００をコンピュータシステムにて実行した場合、呼び出し命令９０２によりまず外側の復号関数９０８が呼び出されて外側の暗号が解かれ、これにより中間の暗号化の復号コード９１６が平文になる。次に、中間の復号関数９２０が呼び出され、平文の復号コード９１６が実行されることで、中間の暗号が解かれる。そして同様にして内側の暗号が解かれることで、保護対象のコード９０６が平文となり、命令９２４によりそのコード９０６が呼び出されて実行される。
【００５６】
多重暗号化の別の例を、図１０を参照して説明する。この例では、１つの復号関数（挿入関数）１００８内に多重に外側用、中間用、及び内側用の復号コード１０１０、１０１２、及び１０１４をその順に組み込んでいる。保護対象のコード１００６を含んだ対象関数１００４は、元の関数名"funcA"とは異なる関数名"funcAX"に変更され、復号関数１００８には対象関数１００４の元の関数名"funcA"が与えられている。復号コード１０１０〜１０１４のコード内容やサイズは第１変換部３０８が知っている（あるいは図５の例の方式と同様にして各復号コード内に書き込まれた情報から求めることができる）ので、第１変換部３０８は内側の復号コード１０１４が中間の暗号化で、中間の復号コード１０１２が外側の暗号化で、それぞれ暗号化されるように、オブジェクトコードに組み込むことができる。第２変換部３１２は、保護対象のコード１００６及び対象関数１００４を呼び出す命令１０１６を内側の暗号化処理で暗号化し、その暗号化結果と内側用の復号コード１０１４とを中間の暗号化処理で暗号化し、その暗号化結果と中間の復号コードとを外側の暗号化処理で暗号化する。
【００５７】
このような処理で作成された実行コード１０００をコンピュータシステムが実行した場合、対象関数１００４を呼び出す命令１００２により復号関数１００８が呼び出され、まず外側の復号コード１０１０が実行されることで外側の暗号化が解かれ、これによって平文となった中間の復号コード１０１２が実行されることで中間の暗号化が解かれる。そして、その結果平文となった内側の復号コード１０１４が実行されることで内側の暗号化が解かれ、命令１０１６と保護対象コード１００６が平文となる。この後、命令１０１６が実行されることにより、保護対象コード１００６が呼び出されて実行される。
【００５８】
図９及び図１０の例に示したように、復号コードを複数用意し、内側の復号コードから順に、各復号コードに対応する暗号化により順に他の復号コードを入れ子式に暗号化していくことにより、対象関数を復号するためのコードの多くの部分を暗号化することができる。これにより、解析に対しより耐性の高い保護が実現できる。
【００５９】
図９及び図１０の例では、保護対象のコード９０６及び１００６に対し、内側、中間、外側の暗号化を順に施したが、これに限らず、保護対象のコードには内側の暗号化のみを施し、その内側の暗号化を解除するための復号コードを中間及び外側の暗号化で保護するようにしてもよい。
【００６０】
また、以上の例ではユーザの指定に応じて対象関数指定部が対象関数のリストを作成し、このリストに基づき第１変換部３０８が対象関数の関数名を変更した。ただし、これは必須のことではない。この代わりに、ユーザ（プログラマ）が、ソースコード中の対象関数名を、所定の修飾の付加により変更する方式もある。この方式では、ユーザが、エディタなどを用い、ソースコードの中で保護対象とする関数の関数定義の関数名に対し所定の規則に従った修飾を付加する。例えば"funcA"なる関数名の後に、あらかじめ定めた"_x"なる文字列を付加して"funcA_x"と変更するなどである。
【００６１】
ただし、変更した関数名がプログラム内で一意になるようにするには、人間にとっては覚えにくく、入力しにくく、また後で読んで認識しにくいような、長く複雑な修飾文字列を付加する必要が出てくることも考えられる。そこで、関数名の変更作業を支援するために、ソースコードを前処理するプリプロセッサのマクロ機能を用いることも好適である。すなわち、この場合、人間にとって分かりやすく比較的入力しやすい修飾を、コンピュータにとって識別しやすく一意性が得られる確率の高い修飾に置換するためのマクロをユーザが作成してソースコードに追加する。そして、ユーザは、エディタ等を用いてソースコード中の対象関数の定義の関数名に人間用の修飾を付加する。この修飾付加済みのソースコードをプリプロセッサに処理させれば、対象関数の定義の関数名をコンピュータ用の修飾付きのものに変更することができる。このとき、仮に修飾を付けて変更した関数名が他の関数の関数名と重複してしまった場合は、プリプロセッサがその重複の事実を検出して警告を発するので、これに応じユーザは対象関数の関数名に与える人間用修飾を別のものに変更するなどの対処ができる。また、この例のようにマクロで修飾を与える場合、マクロを削除又は変更するだけで、それまでの修飾を解除することができる。したがって、複数の関数を保護対象に指定する場合に、保護の有効化／無効化の切り換え作業が容易になるという利点もある。
【００６２】
この場合、図３のシステムでは、対象関数指定部３０６が不要となる。第１変換部３０８は、挿入関数の作成は行うが、関数名の変更処理は行う必要がない。挿入関数の作成に当たり、第１変換部３０８は、オブジェクトコード３０４のなかから、対象関数に対応する所定の修飾（コンピュータ用修飾）を持った関数の定義を見つけ出し、その関数定義の関数名からその修飾を削除したものを挿入関数の関数名とする。挿入関数の内容は上述の例と同様でよい。リンカ３１０及び第２変換部３１２は図３の例と同様のものでよい。
【００６３】
このように、ソースコード上でプログラマ自身が対象関数の関数名を変更するようにすれば、暗号化の指定の有効化及び解除が容易に切り換えられ、デバッグやソースコードの変更、メンテナンスのしやすさを維持したまま関数名の修飾ができる。また、図３の例では、第１変換部３０８が対象関数の関数名を自動的に変更するので、プログラマが予期しない副作用が生じる可能性があるが、プログラマ自身が必要な関数名を変更する方式ならば、予期しない副作用のリスクは低減できる。
【００６４】
なお、ソースコード中の対象関数の関数名をユーザが変更する方式は、ソースコードをユーザが改変するという点で従来技術と一致しているが、次のような相違がある。すなわち、従来技術ではソースコード中の関数の中に復号コードや復号関数を挿入するなど、関数の内部に対して改変を行っていたため、コンパイラの最適化によりコードの実行順序に予期せぬ変更が加えられ、想定する動作と異なった動作をする場合があった。これに対し、本方式では、関数定義の関数名しか変更しないので、そのような不具合は生じにくい。
【００６５】
次に、図３、図４の装置により生成された暗号化実行コード３１４をコンピュータシステム上で実行する場合における、挿入関数４３４から暗号化した対象関数４３２を呼び出す際の関数の引数の引き渡しについて説明する。
【００６６】
図３、図４の装置では、元々対象関数４３２を呼び出していた呼び出し命令４３０により挿入関数４３４が呼び出される。このため、呼び出し命令４３０に指定された関数の引数は、挿入関数４３４に渡されることになる。これら引数は、挿入関数４３４を実行して暗号化した対象関数４３２を復号した後、復号された対象関数４３２に正しく引き渡される必要がある。
【００６７】
引数には、レジスタに設定されるものとスタックに積まれるものとがある。レジスタに設定されるものについては、利用されているレジスタを挿入関数内で破壊する場合には、破壊する前にそのレジスタの値を他の場所（例えばメインメモリのデータ領域、或いはローカル変数等の形でスタック上）に退避しておき、退避した値を対象関数の呼び出しの直前に同じレジスタに設定し直せばよい。挿入関数４３４には、このようなレジスタの退避と復帰のためのコードを組み込んでおく。
【００６８】
また、スタックに積まれた引数の引き渡しの方法としては、図１１及び図１２に示すようなものがある。
【００６９】
図１１の例は、挿入関数のために新たにスタックを積み直す方式である。図１１に示すように、挿入関数が呼び出された直後は、スタック１１００の先頭部分には、呼び出し元への戻りアドレス１１０２と、呼び出し命令に指定された引数ａ１１０４，引数ｂ１１０６，・・・及び呼び出し元の作業領域１１０８が格納されている。その後、挿入関数を実行して復号した対象関数を呼び出す段階で、元のスタックの内容は残したまま、スタック１１００の先頭に挿入関数の作業領域１１１８を積み、更に引数ａ１１０４，引数ｂ１１０６，・・・をコピーして引数ａ１１１４，１１１６，・・・として積んだところで、対象関数を呼び出すと、挿入関数への戻りアドレス１１１２が積まれる。このようにすることで、挿入関数から呼び出された対象関数は呼び出し元に指定された引数ａ，ｂ，・・・を用いて計算を行えるようになる。なお、このようにするために、第１変換部３０８は、作成する挿入関数中の対象関数を呼び出す前の位置に、このようにスタック内容のコピーを行うコードを組み込んでおくことで、対象関数への引数の受け渡しが可能となる。なお、広く普及しているインテル社のPentium（登録商標）系のプロセッサでは、呼び出し命令が実行されるとスタックに戻りアドレスが自動的に積まれるので、挿入関数に組み込むコードは、挿入関数への戻りアドレス１１１２以外のデータを積む処理を示すコードであればよい。
【００７０】
ここで、例えば、Ｃ＋＋等のような言語では、コンパイラが、関数名に対し引数などの情報を付加した名前修飾を行うので、その修飾の情報から引数が幾つあり、各引数のデータサイズがどれだけあるかが分かるので、第１変換部３０８は、スタックの先頭からどこまでをコピーすればよいかが判定できる。
【００７１】
図１２の方式は、挿入関数のために新たなスタックを積むことはせずに、元のスタック内容を維持して挿入関数のために流用する方式である。図１２の例では、挿入関数が呼び出された直後のスタック１２００は、図１１の場合と同様である。そして、挿入関数を実行して復号した対象関数を呼び出す段階で、呼び出し元への戻りアドレス１２０２を安全な退避場所１２１０に退避する。退避場所１２１０としては、例えばメインメモリのデータ領域、破壊されないことが分かっているレジスタ、あるいはメインメモリ上のデータ領域又はコード領域に用意した場所（例えば図５の固定データ５０８の領域と合わせて確保するなど）などを用いることができる。そして、対象関数を呼び出すことで、挿入関数への戻りアドレス１２０４が積まれる。そして、復号した対象関数の実行が終わって処理が挿入関数に戻ってきた時に、対象関数からの戻り値は維持したまま、処理は退避場所１２１０にある呼び出し元への戻りアドレス１２０２へとジャンプする。このジャンプは、分岐命令を用いることで実現できる。また、別の方法として、退避場所１２１０の戻りアドレスをスタックの先頭に積み直してから、挿入関数からの戻り命令（例えばret命令）を実行する方法もある。なお、このようにするために、第１変換部３０８は、作成する挿入関数中の対象関数を呼び出す命令の前に呼出元アドレス１２０２の退避を指示するコードを、対象関数を呼び出す命令の後ろに、退避した呼び出し元への戻りアドレスへ処理をジャンプさせるためのコードを組み込めばよい。
【００７２】
また、リンカが生成する実行コード中のプログラムの関数の呼び出し構造として、一般には、関数を直接呼び出す方式と、ジャンプテーブルを介して呼び出す方式とがある。そして、これらの方式は、１つのプログラム中で混在して用いられる可能性がある。ジャンプテーブルを介する呼び出しの場合、上述の関数呼び出し命令の指す先はジャンプテーブル上の１つのジャンプ命令である。したがって、図４で説明した変換処理のように、呼び出し命令が指し示す先を暗号化するという方式では、ジャンプ命令が暗号化されることになりかねない。ところが、暗号化したいのは、ジャンプテーブルではなく、そのジャンプ先にある関数の実体（関数定義）である。そこで、「変換２」において、対象関数のアドレスを取得するときに、そのアドレスがジャンプテーブルであった場合には、ジャンプ先である関数本体のコードを見つけて暗号化する必要がある。
【００７３】
このために、第２変換部３１２は、簡便には、図１３に示すように参照先アドレス（すなわち固定データ５０８のところにリンカ３１０がセットするアドレス）の命令を調べ（Ｓ２１）、その命令がジャンプ命令でなければ（Ｓ２２）、その参照先アドレスが対象関数を指すものと判断し（Ｓ２４）、そのアドレスを起点として暗号化を行う。これに対し、参照先アドレスの命令がジャンプ命令であれば（Ｓ２２）、その命令が示すジャンプ先のアドレスが対象関数の先頭と判断し（Ｓ２３）、そのアドレスを起点として暗号化を行う。この方式は、ジャンプテーブルのエントリはジャンプ命令そのものであるのに対し、関数実体の先頭にジャンプ命令が来ることは稀であるという事実に基づいている。
【００７４】
ただし、関数定義の先頭にジャンプ命令が来ることは皆無とは言えない。このような稀な場合も考慮した処理方式として、例えば次のような処理方式も考えられる。すなわち、この処理方式では、第１変換部３０８は、ユーザが指定した対象関数の実体（例えばその関数の先頭の所定数の命令など）の一部又は全体を複写して対象関数データベースに保存しておき、これを第２変換部３１２が参照する。第１変換部３０８は、対象関数指定部３０６から与えられる情報からどの関数実体が保護対象かが判別でき、その関数の実体の情報を取得することができる。保存する対象関数の実体の一部は、実体の所定の位置（例えば先頭）の所定サイズのコードであってもよいし、その対象関数の実体のハッシュ値であってもよい。第２変換部３１２は、図１４に示すように、参照先アドレスの命令を調べ（Ｓ３１）、その命令が対象関数データベースに記録されているものと同じか否かを判定する（Ｓ３２）。記録されていれば、その参照先アドレスが対象関数を指すものと判断し（Ｓ３３）、そのアドレスを起点として暗号化を行う。記録されていなければ、その参照先アドレスの指すコードの先頭がジャンプ命令であるか否かを判定する（Ｓ３４）。ここで参照先アドレスの先頭の命令がジャンプ命令であれば、その命令が示すジャンプ先のアドレスが対象関数の先頭と判断し（Ｓ３５）、そのアドレスを起点として暗号化を行う。ジャンプ命令でなければ、参照先アドレスに対象関数もなければ、その対象関数に対してジャンプする命令もないので、結局、正しい対象関数が見つからないということになる。そこで、この場合は、正しい対象関数が見つからない場合の所定のエラー処理を実行する（Ｓ３６）。
【００７５】
以上の様々な例では、対象関数を保護する手段として暗号化を用いた。しかし、関数の保護手段は暗号化に限らない。例えば、デバッガなどのツールを用いて対象関数が解析されることを防止又は低減するための保護手段が考えられる。この保護手段としては、例えば、そのようなツールによる解析が行われていることを検知する処理と、検知した場合にはそのツールの実行を止めるなどして対象関数の解析をできなくする処理と、を記述した解析対策用の挿入関数をプログラムに組み込むことが１つの方法である。
【００７６】
すなわち、この例では、対象関数の関数名を変更すると共に、その対象関数の元の関数名"funcA"を持つ図１５に示すような挿入関数１５００を作成する。この挿入関数１５００は、上述のように、ツールによる解析されていることを検出する処理と、解析されていることを検出した場合はツールの実行を止める処理とを記述した解析対策コード１５０２を含む。解析されていない場合は、ツールを止める処理を行わずに解析対策コード１５０２の実行は終了し、対応する対象関数"funcAX"を呼び出す命令１５０４が実行される。挿入関す１５００に付随するリロケーションテーブル１５１０には、命令１５０４が正しい呼び出し命令として機能するようにするために、そのオペランドにリンカが対象関数"funcAX"をセットするようにするためのデータエントリ１５１２が含まれる。このような保護をプログラムに対して施すためのシステムを、図１６を参照して説明する。
【００７７】
図１６のシステムにおいて、コンパイラ１６０２及びリンカ１６１０は、従来からある通常のものでよい。コンパイラ１６０２は、ソースコード１６００をオブジェクトコード１６０４に変換する。対象関数指定部１６０６は、図３のシステムの対象関数指定部３０６と同様の働きをし、ユーザはこの対象関数指定部１６０６に対し保護対象の関数を指定する。コード変換部１６０８は、図３における第１変換部３０８に類似の処理を行う手段であり、オブジェクトコード１６０４の中の各対象関数の関数実体の関数名を変更し、各対象関数の元の関数名を持つ挿入関数１５００をオブジェクトコード１６０４に挿入する。リンカ１６１０は、挿入関数１５００とオブジェクトコード１６０４、他のライブラリ関数などとリンクし、このときアドレス解決などの必要な処理を行う。このリンク処理により、保護済みの実行コード１６１４が生成される。この保護済み実行コード１６１４は、普通に実行されている状態であれば対象関数も実行される。これに対し、デバッガなどの解析ツールで解析を行いながら実行されている場合は、挿入関数１５００がその解析の事実を検出し、例えば実行を即時停止するなど、解析ツールが対象関数のところに進めないように制御する。これにより、対象関数が解析ツールに読み込まれることを防止できる。
【００７８】
以上、対象関数の保護の例として、暗号化と、デバッガによる解析に対する保護を例示したが、対象関数の保護の方法には様々なやり方があり、図１５及び図１６を用いて説明した方法はそれら様々なやり方に対して適用可能である。
【図面の簡単な説明】
【００７９】
【図１】従来の暗号化プログラム作成システムの処理を説明するための図である。
【図２】別の従来の暗号化プログラム作成システムの処理を説明するための図である。
【図３】保護対象のコード部分を暗号化した暗号化プログラムを作成するための暗号化実行プログラム作成システムの一実施例を示す図である。
【図４】図３のシステムが行う処理の流れを模式的に示した図である。
【図５】挿入関数の内容の一例を模式的に示す図である。
【図６】第１変換部の処理手順の例を示す図である。
【図７】第２変換部の処理手順の例を示す図である。
【図８】挿入関数の内容の別の例を模式的に示す図である。
【図９】多重的な暗号化の例を説明するための図である。
【図１０】多重的な暗号化の別の例を説明するための図である。
【図１１】挿入関数と対象関数との間での引数の引き渡し方式の一例を説明するための図である。
【図１２】挿入関数と対象関数との間での引数の引き渡し方式の別の一例を説明するための図である。
【図１３】ジャンプテーブルを介した関数呼び出しを考慮した場合の「変換２」の処理手順の例を示す図である。
【図１４】ジャンプテーブルを介した関数呼び出しを考慮した場合の「変換２」の処理手順の別の例を示す図である。
【図１５】デバッガ等のツールによるコード解析に対する対策のための挿入関数の例を示す図である。
【図１６】デバッガ等のツールによるコード解析に対する対策のための保護を施すためのシステムの例を示す図である。
【符号の説明】
【００８０】
３００  ソースコード、３０２  コンパイラ、３０４  オブジェクトコード、３０８  第１変換部、３１０  リンカ、３１２  第２変換部、３１４  暗号化実行コード。
【図１】
0004770425.tif 000002
【図２】
0004770425.tif 000003
【図３】
0004770425.tif 000004
【図４】
0004770425.tif 000005
【図５】
0004770425.tif 000006
【図６】
0004770425.tif 000007
【図７】
0004770425.tif 000008
【図８】
0004770425.tif 000009
【図９】
0004770425.tif 000010
【図１０】
0004770425.tif 000011
【図１１】
0004770425.tif 000012
【図１２】
0004770425.tif 000013
【図１３】
0004770425.tif 000014
【図１４】
0004770425.tif 000015
【図１５】
0004770425.tif 000016
【図１６】
0004770425.tif 000017