(57)【特許請求の範囲】
【請求項１】
処理対象プログラムの命令列を入力として計算した値に応じて自己書換えを行う自己書換えルーチンを生成する手段と、動的解析を妨げるアンチデバッギングルーチンおよび前記自己書換えルーチンを処理対象プログラムに追加する手段と、を備え、前記追加手段は、複数個の前記自己書換えルーチンが相互に依存し、かつ前記自己書換えルーチンが計算の入力として用いる処理対象プログラムの命令列の中に前記アンチデバッギングルーチンと自己書換え対象の命令が含まれるように追加することを特徴とする情報処理装置。
【請求項２】
前記自己書換えルーチン生成手段は、前記処理対象プログラムの特定の変数を自己書換えの対象とし、自己書き換えによって前記変数を予測困難な値に変更することを特徴とする、請求項１記載の情報処理装置。
【請求項３】
前記自己書換えルーチン生成手段が生成する自己書換えルーチンは、前記処理対象プログラムを測定して計算した値に応じて複数の自己書換えを行うことを特徴とする、請求項１あるいは請求項２記載の情報処理装置。
【請求項４】
コンピュータに処理対象のプログラムを耐タンパー化させるプログラムであって、コンピュータを、処理対象プログラムの命令列を入力として計算した値に応じて自己書換えを行う自己書換えルーチンを生成する手段と、動的解析を妨げるアンチデバッギングルーチンおよび前記自己書換えルーチンを処理対象プログラムに追加する手段と、として機能させ、前記追加手段は、複数個の前記自己書換えルーチンが相互に依存し、かつ前記自己書換えルーチンが計算の入力として用いる処理対象プログラムの命令列の中に前記アンチデバッギングルーチンと自己書換え対象の命令が含まれるように追加することを特徴とするプログラム。
【請求項５】
前記自己書換えルーチン生成手段は、前記処理対象プログラムの特定の変数を自己書換えの対象とし、自己書き換えによって前記変数を予測困難な値に変更することを特徴とする、請求項４記載のプログラム。
【請求項６】
前記自己書換えルーチン生成手段が生成する自己書換えルーチンは、前記処理対象プログラムを測定して計算した値に応じて複数の自己書換えを行うことを特徴とする、請求項４あるいは請求項５記載のプログラム。
【請求項７】
コンピュータが、処理対象プログラムの命令列を入力として計算した値に応じて自己書換えを行う自己書換えルーチンを生成する工程と、
前記コンピュータが、動的解析を妨げるアンチデバッギングルーチンおよび前記自己書換えルーチンを処理対象プログラムに追加する工程と、
を有し、
前記追加する工程においては、前記コンピュータが、複数個の前記自己書換えルーチンが相互に依存し、かつ前記自己書換えルーチンが計算の入力として用いる処理対象プログラムの命令列の中に前記アンチデバッギングルーチンと自己書換え対象の命令が含まれるように追加することを特徴とする情報処理方法。
【請求項８】
請求項４に記載のプログラムを格納したコンピュータ読み取り可能な記録媒体。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、情報処理装置およびその方法、プログラム、記録媒体に関し、特にプログラムの解析や改ざんを困難にする技術に関するものである。
【背景技術】
【０００２】
データの暗号化や認証、コンテンツの著作権保護を特別なハードウェアを必要とせず通常のハードウェアとソフトウェアだけで実現するために、解析や改ざんの困難なプログラムを作成する技術が求められている。そのような技術として、プログラム中の処理の出力値に応じて自己書換えを行うプログラムを作成する方法が特許文献１で提案されている。
【先行技術文献】
【特許文献】
【０００３】
【特許文献１】特開２００９−１０４５８９号公報
【発明の概要】
【発明が解決しようとする課題】
【０００４】
解析や改ざんが困難になるように処理を施すことを耐タンパー化と呼ぶ。特許文献１の耐タンパー化方法を複数回繰り返して耐タンパー化を施したプログラムを解析することを考える。複数回の耐タンパー化のそれぞれはお互いに独立なので、1回の耐タンパー化を無効化することを順番に繰り返すことによって複数回の処理全てが無効化されるという課題があった。
また、特許文献１の耐タンパー化方法は、プログラムを実行して解析を行う動的解析に対する耐性が明らかではないという課題があった。本発明は、上記問題に鑑みてなされたものであり、プログラムの解析や改ざんをさらに困難にすることが可能な技術を提供することを目的とする。
【課題を解決するための手段】
【０００５】
本発明によれば、処理対象プログラムの命令列を入力として計算した値に応じて自己書換えを行う自己書換えルーチンを生成する手段と、動的解析を妨げるアンチデバッギングルーチンおよび前記生成手段により生成される自己書換えルーチンを処理対象プログラムに追加する手段と、を備え、前記追加手段は、複数個の前記自己書換えルーチンが相互に依存し、かつ前記自己書換えルーチンが計算の入力として用いる処理対象プログラムの命令列の中に前記アンチデバッギングルーチンと自己書換え対象の命令が含まれるように追加することを特徴とする情報処理装置が提供される。
【０００６】
また、本発明によれば、コンピュータに処理対象のプログラムを耐タンパー化させるプログラムであって、コンピュータを、処理対象プログラムの命令列を入力として計算した値に応じて自己書換えを行う自己書換えルーチンを生成する手段と、動的解析を妨げるアンチデバッギングルーチンおよび前記生成手段により生成される自己書換えルーチンを処理対象プログラムに追加する手段と、として機能させ、前記追加手段は、複数個の前記自己書換えルーチンが相互に依存し、かつ前記自己書換えルーチンが計算の入力として用いる処理対象プログラムの命令列の中に前記アンチデバッギングルーチンと自己書換え対象の命令が含まれるように追加することを特徴とするプログラムが提供される。
【０００７】
また、本発明によれば、処理対象プログラムの命令列を入力として計算した値に応じて自己書換えを行う自己書換えルーチンを生成する工程と、動的解析を妨げるアンチデバッギングルーチンおよび前記生成手段により生成される自己書換えルーチンを処理対象プログラムに追加する工程と、を有し、前記追加工程は、複数個の前記自己書換えルーチンが相互に依存し、かつ前記自己書換えルーチンが計算の入力として用いる処理対象プログラムの命令列の中に前記アンチデバッギングルーチンと自己書換え対象の命令が含まれるように追加することを特徴とする情報処理方法が提供される。
【発明の効果】
【０００８】
本発明によれば、動的解析を妨げるアンチデバッギングルーチンを、処理対象プログラムの命令列を入力として計算した値に応じて自己書換えを行う自己書換えルーチン（
動的自己書換えによる命令偽装）で保護し、前記自己書換えルーチンは相互に依存するように構成される。この構成によって、動的解析の実行を困難にし、かつ、動的自己書換えによる命令偽装を静的解析で無効化する攻撃の成功確率を相互に依存しない場合の攻撃の成功確率よりも小さくでき、プログラムの解析や改ざんをさらに困難にすることが可能な技術を提供することができる。
【図面の簡単な説明】
【０００９】
【図１】自己インテグリティ相互依存検証の具体例のアセンブリプログラム。
【図２】コンピュータ装置の内部構成を示すブロック図。
【図３】動的自己書換えによる命令偽装1回を施す前のアセンブリプログラム。
【図４】動的自己書換えによる命令偽装1回を施した後のアセンブリプログラム。
【図５】動的自己書換えによる命令偽装アルゴリズムの入力と出力の関係。
【図６】アンチデバッギングルーチンの例。
【図７】自己インテグリティ相互依存検証の具体例の適用前のアセンブリプログラム（偽装2回の場合）。
【図８】自己インテグリティ相互依存検証の具体例の復帰ルーチン1の例。
【図９】自己インテグリティ相互依存検証の具体例のstep-3実施後のアセンブリプログラム（偽装2回の場合）。
【図１０】自己インテグリティ相互依存検証の具体例のstep-4実施中のアセンブリプログラム（偽装2回の場合）。
【図１１】自己インテグリティ相互依存検証の具体例のstep-4実施後のアセンブリプログラム（偽装2回の場合）。
【図１２】自己インテグリティ相互依存検証の一般化アルゴリズムの適用前のアセンブリプログラム。
【図１３】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-1実施後のアセンブリプログラム。
【図１４】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-3実施後のアセンブリプログラム。
【図１５】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-4実施中の場合1のアセンブリプログラム。
【図１６】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-4実施中の場合2のアセンブリプログラム。
【図１７】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-4の割り当て条件2の場合1のアセンブリプログラム。
【図１８】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-4の割り当て条件2の場合2のアセンブリプログラム。
【図１９】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-5実施中の場合1のアセンブリプログラム。
【図２０】自己インテグリティ相互依存検証の一般化アルゴリズムのstep-5実施中の場合2のアセンブリプログラム。
【図２１】自己インテグリティ相互依存検証の一般化アルゴリズムの実施後の場合1のアセンブリプログラム。
【図２２】自己インテグリティ相互依存検証の一般化アルゴリズムの実施後の場合2のアセンブリプログラム。
【図２３】耐タンパーソフトウェアの作成方法のフローチャート。
【図２４】タンパー応答機能の例。
【図２５】自己インテグリティ相互依存検証の具体例の適用前のアセンブリプログラム（偽装3回の場合）。
【図２６】自己インテグリティ相互依存検証の具体例のstep-1実施後のアセンブリプログラム（偽装3回の場合）。
【図２７】自己インテグリティ相互依存検証の具体例のstep-2の復帰ルーチンと隠蔽ルーチンの例（偽装3回の場合）。
【図２８】自己インテグリティ相互依存検証の具体例のstep-3実施後のアセンブリプログラム（偽装3回の場合）。
【図２９】自己インテグリティ相互依存検証の具体例のstep-4.1, step-4.2実施後のアセンブリプログラム（偽装3回の場合）。
【図３０】自己インテグリティ相互依存検証の具体例のstep-4.3実施後のアセンブリプログラム、ただし復帰ルーチンの相互依存のみ図示（偽装3回の場合）。
【図３１】自己インテグリティ相互依存検証の具体例のstep-4.3実施後のアセンブリプログラム、復帰ルーチンと隠蔽ルーチンの相互依存を図示（偽装3回の場合）。
【図３２】自己インテグリティ相互依存検証の具体例のstep-4.4実施後のアセンブリプログラム（偽装3回の場合）。
【図３３】自己インテグリティ相互依存検証の具体例のstep-5実施後のアセンブリプログラム、ただし第2の領域が確定した時点（偽装3回の場合）。
【図３４】自己インテグリティ相互依存検証の具体例のstep-5実施後のアセンブリプログラム、ただし第1の領域が確定した時点（偽装3回の場合）。
【図３５】自己インテグリティ相互依存検証の具体例のstep-5実施後のアセンブリプログラム、ただし第3の領域が確定した時点（偽装3回の場合）。
【図３６】自己インテグリティ相互依存検証の具体例のデジタル署名を適用後のアセンブリプログラム（偽装3回の場合）。
【発明を実施するための形態】
【００１０】
本発明では、プログラムの解析や改ざんを困難にするために、対象プログラムに最初にアンチデバッギング技術を実装する。次に、動的自己書換えによる命令偽装を複数回かつそれぞれが相互依存するように適用して、自己インテグリティ相互依存検証の構成を作成する。
以下、添付する図面を参照して、本発明に係る実施の形態を詳細に説明する。ただし、この実施の形態に記載されている構成要素はあくまでも例示であって、本発明の範囲をそれらのみに限定する趣旨のものではない。また、本実施の形態で説明されている特徴の組み合わせの全てが発明の解決手段に必須のものとは限らない。
【実施例１】
【００１１】
（コンピュータ装置の構成）
本実施形態におけるコンピュータ装置（情報処理装置）の内部構成について、図2を参照して説明する。図2は、コンピュータ装置の内部構成を示すブロック図である。この内部構成は、本明細書の全ての実施形態に共通とする。
図2に示されるように、コンピュータ装置200は、ネットワーク・インタフェース201、外部媒体読み書き装置202、CPU203、ROM204、RAM205、ハードディスク206を備える。また、電源207、指示入力装置インタフェース208、モニタ・インタフェース209、バス210等を備える。
【００１２】
ネットワーク・インタフェース201は、外部装置と通信するための通信インタフェースであり、例えば、LANインタフェース、無線LANインタフェース等によって実現される。外部媒体読み書き装置202は、外部媒体からデータを読み出すあるいは外部媒体にデータを書き込む装置である。外部媒体読み書き装置202がデータを読み書きする外部媒体には、例えば、CD-RやDVD、USB、メモリーカード等が含まれる。
【００１３】
CPU203は、コンピュータ装置200全体の動作を制御する中央演算処理装置である。ROM204は読み出し専用メモリであり、基本プログラム、基本データ等が格納されている。RAM205は書き込み可能メモリであり、CPU203による演算のワークエリア等として使用される。
【００１４】
ハードディスク（以下、HD）206は大容量の外部記憶装置であり、演算前後のデータ等が記憶される。電源（以下、POWER）207はコンピュータ装置200に電力を供給する。指示入力装置インタフェース208は指示入力装置とのインタフェースであり、ユーザは当該指示入力装置を介して指示命令を入力する。指示入力装置インタフェース208に接続される指示入力装置には、例えば、キーボード/ポインティングデバイス等の装置が含まれる。
【００１５】
モニタ・インタフェース209はモニタとのインタフェースであり、接続されたモニタに演算結果等を示す画面を出力する。バス210はコンピュータ装置200の構成要素間を接続し、信号を伝達する。
【００１６】
なお、コンピュータ装置200は、パーソナルコンピュータ（PC）やワークステーション（WS）、携帯情報端末（PDA）等により実現される。
【００１７】
以下の処理内容(手順)は、プログラム（ソフトウェア）もしくはモジュール（ハードウェア）として実現される。例えば、プログラムとして実現される場合は、そのプログラムはROM204もしくはHD206に格納され、そのプログラムをCPU203が読み込む。そして必要に応じてRAM205を計算のための空間（ワークエリア）として利用しながら、バス210を介してHD206に記録されたデータを読んだり、HD206にデータを書いたりして処理を実行する。
【００１８】
モジュールとして実現される場合は、プログラムによる動作と同等の動作を実行する実体が、例えばLSIとして実現され、コンピュータ装置200に組み込まれている。この場合、装置のCPU203からモジュール(LSI)へ指示が発行され、それを契機として各モジュールが動作し、処理を実行する。
【００１９】
以下、解析や改ざんを困難にするために、コンピュータ装置200に、処理対象のプログラムに対する耐タンパー化を施させるためのプログラムを、耐タンパー化プログラムと呼ぶ。耐タンパー化プログラムは、フレキシブルディスク、CD-ROM、DVD等の外部媒体から外部媒体読み書き装置202を経由してコンピュータ装置200にインストールすることにより、HD206に格納される。あるいは、ネットワーク・インタフェース201を経由してHD206に格納してもよい。
【００２０】
耐タンパー化を施す前の対象ソフトウェアをホストコードと呼び、アセンブリプログラムとする。高級言語（例えば、C）のソースプログラムを耐タンパー化するときは、それをコンパイルしてアセンブリプログラムを求め、そのアセンブリプログラムを対象として以下の手順を行う。
【００２１】
（動的自己書換えによる命令偽装）
最初に、動的自己書換えによる命令偽装を説明する。自己書換えとは、プログラムが自プログラムのコードを書換えることである。アセンブリプログラムで実現できる。Intel x86系CPUを想定し、アセンブリプログラムをAT&T表記で示す。自己書換え対象のアドレスにある値を書き込むアセンブリプログラムは、 mov を用いて、「mov 値, アドレス」と表現できる。例えば、「mov $0x74, (%eax)」は、レジスタ eax に格納されているアドレスに値0x74（16進数の74）を書き込む。
【００２２】
改ざんを検出するために、自プログラムのコードを対象にしてチェックサム（あるいは暗号的ハッシュ値）を計算し、あらかじめ計算して埋め込んである参照値と比較して、改ざんの有無を実行時に自分で確認する処理を自己インテグリティ検証と呼ぶ。チェックサムあるいは暗号的ハッシュ値を求める関数は暗号的ハッシュ関数でなくてもよい。
【００２３】
動的自己書換えによる命令偽装では、自己書換えの対象アドレスが、自己インテグリティ検証によって保護対象を測定して計算される値（以下、ハッシュ値）に依存して決まるように構成し、自己書換え対象の命令を別命令に偽装しておく。
【００２４】
このように構成されたプログラムは、実行時に、保護対象を測定してハッシュ値を計算する。改ざんされていないときはハッシュ値が偽装命令のアドレスになるため偽装された命令が自己書換えによって本来の命令に戻され、それが実行される。改ざんが行われるとハッシュ値は偽装命令のアドレスとは別の値になるため、自己書換えによって偽装命令とは別の命令が書換えられ偽装命令はそのまま残り、偽装命令と書換えられた別の命令が実行される。
【００２５】
図3のプログラムに動的自己書換えによる命令偽装を1回適用した例が図4である。保護領域（図3の「cmpl $1, -8(%ebp)」と「je L9」）の中の一つの命令「je L9」が「jne L9」に偽装され、偽装命令を本来の命令に自己書換えする復帰ルーチン（Restroring Routine）と、本来の命令を偽装命令に自己書換えする隠蔽ルーチン（Hiding Routine）が偽装命令の前後にそれぞれ追加される。図4には示されていないがハッシュ関数ルーチン _hash も追加される。
【００２６】
動的自己書換えによる命令偽装の作成手順および自己インテグリティ相互依存検証の作成手順の入出力の関係を図5に示す。耐タンパー化したいアセンブリプログラムP_inと、偽装対象の命令と偽装命令を入力として、耐タンパー化されたアセンブリプログラムP_outが出力される。動的自己書換えによる命令偽装の作成手順および自己インテグリティ相互依存検証の作成手順の詳細は後述する。
【００２７】
図4のプログラムが実行されると、復帰ルーチンが実行される。最初に保護領域のハッシュ値が計算され（最初の6行）、次にそのハッシュ値に応じて自己書換え対象のアドレスが計算され（7〜9行目）、最後に自己書換え命令「movb $0x74, (%eax)」（10行目）が実行される。保護領域に改ざんが検出されないときは偽装命令「jne L9」が本来の命令「je L9」に書換えられ、本来の命令「je L9」が実行され、その後隠蔽ルーチンが実行され「je L9」が「jne L9」に再偽装される。改ざんが検出されるときはハッシュ値が異なるため偽装命令の先頭アドレスではないアドレスが自己書換えされるので、「jne」はそのままで他のランダムなアドレスが「0x74」に書換えられる。
【００２８】
命令の一部が別の値に書換えられると、そのアドレス以降のいくつかの命令は本来とは異なる命令に変化する。命令の区切りが影響を受けることもあり、その場合は以降の処理は本来とは異なる処理になり仕様通りに動作しない可能性が高い。例えば、命令の種類やデータの値が変わり計算が誤って行われ動作は続くがバグが発生する、あるいは不正なメモリアクセスが発生してエラー終了する等の非正常動作が起こる。
【００２９】
つまり、改変が検出されると自己書換えが正しく行われず、高い確率で二つ以上の命令が本来とは異なる命令になり、バグやエラーを含む、仕様とは異なる動作を動的に発生して攻撃者の解析と改変を妨げる。このタンパー応答の仕組みによって保護領域は改変から保護される。
【００３０】
（自己インテグリティ相互依存検証の具体例）
本実施例では、改ざんから保護したいプログラム（ホストコード）にアンチデバッギング技術を適用してプログラム実行型解析を妨げる。アンチデバッギング技術は、デバッガ等のツールを用いて行われるプログラム実行型解析，いわゆる動的解析を妨げる技術の総称である。
【００３１】
例えば、デバッグレジスタを参照して特定の値を得たとき、あるいはプログラムのある処理の実行にかかった時間が所定の値以上のときはデバッガが存在すると判断してプログラムの実行を停止する、CPUの仕様を活用してハードウェアブレークポイントを設定できない位置で関数呼び出しを実行する等の手法である。デバッグレジスタ（db7）を参照して特定の値（0x400）を得たときに、デバッガが存在すると判断して、その際に行う処理（DebuggerDetected というラベルが指し示すアドレスにジャンプし，そこに記載されている処理）を実行するルーチンのアセンブリプログラム例を図6に示す．
【００３２】
アンチデバッギング技術を適用する場合、ホストコードを改ざんから保護するだけでなく、アンチデバッギング技術を実装したルーチンも改ざんから保護する必要がある。動的自己書換えによる命令偽装でホストコードとアンチデバッギングルーチンを保護する場合は、動的自己書換えによる命令偽装を実装したルーチンも改ざんから保護する必要がある。従来の耐タンパー化では、複数回の耐タンパー化のそれぞれはお互いに独立なので、1回の耐タンパー化を無効化することを順番に繰り返すことによって複数回の処理全てが無効化されるという課題があった。
【００３３】
ホストコードとアンチデバッギングルーチンを保護するために動的自己書換えによる命令偽装を複数回適用し、複数の動的自己書換えによる命令偽装が相互に依存するように構成することによって、攻撃者が一箇所を無効化するだけでは改ざんに成功しないようにできる。攻撃者は、複数回の相互依存する動的自己書換えによる命令偽装を全て同時に無効化することができれば改ざんに成功するが、その成功確率は従来の耐タンパー化より小さい。
【００３４】
このような構成およびその構成を作成する方法を、自己インテグリティ相互依存検証と呼ぶ。図1は、図7のアセンブリプログラムに動的自己書き換えによる命令偽装を2回適用して構成した自己インテグリティ相互依存検証の具体例である。
【００３５】
図1では1番目の領域（1st area）の途中にマスク mask-2 が位置するように見えるが、マシン語プログラムでは4011af行の後半にマスク mask-2が位置するので1番目の領域は連続した領域である。2番目の領域（2nd area）についても同様である。また、図1では隠蔽ルーチン2のマスク以降の領域は保護されていないが、後述するように復帰ルーチンと隠蔽ルーチンの組が3組以上の場合はマスクより後ろの領域も保護できる。図7、図1では、偽装対象の命令1は je、偽装命令1は jne、偽装対象の命令2は addl、偽装命令2は xorl である。
【００３６】
自己インテグリティ相互依存検証を作成する手順を、図7、図8、図9、図10、図11、図1を参照しながら説明する。耐タンパー化したいアセンブリプログラムP_inと、2組の偽装対象の命令と偽装命令の組を入力として、以下の手順を実行すると、耐タンパー化されたアセンブリプログラムP_outが作成される。
【００３７】
（step-1）偽装命令に置換する。
P_inの偽装対象の命令それぞれを対応する偽装命令に置換する。 図7の「je L9」が「jne L9」に、「addl $40, (%eax)」が「xorl $40, (%eax)」に置換される。
【００３８】
（step-2）復帰ルーチンと隠蔽ルーチンを生成する。
復帰ルーチン1、2と隠蔽ルーチン1、2のコードを以下のように生成する。
【００３９】
偽装対象の命令における自己書き換え対象のアドレスをsmaddress、smaddressを間接的に求めるために用いるアドレスをbaseとする。 baseは、ホストコードが使用するラベルからランダムに選ぶ、あるいはホストコード上のランダムなアドレスに宣言したラベルを用いる。偽装対象の命令の直前にラベルを宣言するとそのアドレスが即値としてマシン語プログラムに現れるため、攻撃者が偽装命令を見つける手がかりになるので、そのようなラベルは使わない。
【００４０】
図1の復帰ルーチン1ではホストコードのL10をbaseとしている。ハッシュ値hvと自己書換え対象アドレスsmaddressとbaseの3つの変数は任意の値を取りえるため、それらを関連づけるマスクmaskを定義する。
【００４１】
それら4変数の関係は、例えば、関数fと加減算を用いて
smaddress-base=f(hv)+mask
と定義できる。
【００４２】
関数fは、ハッシュ関数の出力をアドレスのビット長以下のビット長のデータに変換する関数（例えば、256ビットのhvを8ビットのブロック32個に分割し、その一つのブロックを出力する関数）である。以降では説明を簡単にするため、hvのビット長はアドレスのビット長以下、f(x)=xと仮定する。
【００４３】
マスクの値は、hvと、復帰ルーチンと隠蔽ルーチンが挿入されbaseとsmaddressの相対距離が確定した後に決定される。コード生成時には未確定なので、取りえる最大値のデータ領域を占める仮値を指定して復帰ルーチンのコードに含めておく。例えば、32ビットアドレス空間ならば32ビットを要する値 0x12345678 を仮値とする。
【００４４】
最初に、保護領域の先頭アドレスと長さを入力とするハッシュ関数ルーチン_hashを呼んでハッシュ値hvを求めるコードを生成する。保護領域の先頭アドレス、長さはこの時点では未確定なので、マスクと同様に仮値を指定する。ハッシュ関数ルーチン_hashは、レジスタebxに長さが、レジスタeaxに先頭アドレスが指定される仕様なので、それぞれに仮値を指定したコードを生成する。
【００４５】
次に、「smaddress=base+hv+mask」を求めるコードを生成する。ハッシュ関数ルーチン_hashは、その関数呼び出しから戻ってきたときにレジスタedxにハッシュ値hvが格納されている仕様なので、
movl  $L10,        %eax
addl  %edx,        %eax
subl  $0x12345678, %eax
を生成する。L10のアドレスの方がsmaddressより大きい（L10の方が下にある）ためマスクが負の値になることを考慮してsublを使っている。レジスタeaxを使ってsmaddressが計算されるので、ハッシュ値も偽装対象の命令のアドレスも即値としてプログラムに現れない。
【００４６】
最後に、smaddressのデータを偽装対象の命令のマシン語に書換えるコードを生成する。偽装対象の命令と偽装命令の差分が先頭1バイトだけのときは、「movb  $0x74,  (%eax)」を生成する。偽装対象の命令と偽装命令の差分が1バイトよりも大きい場合は、例えば4バイト（32ビット）の場合は、movbの代わりにmovlを、0x74の代わりに4バイトの値（偽装対象の命令のマシン語）を指定する。
【００４７】
以上のコードが復帰ルーチン1を構成する。このようにして生成した復帰ルーチン1を図8に示す。同様の処理を行って復帰ルーチン2、隠蔽ルーチン1、2を生成する。
【００４８】
各隠蔽ルーチンは対応する復帰ルーチンと同じコードにならないように、例えば、マスクの定義式、ラベル、用いる命令等を変えて処理を行う。図4では、隠蔽ルーチンの自己書換え命令にaddbが用いられ、復帰ルーチンのmovbと異なっている。
【００４９】
隠蔽ルーチンは偽装対象の命令の実行後に実行されるので、復帰ルーチンのように改変検出時に本来と異なる処理を発生させるわけではない。従って、提案方法の必須機能ではないため省略してもよい。しかし、隠蔽ルーチンは、その実行後の時点におけるスナップショット（メモリにロードされている標的プログラムの内容）を攻撃者が入手しても、それから本来の命令を突き止められることを防ぐ。それに加えて、ある改変の検出時に隠蔽ルーチンがランダムに自己書換えする命令が他の復帰ルーチンの保護領域に含まれる場合は別の改変および仕様とは異なる動作を発生させる。従って、仕様とは異なる動作を発生させる確率を復帰ルーチンのみの場合より高められる。
【００５０】
（step-3）復帰ルーチンと隠蔽ルーチンを挿入する。
「偽装命令が実行される前に必ず偽装対象の命令に書換えられ、プログラム終了前に必ず元通り偽装命令に書換えられる」ことが保障されるように、復帰ルーチン1、2と隠蔽ルーチン1、2それぞれを、それぞれの挿入可能区間からランダムに選んだ位置に挿入する。
【００５１】
復帰ルーチン1の挿入可能区間は、P_inの開始から偽装命令1までの制御フロー上であり、かつ隠蔽ルーチン1から偽装命令1までの制御フロー上であり、かつ隠蔽ルーチン1からP_inの終了までの制御フロー上ではないという条件を満たす位置である。
【００５２】
隠蔽ルーチン1の挿入可能区間は、偽装命令1からP_inの終了までの制御フロー上であり、かつ復帰ルーチン1から偽装命令1までの制御フロー上ではないという条件を満たす位置である。復帰ルーチン2と偽装命令2と隠蔽ルーチン2についても同様である。
【００５３】
改変が検出されたときにランダムに書換えられる命令が実行されるためには、復帰ルーチンの自己書換え命令のアドレスと書換え対象のアドレスとの差がf(hv)の最大値よりも大きくなるように自己書換え命令の挿入位置を選ぶ。図9のように復帰ルーチン1、2と隠蔽ルーチン1、2のコードが挿入されたと仮定する。
【００５４】
（step-4）保護領域の先頭アドレスと長さを設定する。
復帰ルーチン1と、復帰ルーチン2のマスク（mask-2）直前までを含む範囲を1番目の領域と定め、復帰ルーチン2と隠蔽ルーチン2の保護領域に割り当てる。1番目の領域は、復帰ルーチン1よりも上の命令を含むことができる。
【００５５】
復帰ルーチン2のマスク（mask-2）直後を先頭とし、隠蔽ルーチン2のマスク直前までを含む範囲を2番目の領域と定め、復帰ルーチン1と隠蔽ルーチン1の保護領域に割り当てる。
【００５６】
P_inをアセンブルしてマシン語プログラムを求める。マシン語プログラムを逆アセンブルして、1番目の領域と2番目の領域のアセンブリプログラムに対応するマシン語プログラムをそれぞれ特定して、それぞれの先頭アドレスと長さを求める。それらの値をP_inの仮値と入れ替える。
【００５７】
入れ替えた結果のプログラムを図11に示す。1番目の領域の先頭アドレスは0x4010ad、長さは0x102、2番目の領域の先頭アドレスは0x4011b4、長さは0x40であり、step-2で設定した仮値とそれぞれ入れ替えられている。
【００５８】
（step-5）マスク値を求めて設定する。
step-4で確定した2番目の領域のマシン語プログラム（バイナリデータ）を入力としてハッシュ関数を計算して、復帰ルーチン1と隠蔽ルーチン1が実行時に計算するハッシュ値hvを求める。
【００５９】
ただし、復帰ルーチン2の実行後かつ隠蔽ルーチン2の実行前に復帰ルーチン1が実行される場合は、2番目の領域内の偽装命令2が本来の命令に戻っている状態で復帰ルーチン1がハッシュ関数を計算するので、ハッシュ関数に入力するバイナリデータの偽装命令2のマシン語を本来の命令のマシン語に置換したデータを入力としてハッシュ値hvを求める。隠蔽ルーチン1についても同様である。
【００６０】
次に、step-4で求めた逆アセンブル結果からbaseとsmaddressの値を求め、それらとhvの値を式「smaddress-base=f(hv)+mask」に代入してmaskの値を求める。それをP_in内の仮値と入れ替える。
【００６１】
図11の復帰ルーチン1では、求めたマスクの値が-0x52であり、コードにsublが指定されているので、符号を反転した0x00000052のマシン語をmask-1の仮値0x12345678のマシン語と入れ替える。同様にして隠蔽ルーチン1のマスク値を求め、仮値と入れ替える。1番目の領域のマシン語プログラムが確定したので、それを入力として復帰ルーチン2と隠蔽ルーチン2が実行時に計算するハッシュ値を求める。
【００６２】
復帰ルーチン2の実行時に1番目の領域内の偽装命令1が本来の命令に戻っている場合はハッシュ関数に入力するバイナリデータの偽装命令1のマシン語を本来の命令のマシン語に置換したデータを入力としてハッシュ値を求める。隠蔽ルーチン2についても同様である。
【００６３】
求めたハッシュ値を用いて復帰ルーチン2と隠蔽ルーチン2のそれぞれのマスクの値を計算し、P_inの仮値とそれぞれ入れ替える。以上の処理を施したP_inをP_outとして出力する。図1のプログラムがP_outに相当する。（end）
【００６４】
図1では、説明を簡単にするため保護領域の先頭アドレスや長さ、偽装対象の命令のマシン語を即値として表現している。即値としてプログラムに含めると、それらをプログラム非実行型解析の手がかりにされる可能性がある。これらの定数を直接コードに含めて（即値として）使うことを避け、ランダムなラベルとマスクを用いて間接的にsmaddressを求めたように、ある定数を用いてレジスタ内で計算した値を使うようにすれば、解析を困難にできる。
【００６５】
例えば、復帰ルーチン1の2行目のmovl $0x4011b4, %eaxの代わりに、アドレス0x4011b4より0x8cバイト下のアドレスにラベルL13が存在する場合、それを定数として
movl $L13,  %eax
subl $0x8c, %eax
とできる。そのような定数として、実行時のある特定の期間に特定の値となるホストコードの変数を採用すれば、解析はさらに困難になる。
【００６６】
以上の自己インテグリティ相互依存検証の具体例では、復帰ルーチンと偽装命令と隠蔽ルーチンの三つ組が2個重ならずに配置されていたが、一般にそのような構造になるとは限らない。また、上述の動的自己書換えによる命令偽装を2回適用する場合は、ホストコードの隠蔽ルーチン2のマスク値以降は保護されない。
【００６７】
動的自己書換えによる命令偽装を3回適用する場合であって、復帰ルーチンと偽装命令と隠蔽ルーチンの三つ組が順不同であり、ホストコードの全てを保護する例を説明する。
【００６８】
自己インテグリティ相互依存検証を作成する手順を、図25、図26、図27、図28、図29、図30、図31、図32、図33、図34、図35、図36を参照しながら説明する。耐タンパー化したいアセンブリプログラムP_inと、2組の偽装対象の命令と偽装命令の組を入力として、以下の手順を実行すると、耐タンパー化されたアセンブリプログラムP_outが作成される。
【００６９】
（step-1）偽装命令に置換する。
P_inの偽装対象の命令それぞれを対応する偽装命令に置換する。 図25の「incl (%eax)」が「decl (%eax)」に、「je L8」が「jne L8」に置換される。偽装対象の命令3と偽装命令3は明示していないが、同様に置換される。図26は、置換された結果のアセンブリプログラムである。
【００７０】
（step-2）復帰ルーチンと隠蔽ルーチンを生成する。
復帰ルーチン1、2、3と隠蔽ルーチン1、2、3のコードを前述と同様の方法に従い、maskとbaseとsmaddressとhvを用いて生成する。生成されたコードのマスクの値および保護領域の先頭アドレスと長さには仮値を指定しておく。図27は、生成された復帰ルーチンと隠蔽ルーチンを示す、ただし復帰ルーチン3と隠蔽ルーチン3と隠蔽ルーチン1のコードは省略してある。
【００７１】
（step-3）復帰ルーチンと隠蔽ルーチンを挿入する。
「偽装命令が実行される前に必ず偽装対象の命令に書換えられ、プログラム終了前に必ず元通り偽装命令に書換えられる」ことが保障されるように、復帰ルーチン1、2、3と隠蔽ルーチン1、2、3それぞれを、それぞれの挿入可能区間からランダムに選んだ位置に挿入する。
【００７２】
復帰ルーチン1の挿入可能区間は、P_inの開始から偽装命令1までの制御フロー上であり、かつ隠蔽ルーチン1から偽装命令1までの制御フロー上であり、かつ隠蔽ルーチン1からP_inの終了までの制御フロー上ではないという条件を満たす位置である。
【００７３】
隠蔽ルーチン1の挿入可能区間は、偽装命令1からP_inの終了までの制御フロー上であり、かつ復帰ルーチン1から偽装命令1までの制御フロー上ではないという条件を満たす位置である。復帰ルーチン2と偽装命令2と隠蔽ルーチン2、復帰ルーチン3と偽装命令3と隠蔽ルーチン3についても同様である。挿入した結果、図28のアセンブリプログラムになったとする。
【００７４】
（step-4）保護領域の先頭アドレスと長さを設定する。
（step-4.1）復帰ルーチンを任意に1個選ぶ。中間に位置する復帰ルーチン2を選ぶ。
【００７５】
（step-4.2）ホストコードを3個の領域に分割する。復帰ルーチン1と、復帰ルーチン2のマスク直前までを含む範囲を1番目の領域と定める。復帰ルーチン2のマスクの直後を先頭とし、隠蔽ルーチン2のマスク直前までを含む範囲を2番目の領域と定める。隠蔽ルーチン2のマスクの直後を先頭とし、ホストコードの一番最後（図29の最下部）までを含む範囲を3番目の領域と定める。図29に1番目の領域、2番目の領域、3番目の領域を太線で図示する。
【００７６】
（step-4.3）循環する相互依存の順序を決定する。復帰ルーチン1に2番目の領域を割り当てる。復帰ルーチン2に3番目の領域を割り当てる。復帰ルーチン3に1番目の領域を割り当てる。図30は、左側の矢印で復帰ルーチンへの割り当てを示したアセンブリプログラムである。
【００７７】
隠蔽ルーチン1に1番目の領域を割り当てる。隠蔽ルーチン2に3番目の領域を割り当てる。隠蔽ルーチン3に1番目の領域を割り当てる。図31は、左側の矢印で復帰ルーチンへの割り当てと隠蔽ルーチンへの割り当てを全て示して相互依存の順序を図示したアセンブリプログラムである。
【００７８】
（step-4.3）P_inをアセンブルしてマシン語プログラムを求める。マシン語プログラムを逆アセンブルして、1番目の領域と2番目の領域と3番目の領域のアセンブリプログラムに対応するマシン語プログラムをそれぞれ特定して、それぞれの先頭アドレスと長さを求める。それらの値をP_inの仮値と入れ替える。図32は、復帰ルーチン1、2、3と隠蔽ルーチン1、2、3の先頭アドレスと長さを特定した値に入れ替えたアセンブリプログラムである。
【００７９】
（step-5）マスク値を求めて設定する。
step-4で確定した2番目の領域のマシン語プログラム（バイナリデータ）を入力としてハッシュ関数を計算して、復帰ルーチン1が実行時に計算するハッシュ値hvを求める。求めたhvの値を式「smaddress-base=f(hv)+mask」に代入してmaskの値を求める。それをP_in内の仮値と入れ替える。図33は、復帰ルーチン1が2番目の領域を入力とすることを破線の矢印で示し、求めたmaskが0xe4であることを太い四角で示している。
【００８０】
その結果、1番目の領域が確定する。次は、1番目の領域を入力としてハッシュ関数を計算する隠蔽ルーチン1と復帰ルーチン3と隠蔽ルーチン3について、ハッシュ値を求め、maskを求める。
【００８１】
この例では、復帰ルーチン1の実行後かつ復帰ルーチン3の実行前に隠蔽ルーチン1が実行されるので、1番目の領域内の偽装命令2が本来の命令に戻っている状態で隠蔽ルーチン1がハッシュ関数を計算するので、ハッシュ関数に入力するバイナリデータの偽装命令1のマシン語を本来の命令のマシン語に置換したデータを入力としてハッシュ値hvを求めることに注意する。復帰ルーチン3と隠蔽ルーチン3がハッシュ関数に入力するときは偽装命令1に戻っているので、偽装命令1を含む1番目の領域を入力データとしてハッシュ値を求める。図34は、太い四角で示されたmaskが仮値から入れ替えられた状態を示す。
【００８２】
その結果、3番目の領域が確定する。3番目の領域を入力としてハッシュ関数を計算する復帰ルーチン1と復帰ルーチン2について、ハッシュ値を求め、maskを求める。図35は、太い四角で示されたmaskが仮値から入れ替えられた状態を示す。この2つのmaskは、ハッシュ関数の入力に含まれないことに注意する。
【００８３】
最後に入れ替えられた2つのmaskを保護するために、デジタル署名を適用することができる。図36を参照しながら、その方法を説明する。
【００８４】
最後に置換される2箇所のマスク値を含む領域を署名対象（Area for Signature）とし、オブジェクトプログラムのデータ領域に格納された署名データ（Signature Data）と
署名対象とが対応するか否かを検証して対応しないときはプログラムを中断するディジタル署名検証ルーチンと署名検証鍵（Signature Verification Routine and Key）を保護領域の中に実装する。この実装は、step-1のときに行う。
【００８５】
このように実装したプログラム、ただし、署名データには仮値を入れておく、を入力として上述の作成方法を適用する。
【００８６】
作成されたマシン語プログラムP_outに対して、最後に置換された2箇所のマスク値を含む領域を署名対象として署名生成鍵を用いてディジタル署名を生成し、その署名データをP_outのデータ領域の仮値と置換する。署名生成鍵は、秘密かつ安全に保管あるいは廃棄する。用いるディジタル署名方式が安全であり、かつ署名生成鍵が攻撃者に知られないならば、攻撃者は署名を偽造できない。
【００８７】
以上の処理を施したP_inをP_outとして出力する。図36のプログラムがP_outに相当する。（end）
【００８８】
作成方法を拡張し、動的自己書換えによる命令偽装をn（nは3以上の整数）回適用して自己インテグリティ相互依存検証の一般的構成を作成する方法を、図11を参照しながら説明する。
【００８９】
（自己インテグリティ相互依存検証の一般的アルゴリズム）
耐タンパー化したいアセンブリプログラムP_inと、n組の偽装対象の命令と偽装命令の組を入力として、以下の手順を実行すると、耐タンパー化されたアセンブリプログラムP_outが作成される。
【００９０】
（step-1）偽装命令に置換する。
図12のプログラムの偽装対象の命令が偽装命令に置換され図13のプログラムになる。ディジタル署名検証ルーチンと署名検証鍵（Signature Verification Routine and Key）を保護領域の中に実装する。図13では、ディジタル署名検証ルーチンと署名検証鍵と仮値を入れた署名データは省略している。
【００９１】
（step-2）復帰ルーチンと隠蔽ルーチンを生成する。
プログラムPのオブジェクトファイル内の、あるいは実行時にPが格納されるメモリ内の、Pの命令列（コード）を含む領域をコードセグメントと呼ぶ。コードセグメントにおいてn個の偽装命令を上（アドレスの低い方）から順に偽装命令1、偽装命令2、．．．、偽装命令nと呼び、偽装命令i （iは1以上n以下の整数）とその本来の命令を自己書換えする復帰ルーチンと隠蔽ルーチンをそれぞれ復帰ルーチンi、隠蔽ルーチンiと呼ぶ。 
【００９２】
P_inの各復帰ルーチンと隠蔽ルーチンの保護領域の先頭アドレスと長さおよびマスクに仮値を指定して、n個の復帰ルーチンとn個の隠蔽ルーチンを生成する。
【００９３】
（step-3）復帰ルーチンと隠蔽ルーチンを挿入する。
各復帰ルーチンと隠蔽ルーチンを、その制御フローにおける挿入可能区間の中からランダムに選んだ位置に挿入する。その結果、上からi番目の復帰ルーチンが復帰ルーチンiとは限らず、隠蔽ルーチンについても同様であり、復帰ルーチンと偽装命令と隠蔽ルーチンのそれぞれが連続することもありうる。図14のような配置になったと仮定する。
【００９４】
（step-4）保護領域と循環の順序を定め、先頭アドレスと長さを設定する。
コードセグメントをn個の領域に分割する。上から順にそれぞれi（＝1、2、．．．、n）番目の領域と呼ぶ。
【００９５】
復帰ルーチンをランダムに1個選ぶ。j番目（j≠1、j≠n）とする。上から1番目を選ぶとその復帰ルーチンのマスク直前までが保護されなくなり偽装解除攻撃の成功可能性を高めることになるので、選ばない。上からn番目を選ぶと隠蔽ルーチンnのマスク以降が保護されなくなる。
【００９６】
j-1とjとj+1番目の領域を除き、以下の条件を満たすように分割する。
（分割条件1）各領域は復帰ルーチンを1個だけ完全に含む。（後述の割当条件3で述べる数珠繋ぎ状の構成にするため）。なお、ある領域があるルーチンを完全に含むとは、1個の領域がそのルーチンの全てを含み、そのルーチンが複数の領域にまたがることがないことである。
（分割条件2）1個の領域は隠蔽ルーチンを0個以上完全に含む。
（分割条件3）分割条件1と2を満たし可能な限り多くの領域が偽装命令を含むように、各領域が重ならず連続するように境界をランダムに定める。
【００９７】
j-1番目の領域は、j-2番目の領域との接する境界をランダムに定め、j-1番目の復帰ルーチンを完全に含み、j番目の復帰ルーチンのマスク直前までを含む。j番目とj+1番目の領域は、次の2つの場合で異なる。
（場合1）j番目の復帰ルーチンとj+1番目の復帰ルーチンとの間に隠蔽ルーチンが1個以上存在するとき、その1番上のものを隠蔽ルーチンαとして、j番目の復帰ルーチンのマスク直後から隠蔽ルーチンαのマスク直前までをj番目の領域とし、隠蔽ルーチンαのマスク直後から、j+1番目の復帰ルーチンを含み、j+2番目の領域の直前までをj+1番目の領域とする。図15のプログラムが、場合1に相当する。
（場合2）j番目とj+1番目の復帰ルーチンとの間に隠蔽ルーチンが1個も存在しない場合は、j番目の復帰ルーチンのマスク直後からj+1番目の領域の直前まで（境界はランダムに定める）をj番目の領域とし、j+1番目の領域はj+1番目の復帰ルーチンを完全に含み、分割条件1と2と3を満たす。図16のプログラムが、場合2に相当する。
【００９８】
次に、相互依存の循環順序を以下の条件を満たすように定める。1個の領域に含まれる復帰ルーチンと隠蔽ルーチンを自己書換えルーチンセットと呼ぶ。例えば、図15では、i番目の領域に含まれるi番目の復帰ルーチン（i-th RR）と隠蔽ルーチンb（HR-b）と隠蔽ルーチンd（HR-d）が自己書換えルーチンセットである。
（割当条件1）j-1とjとj+1番目の領域を除き、ある自己書換えルーチンセットに含まれる復帰ルーチンと隠蔽ルーチンは同じ領域を保護領域とする。
（割当条件2）j-1番目の復帰ルーチンとj番目の復帰ルーチンの保護領域は異なる。j番目の領域に隠蔽ルーチンαが含まれるとき、j番目の復帰ルーチンと隠蔽ルーチンαは同じ領域を保護領域とし、隠蔽ルーチンαとj+1番目の復帰ルーチンの保護領域は異なる。場合1にこの割当条件2を適用した例を図17に，場合2に割当条件2を適用した例を図18に示す。
（割当条件3）n個の領域それぞれは別の領域1個の自己書換えルーチンセットの保護対象に割り当てられ、各自己書換えルーチンセットはそれが含まれる領域ではない領域1個を保護対象とし、n個の領域の保護（依存）関係が数珠繋ぎ状の循環を形成する。
【００９９】
例えば、1番目の領域が2番目の領域を保護し、2番目が3番目を保護し、．．．、n番目が1番目を保護する。
【０１００】
次に、P_inをアセンブルしてマシン語プログラムを求め、それを逆アセンブルして各領域の先頭アドレスと長さを求める。P_inの各復帰ルーチン、隠蔽ルーチンの保護領域の先頭アドレスと長さの仮値を割り当てに応じてそれぞれ入れ替える。
【０１０１】
（step-5）マスク値を求めて設定する。
P_inの各復帰ルーチンと隠蔽ルーチンについて、以下の順序でそれぞれの保護領域のstep-4で確定したマシン語プログラムを入力としてハッシュ値を求め、それを用いてマスクの値を求め、P_inの対応する仮値とそれぞれ入れ替える。
【０１０２】
1番目に、j番目の領域を保護領域とする自己書換えルーチンセットのハッシュ値とマスク値を定め、それらのマスク値を仮値と置換する。2番目に、1番目にマスク値が定められた自己書換えルーチンセットを含む領域を保護領域とする自己書換えルーチンセットのハッシュ値とマスク値を定め、それらのマスク値を仮値と置換する。3番目に、2番目にマスク値が定められた自己書換えルーチンセットを含む領域を保護領域とする自己書換えルーチンセットのハッシュ値とマスク値を定め、それらのマスク値を仮値と置換する。以上の手順を繰り返し、n番目に、j番目の自己書換えルーチンセット（の復帰ルーチンと存在する場合は隠蔽ルーチンα）のハッシュ値とマスク値を定め、それらのマスク値を仮値と置換する。
【０１０３】
場合1のときを図19を参照して説明する．図19では、1番目に、i番目の領域を保護領域とする自己書換えルーチンセット、つまり、i番目の復帰ルーチン（i-th RR）と隠蔽ルーチンb（HR-b）と隠蔽ルーチンd（HR-d）のハッシュ値とマスク値をそれぞれ求め、それらのマスク値を仮値と置換する。2番目に、i番目の領域を保護対象とする自己書換えルーチンセット（図示せず）のハッシュ値とマスク値をそれぞれ求め、それらのマスク値を仮値と置換する。場合2のときを図20に示す．
【０１０４】
ただし、各復帰ルーチンと隠蔽ルーチンがハッシュ値を実行時に計算するときに保護領域に含まれる偽装命令が本来の命令に戻っている場合は、ハッシュ関数に入力するバイナリデータの偽装命令のマシン語を本来の命令のマシン語に置換したデータを入力としてハッシュ値を求める。
【０１０５】
保護領域に含まれる偽装命令が本来の命令に戻っているか否かは次のように決める。ある自己書換えルーチンセットの復帰ルーチンと隠蔽ルーチンのそれぞれをR_i、R_iの保護領域に含まれる偽装命令を偽装命令k、偽装命令kを自己書換えする復帰ルーチンkと隠蔽ルーチンkをそれぞれRR_kとHR_kとして、R_iとRR_kとHR_kの実行順序を比較する。R_iが実行される時刻をt(R_i)とすると、t(RR_k) < t(R_i) < t(HR_k)の場合は偽装命令kは本来の命令に戻っている、そうでない場合は偽装命令kである。
【０１０６】
R_iの全てと、RR_kとHR_kの全てとに対して、実行順序比較を行って、ハッシュ関数に入力するバイナリデータを定めてハッシュ値を求める。実行順序の比較結果が条件に応じて変わる場合は、step-3に戻り復帰ルーチンkと隠蔽ルーチンkの挿入位置を変更してアルゴリズムを繰り返す。
【０１０７】
変更後も実行順序の比較結果が定まらない場合は、step-1に戻り偽装命令kを別の命令に変更してアルゴリズムを繰り返す。
【０１０８】
以上の処理を施したP_inをP_outとして出力する。場合1のときは図21のプログラムがP_outに相当し、場合2のときは図22のプログラムがP_outに相当する。（end）
【０１０９】
（耐タンパーソフトウェアの作成方法）
本発明の耐タンパーソフトウェアの作成方法を説明する。最初にホストコードにアンチデバッギング技術を実装して、次に自己インテグリティ相互依存検証の一般的アルゴリズムを適用する。耐タンパー化したいアセンブリプログラムP_inを入力として、以下の手順を実行すると、耐タンパー化されたアセンブリプログラムP_outが作成される。図23を参照しながら説明する。
【０１１０】
（step-1）アンチデバッギング技術とハッシュ関数を追加する。
アンチデバッギング技術とハッシュ関数をP_inに追加実装する。追加実装の方法（サブルーチンあるいはインライン）は任意である。例えば、デバッガ検出処理と検出時にプログラムを中断する処理を実装したアンチデバッギング・ルーチンを、P_inの開始から終了まで定期的に実行するように実装する。
【０１１１】
アンチデバッギング技術は、アセンブリプログラムに追加実装してもよいし、高級言語（例えば、C）のソースプログラムに追加実装してもよい。ソースプログラムに追加実装したときは、そのソースプログラムをコンパイルして作成したアセンブリプログラムを入力として以下の手順を行う。
【０１１２】
（step-2）偽装対象の命令と偽装命令を定める。
P_inの中から偽装対象の命令を選び、対応する偽装命令を定める。偽装対象の命令と偽装命令の組はランダムに選ばれる、あるいはプログラム開発者が直接指定する。n組の偽装対象の命令と偽装命令の組が決定されたとする。
【０１１３】
（step-3）一般的アルゴリズムを実行する。
耐タンパー化したいアセンブリプログラムP_inとn組の偽装対象の命令と偽装命令の組を、前述の一般的アルゴリズムに入力し、出力される耐タンパー化されたアセンブリプログラムを得る。作成されたマシン語プログラムに対して、最後に置換された2箇所のマスク値を含む領域を署名対象として署名生成鍵を用いてディジタル署名を生成し、その署名データをデータ領域の仮値と置換する。その結果をP_outとして出力する。（end）
【実施例２】
【０１１４】
実施例１では、改ざんを検出したときのタンパー応答は、本来の命令の変わりに偽装命令が実行されることによる正常ではない動作、および本来とは異なる命令が自己書換えされることに伴う正常ではない動作である。
【０１１５】
プログラムが改ざんを検出したときの反応を攻撃者が理解困難であることが望ましい。なぜならば、プログラムの改ざん検出の仕組みおよび改ざん検出時の反応の仕組みを攻撃者が捕捉することが困難であれば、それらを無効化することも困難であるからである。
【０１１６】
基本アイデアを拡張して、図24のような耐タンパー応答機能を実現できる。図24の 「or」 は「and」 を偽装している。「_hash」 が保護対象を測定して計算を行い、改変が検出されないときは自己書換えにより「or」 は「and」 に書換えられる。
【０１１７】
「0x0」 と 「operand1」 の論理積（and）を 「operand1」に格納するので、operand1=0x0となり、その次の命令で 「operand2」 に 「operand1」 の値 「0x0」 を加算した値が「operand2」 に格納されるので、「operand2」 の値は変わらない。改変が検出されるときは自己書換えが正しく行われないため、「or」 は自己書換えされない。このとき、「_hash」の値が「operand1」に格納され、「0x0」と 「operand1」の論理和（or）が「operand1」に格納されるため、「_hash」の結果が 「operand1」 に格納される。その次の命令で 「operand2」 に 「operand1」 の値を加算した値が「operand2」 に格納されるので、「operand2」 の値は 「_hash」 の値に依存して変化する。この変化は改変が検出されたときだけ発生し 「operand2」 の値の変化は予測困難である。
【０１１８】
従って、プログラムの本来の計算で利用される変数が「operand2」になるように耐タンパー化することにより、改ざんが検出されないときは正しく計算され、改ざんが検出されるときは正しくない計算が行われる。例えば、ディジタル署名のアルゴリズムの計算や暗号アルゴリズムの計算の中で利用される変数を「operand2」とすること、ポインタの値を「operand2」とすることが考えられる。
【０１１９】
タンパー応答が自己書換え処理のみの場合と比較すると、改ざんを検出したときに正常ではない動作が発生することに加え、計算も正しく行われなくなるため、攻撃者の解析をより困難にする効果がある。
【実施例３】
【０１２０】
実施例１及び実施例２では、動的自己書換えによる命令偽装を一回適用されたプログラムは、追加される復帰ルーチン1個あるいは隠蔽ルーチン1個に対応する自己書換えをそれぞれ1回行う。本実施例では、1つの自己書換えルーチンが複数回の自己書換えを行うようにする構成を示す。
【０１２１】
自プログラムのコードを対象にしてチェックサム（あるいは暗号的ハッシュ値）を計算する関数として、暗号的ハッシュ関数を使うことができる。例えば、暗号的ハッシュ関数SHA-256やSHA-512は、それぞれ256ビット、512ビットのハッシュ値を出力する。
【０１２２】
暗号的ハッシュ関数は、入力が1ビットでも異なるときは異なる値を出力する。従って、実施例１及び実施例２の動的自己書換えによる命令偽装を施されたプログラムに改ざんが行われると、原理的には、本来とは異なるアドレスが別の値に自己書換えされる。しかし、自己書換え対象アドレスの計算に必要な値は256ビットである必要はなく、より小さな値の方が都合がよいことがある。
【０１２３】
しかし、256ビットの情報量を反映しないとすると改ざんの成功確率が高くなる。そこで、例えばSHA-256の出力256ビットを、1つのブロックが8ビットになるように32個のブロックに分け、1つのブロックに1つの自己書換えを対応させる。耐タンパー化を一回適用すると、保護対象を測定して256ビットの値を計算するコードが追加される。256ビットに対応する32個のブロックそれぞれに1つの自己書換えを追加する。この構成を採用することにより、256ビットの情報量を反映し、原理的には、改ざんが検出された場合に正常ではない動作を32箇所で発生する。
【０１２４】
自己書換え箇所が増えると、正常ではない動作を発生する確率を高めることができるので、改ざんを見逃す可能性を低くできる。
【実施例４】
【０１２５】
本発明の目的は、前述した実施形態の機能を実現するソフトウェアのプログラムコードをシステムあるいは装置で実行することによっても達成されることは言うまでもない。この場合、プログラムコード自体が前述した実施形態の機能を実現することになり、そのプログラムコードは本発明の技術的範囲に含まれる。
【０１２６】
プログラムコードは、例えば、コンピュータ読み取り可能な記録媒体に記録してシステムあるいは装置に供給することができる。そのシステムあるいは装置のコンピュータ（またはCPUまたはMPU）は、記録媒体に格納されたプログラムコードを読み出し実行することによっても、本発明の目的を達成することができる。したがって、そのプログラムコードを記憶した記録媒体も本発明の技術的範囲に含まれる。
【０１２７】
プログラムコードを供給するための記録媒体としては、例えば、フレキシブルディスク、ハードディスク、光磁気ディスク、CD-ROM、CD-R、磁気テープ、不揮発性メモリカード、ROM、DVD等を用いることができる。
【０１２８】
なお、プログラムコードは、コンピュータが当該プログラムコードを読み出し実行することにより前述した実施形態の機能を実現するための、全ての要素を備えたものに限られない。すなわち、プログラムコードには、コンピュータに組み込まれたソフトウェアおよびハードウェアの少なくともいずれかと協働することにより目的を達成するプログラムコードも含まれる。
【０１２９】
例えば、プログラムコードの指示に基づき、コンピュータ上で稼動しているOSなどが実際の処理の一部または全部を行い、その処理によって前述した実施形態の機能が実現される場合も、そのプログラムコードは本発明の技術的範囲に含まれる。ただし、OSはオペレーティングシステム（Operating System）の略称である。
【０１３０】
あるいは、例えば、プログラムコードの指示に基づき、コンピュータに挿入または接続された機能拡張ボードや機能拡張ユニットに備わるCPU等が実際の処理の一部または全部を行い、その処理によって前述した実施形態の機能が実現される場合がある。このような場合も、そのプログラムコードは本発明の技術的範囲に含まれる。なお、機能拡張ボードや機能拡張ユニットは、それらが備えるメモリにプログラムコードを読み込み実行することでこのような処理を行うことができる。
【図１】
0005467271.tif 000002
【図２】
0005467271.tif 000003
【図３】
0005467271.tif 000004
【図４】
0005467271.tif 000005
【図５】
0005467271.tif 000006
【図６】
0005467271.tif 000007
【図７】
0005467271.tif 000008
【図８】
0005467271.tif 000009
【図９】
0005467271.tif 000010
【図１０】
0005467271.tif 000011
【図１１】
0005467271.tif 000012
【図１２】
0005467271.tif 000013
【図１３】
0005467271.tif 000014
【図１４】
0005467271.tif 000015
【図１５】
0005467271.tif 000016
【図１６】
0005467271.tif 000017
【図１７】
0005467271.tif 000018
【図１８】
0005467271.tif 000019
【図１９】
0005467271.tif 000020
【図２０】
0005467271.tif 000021
【図２１】
0005467271.tif 000022
【図２２】
0005467271.tif 000023
【図２３】
0005467271.tif 000024
【図２４】
0005467271.tif 000025
【図２５】
0005467271.tif 000026
【図２６】
0005467271.tif 000027
【図２７】
0005467271.tif 000028
【図２８】
0005467271.tif 000029
【図２９】
0005467271.tif 000030
【図３０】
0005467271.tif 000031
【図３１】
0005467271.tif 000032
【図３２】
0005467271.tif 000033
【図３３】
0005467271.tif 000034
【図３４】
0005467271.tif 000035
【図３５】
0005467271.tif 000036
【図３６】
0005467271.tif 000037