説明

プログラム及びプログラム実行装置

【課題】通常のリンカでリンクを行っても、外部オブジェクトを参照する原プログラムコードを符号化した符号化プログラムコードを正しく復号できるようにする。
【解決手段】オブジェクトファイル100は、原プログラムコードの符号化結果である符号化プログラムコード132と、符号化プログラムコードを復号して原プログラムコードを復元するための復号コード124と、原プログラムコード中で参照される外部オブジェクトのアドレスを表す外部参照テーブル142と、外部プログラムからの呼び出しに応じて、復号プログラムコードにより復元された原プログラムコードを、外部参照テーブルのアドレスを引数として呼び出すための呼び出しコード128と、を備え、原プログラムコードは、外部参照テーブルのアドレスにアクセスして外部オブジェクトのアドレスを取得し、そのアドレスを用いて外部オブジェクトを参照する。

【発明の詳細な説明】
【技術分野】
【0001】
本発明は、プログラム及びプログラム実行装置に関する。
【背景技術】
【0002】
コードの配布方法は、完成されたプログラムの形式だけでない。開発者に対しては、自ら生成したプログラムから配布されたコードを呼び出せるように、ライブラリという形式で渡される方法は、広く用いられている。このライブラリに含まれるコードの形態は、C言語を始めとする一般的なコンパイラ言語においては、オブジェクトコードと呼ばれるコンパイル後でリンク前の中間状態のコードとなっている。
【0003】
またコード内に含まれる秘密を秘匿するためにコードの一部を暗号化しておきたいという要求が存在するが、このオブジェクトコードに対しても、暗号化により、コード内の情報を秘匿したいという要求は存在する。
【0004】
リンク時に各オブジェクトが割り当てられるアドレスが決定する(アドレス解決)ため、このオブジェクトコードに対して符号化を行おうとした場合には、符号化されたコードに対して、リンク時のアドレス解決の結果としてコードの書き換えが発生し、アドレス解決の結果が正しく実施できない。加えて、符号化されたコードが変更された結果として、復号が正しく行えなくなるという問題を持つ。
【0005】
アドレス解決が不要になる様にコードを作成すると、前記問題は発生しないが、外部のデータやコードを利用する機能を記述できないため、実現できる機能が強く限定されてしまい、実用的な機能は提供できない。
【0006】
また、実行形式のコードでは、位置独立コード(PIC)と呼ばれるアドレス解決によるコードの書き換えが発生しない方式が用いられているが、この方式はリンク後の実行形式のコードに対する技術であり、オブジェクトコードの段階でこの様なコードを生成する機構は存在しない。
【0007】
特許文献1(特に図1)及び2には、オブジェクトファイルを暗号化して配布し、他のコードとのリンク時に復号して、リンクし、その後再び暗号化を行う方法により、オブジェクトファイル内のコードをディスアセンブルされるのを防ぐ方法が開示されている。当該技術によって作成されたオブジェクトファイルは、リンク作業時に、リンクする直前に、復号部が暗号化されたオブジェクトコードを復号し、リンク後に、復号したコードを再び暗号化するという手順で動作する。
【0008】
また、特許文献3(特に図2)には、実行形式のプログラム、ダイナミックリンクライブラリのコードにおいて、実行中に符号化されたコードを実行する前に、対象コードを復号し、その復号後かつ対象コードを実行する前に、対象コード内のアドレス変更が必要なコードの書き換えを行う方法により、コード内の一部のコードを符号化しておく技術を開示している。
【先行技術文献】
【特許文献】
【0009】
【特許文献1】特開平4−268924号公報
【特許文献2】特開平4−310128号公報
【特許文献3】特許第3033562号明細書
【発明の概要】
【発明が解決しようとする課題】
【0010】
本発明は、通常のリンカでリンクを行っても、外部オブジェクトを参照する原プログラムコードを符号化した符号化プログラムコードを正しく復号できるようにすることを目的とする。
【課題を解決するための手段】
【0011】
請求項1に係る発明は、原プログラムコードの符号化結果である符号化プログラムコードと、前記符号化プログラムコードを復号して前記原プログラムコードを復元する処理を前記コンピュータに実行させるための復号プログラムコードと、前記原プログラムコード中で参照される外部オブジェクトのアドレスを表す外部参照情報と、外部プログラムからの呼び出しに応じて、前記復号プログラムコードにより復元された前記原プログラムコードを、前記外部参照情報のアドレスを引数として呼び出す処理を、前記コンピュータに実行させるための呼び出しプログラムコードと、を備え、前記原プログラムコードは、前記外部参照情報のアドレスにアクセスして前記外部オブジェクトのアドレスを取得し、取得したアドレスを用いて前記外部オブジェクトを参照する処理を前記コンピュータに実行させる、ことを特徴とするプログラムである。
【0012】
請求項2に係る発明は、請求項1に係る発明において、前記原プログラムコード中で参照される外部オブジェクトのアドレスを取得し、前記外部参照情報として、取得したアドレスを含んだ情報を生成するための処理を前記コンピュータに実行させるための外部参照情報作成プログラムコード、を更に備えることを特徴とする。
【0013】
請求項3に係る発明は、請求項1に係る発明において、前記プログラムは、読み出し、書き込み、及び実行が可能なメモリ領域を前記コンピュータのメモリ上に確保する処理を前記コンピュータに実行させるためのプログラムコード、を更に含み、前記復号プログラムコードは、復号の結果である前記原プログラムコードを前記確保されたメモリ領域に書き込むための処理を前記コンピュータに実行させる、ことを特徴とする。
【0014】
請求項4に係る発明は、請求項1に係る発明において、前記コンピュータを、前記復号プログラムコードが既実行か未実行かを表すフラグを記憶するフラグ記憶手段、前記呼び出しプログラムコードが呼び出された場合に、前記フラグ記憶手段に記憶された前記フラグが未実行を表す場合には前記復号プログラムコードを実行して前記フラグを既実行に変更し、前記フラグが既実行を表す場合には前記復号プログラムコードを実行しないように制御する制御手段、として更に機能させることを特徴とする。
【0015】
請求項5に係る発明は、原プログラムコードの符号化結果である符号化プログラムコードを復号して前記原プログラムコードを復元する復号手段と、前記原プログラムコード中で参照される外部オブジェクトのアドレスを表す外部参照情報を記憶する外部参照情報記憶手段と、外部プログラムからの呼び出しに応じて、前記復号プログラムコードにより復元された前記原プログラムコードを、前記外部参照情報のアドレスを引数として呼び出す呼び出し手段と、前記呼び出し手段により呼び出された前記原プログラムコードを実行する実行手段と、を備え、前記原プログラムコードは、前記外部オブジェクトを参照する場合に、前記外部参照情報のアドレスにアクセスして前記外部オブジェクトのアドレスを取得し、取得したアドレスを用いて前記外部オブジェクトを参照する処理を前記実行手段に実行させる、ことを特徴とするプログラム実行装置である。
【発明の効果】
【0016】
請求項1又は5に係る発明によれば、通常のリンカでリンクを行っても、外部オブジェクトを参照する原プログラムコードを符号化した符号化プログラムコードを正しく復号できる。
【0017】
請求項2に係る発明によれば、外部オブジェクトのアドレスが実行時に動的に決定される場合でも、符号化プログラムコードの復号結果である原プログラムコードからその外部オブジェクトにアクセスすることができる。
【0018】
請求項3に係る発明によれば、符号化プログラムコードの復号結果の原プログラムコードを、コンピュータが実行できるようにすることができる。
【0019】
請求項4に係る発明によれば、外部プログラムが復号コードと呼び出しコードをそれぞれ個別に呼び出す必要をなくすことができる。
【図面の簡単な説明】
【0020】
【図1】実施の形態のオブジェクトファイルのデータ構造の例を示す図である。
【図2】外部参照テーブルのデータ構造の例を示す図である。
【図3】実施の形態のオブジェクトファイルの生成及び利用の流れを説明するための図である。
【図4】コンパイルによる外部参照テーブルの内容変遷の例を示す図である。
【図5】リンク及びロード・実行による外部参照テーブルの内容変遷の例を示す図である。
【図6】コンピュータのハードウエア構成の一例を示す図である。
【図7】リンク後の実行可能プログラムが実行される際の処理の流れの一例を示す図である。
【図8】オブジェクトファイルの実行によりコンピュータが実現するプログラム実行装置の機能的構成の例を示すブロック図である。
【発明を実施するための形態】
【0021】
以下、図面を参照して本発明の実施の形態を説明する。まず、図1を参照して、実施の形態のオブジェクトファイル100のデータ構造の一例を説明する。このオブジェクトファイル100は、例えばライブラリ関数又はライブラリファイルとして用いられる。
【0022】
図1に例示するように、オブジェクトファイル100は、オブジェクトヘッダ110、コードセクション120、独自セクション130及びデータセクション140を含んでいる。これら各セクションは、CPU(中央演算ユニット)等のマイクロプロセッサが実行できる機械語で記述されている。
【0023】
オブジェクトヘッダ110は、当該ファイル100のヘッダ情報を記述したセクションである。また、コードセクション120はプログラムコードが含まれるセクションであり、データセクション140はプログラムコードの実行において用いられるデータが含まれるセクションである。これらオブジェクトヘッダ110、コードセクション120及びデータセクション140は、一般的なオブジェクトファイル形式にも存在する。
【0024】
これに対し、独自セクション130は、この実施の形態のオブジェクトファイル独自のものである。独自セクション130は、読み出し、書き込み及び実行が可能なセクションである。独自セクション130には、符号化(例えば暗号化)対象のプログラムコード(原プログラムコードと呼ぶ)の符号化結果である符号化プログラムコード132が置かれる。ここで、原プログラムコードは、このオブジェクトファイル100が他のプログラムに対して提供する機能を記述したプログラムコードである。
【0025】
なお、独自セクション130に符号化プログラムコード132が置かれるのは、オブジェクトファイル100が符号化による保護を受けた後の段階(例えば配布時)でのことであり、符号化の前の段階では独自セクション130には原プログラムコードが置かれる。
【0026】
一般的なオブジェクトファイルでは原プログラムコードはコードセクション120に置かれるのに対し、この実施の形態では、以上のように、原プログラムコードを符号化した符号化プログラムコード132はコードセクション120ではなく独自セクション130に置かれる。
【0027】
一方、この実施の形態のコードセクション120には、独自セクション130に置かれた符号化プログラムコード132を実行するためのプログラムコードが置かれる。すなわち、この例では、コードセクション120には初期化関数122と呼び出しコード128とが置かれる。
【0028】
初期化関数122は、ライブラリ(オブジェクトファイル100)の初期化処理を表すプログラムである。初期化処理には、符号化プログラムコード132の復号処理と、外部参照テーブル142の作成処理とが含まれる。前者をマイクロプロセッサに実行させるためのプログラムコードが復号コード124であり、後者を実行させるためのプログラムコードが外部参照テーブル作成コード126である。初期化関数122は、例えば、このライブラリを利用するリンク元コード(すなわち外部プログラム)から呼び出される。
【0029】
ここで、外部参照テーブル142は、符号化プログラムコード132の復号結果である原プログラムコードが参照する外部オブジェクトのアドレス情報を保持するためのテーブルである。ここで、外部オブジェクトは、例えば、セクション外の関数呼び出しや、スタック外に置かれる静的データなどである。なお、ここで言うセクションは、復号結果の原プログラムコードがロードされた独自セクションのことであり、スタックは、オブジェクトファイル100がメモリにロードされた場合にデータセクションに作成されるスタック領域のことである。
【0030】
外部参照テーブル142は、実行時には、図2に概念的に示すように、各外部オブジェクトの実行時のアドレスの配列となる。図では、便宜上、各外部オブジェクトを名前で特定し、その名前に対応づけてアドレスの値を示しているが、実際には、図5に示したメインメモリ上の外部参照テーブルのイメージ例50のように、メインメモリ上での外部参照テーブル142のアドレス範囲内の各アドレス(これらがそれぞれ外部オブジェクトに対応する)に、当該外部オブジェクトの実行時アドレスの値を記憶したものとなる(詳細は後述)。なお、以上に説明した外部参照テーブル142の状態は、当該オブジェクトファイル100が外部プログラムとリンクされ、実行される状態となったときのものである。このような外部参照テーブル142がどのように作成されるかについては、後で図4及び図5を参照して詳しく説明する。
【0031】
外部参照テーブル作成コード126は、外部参照テーブル142の中で、実行時に動的に作成される部分を作成するための処理を記述したプログラムコードである。外部参照テーブル142のうち、静的な部分のデータは、あらかじめプログラマにより記述されている。すなわち、プログラマが記述した静的な部分の記述がコンパイルにより機械語に変換されるとともに、後のリンク時にリンカがデータセクション140の外部参照テーブル142を構成できるように、再配置情報(例えばリロケーションテーブル)が生成される。オブジェクトファイル100が使用されて、外部プログラムの中にリンクされることにより生成された実行可能ファイルがファイルシステムに保存されている段階では、オブジェクトファイル100のデータセクション140内の外部参照テーブル142には、静的な外部参照情報、すなわちアドレスが静的に定まっている外部オブジェクトについてのアドレス情報のみが含まれている。そして、実行時にならないとアドレスが決まらない外部オブジェクトのアドレス情報は、初期化関数122による初期化処理時に、外部参照テーブル作成コード126の実行により作成される。
【0032】
復号コード124は、符号化されたコードをマイクロプロセッサが実行可能なコードに復号する処理を記述したプログラムコードである。
【0033】
呼び出しコード128は、符号化プログラムコード132を復号して得られた原プログラムコードを呼び出す機能を記述したプログラムコードである。呼び出しコード128は、復号コード124が符号化プログラムコード132を復号した後かつ、外部参照テーブル作成コード126が外部参照テーブル142を完成させた後に、外部参照テーブル142のアドレス(例えば先頭アドレス)を、スタックないしレジスタを介して、原プログラムコードに渡し、その原プログラムコードを呼び出す機能を記述している。
【0034】
復号結果の原プログラムコードは、呼び出しコード128からの呼び出しに応じて、渡された外部参照テーブル142を用いて外部オブジェクトを利用しながら、外部のプログラム(例えば、後述するリンク元プログラム)に提供する所定の処理を行う機能を持つ。すなわち、原プログラムコードでは、外部オブジェクトの呼び出しの記述は、当該オブジェクトの名前で直接指し示す代わりに、外部参照テーブル142における当該オブジェクトのエントリを指し示す形で記述される。
【0035】
以下に、オブジェクトファイル100の元になるライブラリのソースコードの具体例を示す。なお、これは外部オブジェクト参照についての本実施の形態の特徴を示す目的の例であり、原プログラムコードの処理内容については特段の意味はない。
【0036】
// Microsoft社のVisual Studio(登録商標)によりコンパイルされる例
#include <windows.h>
// 独自セクションの作成
#pragma section(".mysect", write, execute )

bool g_isInitialized = false;
char BaseData[1024];

// 外部参照テーブル
struct ExternalObjectReferenceTable {
HANDLE hHeap;
char* pData;
DWORD (WINAPI * pGetLastError)(VOID);
LPVOID (WINAPI * pHeapAlloc)(HANDLE, DWORD, SIZE_T);
BOOL (WINAPI * pHeapFree)(HANDLE, DWORD, LPVOID);
} g_table = { NULL, BaseData, NULL, NULL, NULL };
// 静的に外部参照テーブルを作成する場合には、ここで行う

extern bool DoDecrypt(unsigned char*, BYTE*, BYTE*);

// 初期化関数
int initialize(void)
{
if (g_isInitialized) return 0;
// 復号コード
static unsigned char key[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
BYTE* pFuncTop = reinterpret_cast<BYTE*>(topFunc);
BYTE* pFuncTail= reinterpret_cast<BYTE*>(tailFunc);
if (DoDecrypt(key, pFuncTop, pFuncTail)) return -6;

// 外部参照テーブル作成コード
g_table.hHeap = GetProcessHeap();
if (g_table.hHeap == NULL) return -1;

HINSTANCE hKERNEL32 = LoadLibrary("kernel32.dll");
if (hKERNEL32 == NULL) return -2;
// kernel32.dll
g_table.pGetLastError = (DWORD (WINAPI * )(VOID))
GetProcAddress(hKERNEL32, "GetLastError");
if (g_table.pGetLastError == NULL) return -3;
g_table.pHeapAlloc = (LPVOID (WINAPI *)(HANDLE, DWORD, SIZE_T))
GetProcAddress(hKERNEL32, "HeapAlloc");
if (g_table.pHeapAlloc == NULL) return -4;
g_table.pHeapFree = (BOOL (WINAPI *)(HANDLE, DWORD, LPVOID))
GetProcAddress(hKERNEL32, "HeapFree");
if (g_table.pHeapFree == NULL) return -5;
g_isInitialized = true;
return 0;
}

// 呼び出しコード
int callTopFunc ( unsigned char* x, unsigned int y) {
if (false == g_isInitialized) return -1;
return topFunc(x, y, &g_table);
}

#pragma code_seg(".mysect")
// 原プログラムコード開始
int topFunc(unsigned char* x, unsigned int y,
// 引数(スタックまたはレジスタ経由)で外部参照テーブルのアドレスを渡す例
struct ExternalObjectReferenceTable& pTable) {
// 原プログラムコード内から外部オブジェクトを参照する例
unsigned char* pBuffer = (unsigned char*)(*pTable->pHeapAlloc)(pTable->hHeap, 0, y);

// 機能の提供

// 原プログラムコード内から外部オブジェクトを参照する例
if (pBuffer != NULL) (*pTable->pHeapFree)(pTable->hHeap, 0, pBuffer);
return 0;
}

int tailFunc(int a){ return a; }
// 符号化対象コード終了
#pragma code_seg()
【0037】
以上の例は、Microsoft社のVisual Studio(登録商標)のC/C++コンパイラによりコンパイルされることを想定したソースコードである。また、この例は、符号化(暗号化)する関数を指定した指定情報が、オブジェクトコードとは別に生成される関数リストである場合の例である。
【0038】
上記コード例には、まず独自セクション130を作成するためのコードが記述されている。Microsoft社のVisual StudioのC/C++コンパイラであれば、[#pragma section(“名前”, アトリビュート)]という記述で当該セクションを作成することができる。上述の例では、”.mysect”という名前の独自セクションを作成し、このセクションを書き込み可能かつ実行可能なセクションとして設定している。そして、ソースコード中で、関数定義された関数を[#pragma code_seg(“名前”)]と[#pragma code_seg()]とで挟むことで、その関数を作成した独自セクションに置くことができる(上述のコード例の末尾の原プログラムコードの記述を参照)。また、GNUのGCCコンパイラを用いてコンパイルする場合は、関数の定義に[__attribute__ ((section (“名前”)))]のアトリビュートを付加することで、その関数を設置するセクションを指定できる。
【0039】
上述のコード例では、独自セクションの作成を指示するコードの次に外部参照テーブル142(”g_table”)が定義されている。
【0040】
外部参照テーブル142の定義の後に、外部参照テーブル142の静的な部分を記述してもよい。すなわち、外部参照テーブル142のうちラベル名などにより静的に生成可能なデータは、ラベル名を用いてテーブルのエントリを生成し、リンカがそのラベル名に対応するアドレスを解決するようにする。
【0041】
また、外部参照テーブル142についての記述の後に、初期化関数122のコードが記述される。この初期化関数122のコード中には、まず復号コード124が記述され、その次に外部参照テーブル作成コード126が記述されている。
【0042】
上述の例の復号コード124では、復号に用いる情報のうち復号対象とするセクション(すなわち独自セクション130、とくに原プログラムコード)の範囲を示す情報として、当該セクションの先頭アドレスと終了アドレスと、を取得している。ただし、これは一例に過ぎない。この代わりに、先頭アドレスとセクションのサイズとを取得してもよい。また、別の例としてセクションの先頭と末尾にラベルを付与し、これらラベルからセクションの範囲を取得してもよい。また、セクションの先頭と末尾とに、定義した関数(上述のコード例におけるtopFuncとtailFunc)を用いることで、復号コード124がセクションの範囲を取得するようにしてもよい。また、復号コード124が行う処理が暗文復号であれば復号鍵が必要となるが、復号鍵としてはあらかじめ定めておいた値を用いるようにしてもよい。
【0043】
また、初期化関数のうちの外部参照テーブル作成コード126は、原プログラムコードが参照する外部オブジェクトのうち実行時にアドレスを解決するべきオブジェクトについて、動的に実行時にアドレスを取得し、取得したアドレスを外部参照テーブル142に設定する処理を記述している。例えば、Windows(登録商標)オペレーティングシステムにおいては、GetProcAddressというAPI関数により、外部関数のアドレスが取得できる。例えば、上記コード例では、当該ライブラリ(オブジェクトファイル100)を呼び出すリンク元プログラムのプロセスヒープのアドレスを取得して外部参照テーブルに登録している(g_table.hHeap = GetProcessHeap())。このプロセスヒープは、原プログラムコードにおいて参照される。また、上述のコード例では、原プログラムコードは、例えば、”kernel32.dll”というライブラリファイルに含まれる関数HeapAllocなどを外部オブジェクトとして参照するが、それら外部オブジェクトのメモリ上でのアドレスをGetProcAddress関数により取得し、取得したアドレスを外部参照テーブルg_tableのメンバ(例えばpHeapAlloc)に代入している。
【0044】
なお、原プログラムコードが用いるデータによっては、当該データを含んだ外部オブジェクトのアドレスでなく当該オブジェクト中の当該データを直接、外部参照テーブルに設定してもよい。
【0045】
初期化関数122の記述の後には、復号結果の原プログラムコードを呼び出すための呼び出しコード128が記述される。呼び出しコード128は、上述の例では、外部参照テーブルの初期化(作成)が完了していれば(フラグg_isInitializedがtrue)、原プログラムコード中の関数topFuncを呼び出す記述となっている。ここで、関数topFuncは外部参照テーブル構造体のポインタを引数の1つとしており、呼び出しコード128では、その引数に対し、外部参照テーブル作成コードにより完成したテーブルg_tableのアドレスをセットしている。これにより、呼び出された原プログラムコードの関数topFuncが、外部参照テーブルを参照可能となる。
【0046】
また、上述のコード例では、呼び出しコード128の後に記述された原プログラムコード中の関数topFuncは、引数として外部参照テーブルのアドレス(p_table)を受け取る。また、この関数は、外部オブジェクト(例えば関数HeapAlloc)をその名前で参照するのではなく、外部参照テーブル中の当該オブジェクトに対応するメンバが示すアドレス(p_table->pHeapAlloc)を介してそのオブジェクトを参照する。また、その関数は、呼び出し側の外部関数のプロセスヒープを、外部参照テーブルのメンバpTable->pHeapを介して参照している。
【0047】
上述のコード例では、原プログラムコード中には機能を提供する関数が1つしかなかったが、原プログラムコード中にそのような関数が複数含まれていてもよい。また、この場合、それら関数を個別に呼び出せるように、関数毎に当該関数を呼び出す呼び出しコード128を用意するようにしてもよい。
【0048】
このようなライブラリのソースコードは、例えば次の流れで作成すればよい。すなわち、まず、原プログラムコードを、上述のコード例のように、外部オブジェクトへのアクセスが外部参照テーブルを介して行われる形で記述する。また、原プログラムコードの関数を、独自セクションに置くようにコンパイラに指定するためのコードを記述する。また、独自セクションを復号するための復号コードを実装する。また、外部参照テーブルを定義し、そのうちラベル名などにより静的に生成可能なデータについてはラベル名を用いてテーブルの内容を記述する。また、実行時にアドレスを解決するべき外部オブジェクトについての情報を外部参照テーブルに登録する処理を記述した外部参照テーブル生成コードを実装する。また、外部参照テーブルを引数として原プログラムコード中の関数を呼び出す呼び出しコードを記述する。
【0049】
次に図3を参照して、この実施の形態のオブジェクトファイル100がライブラリとして作成され、配布されて利用される場合の流れの例を説明する。
【0050】
この流れでは、まずライブラリ開発者が、自分のコンピュータ200にて、以上のようにしてライブラリのソースコード150を作成した後、次にそのソースコード150をコンパイラにコンパイルさせる。これによりライブラリのオブジェクトファイル100Aが生成される。このオブジェクトファイル100Aの独自セクション130内は、この時点では符号化されていない。次に、オブジェクトファイル100Aのうちの独自セクション130を符号化プログラムにより符号化する。これにより、符号化プログラムコード132を含んだ配布版のオブジェクトファイル100Bが完成する。完成したオブジェクトファイル100Bが、ライブラリを利用する利用者側に配布される。
【0051】
なお、以上の処理の流れにおいて、独自セクション130の符号化前に、独自セクション130中に外部オブジェクトを直接参照するコードがないか確認し、存在する場合には、コードを修正するように警告する処理を行うようにしてもよい。外部オブジェクトを直接参照するコードがあるかは、例えば、独自セクション130についてのリロケーションテーブルの存在の有無および、エントリ数が1以上であるかによって判定すればよい。すなわち、コンパイラはソースコードをコンパイルする際に、後のリンク又はロードなどの処理のためのリロケーションテーブルを作成するが、独自セクション130についてこのリロケーションテーブルが作成されており、且つこのテーブルの中に1以上のエントリがあれば、独自セクション130中に外部オブジェクトを直接参照するコードがあると判定する。そして、独自セクション130中に外部オブジェクトを直接参照するコードがあると判定した場合には、リロケーションテーブルより参照しているオブジェクトのラベル名、及び、対象コードの位置(デバッグ情報が含まれる場合には、ソースコード上の場所まで)を判別し、判別した情報を警告と共に表示するようにしてもよい。
【0052】
配布版のライブラリ(オブジェクトファイル100B)の提供を受けた利用者のコンピュータ210では、以下のような作業が行われる。
【0053】
すなわち、まずライブラリ利用者は、そのライブラリを利用するリンク元コードをプログラミングする。リンク元コードは、被提供者側がマイクロプロセッサに実行させたい機能を記述するプログラムコードである。リンク元コードは、そのライブラリが提供する機能(複数あってもよい)を呼び出す記述を含む。ここで、リンク元コードは、ライブラリが提供する機能の呼び出しのすべてに先んじて、そのライブラリの初期化関数122を呼び出すようにプログラミングしておく。ここまでが、被提供者による一般のコーディング作業である。
【0054】
利用者は、作成したリンク元コードをコンパイルしてオブジェクトコード形式のリンク元コード155を生成する。そして、このリンク元コード155をライブラリのオブジェクトファイル100Bとリンカにリンクさせる。これにより、実行可能ファイル160が生成される。この実行可能ファイル160が、利用者のコンピュータ210のメモリにロードされ、実行される(170)。なお、このリンクは、静的リンクでも動的リンクでもよい。
【0055】
次に、図4及び図5を参照して、外部参照テーブル142の内容変遷の例を説明する。この例では、まず図4に示すように、ソースコード中では外部参照テーブルはコード例10のように記述されているとする。すなわち、このコード例10では、メンバとしてpData、pfunc、pfunc2等を有する外部参照テーブルg_tableが定義され、そのテーブルの第2のメンバが関数funcとして静的に記述されている。また、そのコード例10は、外部参照テーブル作成コード126の例として、外部参照テーブルg_tableのメンバpFunc2に対し、関数func2(のアドレス)を代入するという命令を含んでいる。
【0056】
このようなコード例10を含むソースコードをコンパイルすると、コード例20のようなオブジェクトコードを含んだオブジェクトファイルが得られる。この例では、ソースコード中の前述の外部参照テーブル作成コードは、オブジェクトファイル中ではコードセクション内のオフセット1300の位置にある「0番地の8バイト目(これは外部参照テーブル中のpfuncのエントリのアドレス)に、0と記入せよ」という命令(図では便宜上文章で説明したが、実際には当然ながら機械語命令である)へと変換されている。なお、その命令の2つの「0」の箇所には、後で適切なアドレス値がセットされる。また、データセクションのオフセット4100以降には、外部参照テーブルの各エントリが確保されている。ここでオフセット4104の位置には、後のリンク処理の際に関数funcのアドレスがセットされるが、この時点では場所の確保がなされるのみであり、値は0となっている。また、コード例20中のリロケーションセクションには、再配置情報であるリロケーションテーブルの内容が記入されている。リロケーションテーブルの内容は、例えば、コードのどの部分にどのシンボルのアドレスを入れるかを規定している。また、コード中のシンボルセクションには、コード中に現れるg_table等の各シンボルの情報が含まれる。シンボルの情報は、例えば名前、内容(データか、関数名かなど)、及び定義場所(このオブジェクトファイルの中か外か)を含んでいる。
【0057】
このようなコード例20を含んだオブジェクトファイルが、外部プログラム(リンク元コード)とリンクされると、図5に例示するコード例30を含んだ実行可能ファイルが生成される。このコード例30では、外部プログラムとのリンクにより、オフセット値がオブジェクトファイルの時点から変化している。リンクにより、各オブジェクトのアドレス(この時点ではファイル上にあるのでオフセット値)が決まる。例えば、外部参照テーブルg_table、関数func及びfunc2のアドレスが6100、4800及び4940と決まるので、それらアドレスがコード中の対応する位置にセットされる。
【0058】
例えば、関数funcのアドレスは、オフセット6100以降に位置するg_table中の当該関数funcの位置にセットされる。これは、外部参照テーブル142のうちの静的な部分の例である。すなわち、リンクの際、リンカは、オブジェクトファイルのシンボルセクションとリロケーションセクションを参照して、関数funcに対応するシンボルCがオフセット4104に位置することを知ると共に、そのオフセット4104がリンクによりオフセット6104に移動したことを知り、これらに基づきオフセット6104に関数funcのアドレス4800をセットする。
【0059】
また、関数func2のアドレス4800は、リンクによりオフセット3300に位置することとなった外部参照テーブル作成コード中にセットされる。この例では、外部参照テーブル作成コードの内容は、外部参照テーブルg_tableの先頭アドレス6100からみて8バイト目に、関数func2のアドレス4940をセットせよと言う命令となる。これは、外部参照テーブルのエントリのアドレスが、外部参照テーブル作成コードの実行により動的にセットされる例である。
【0060】
なお、データセクション中の外部参照テーブルにあるpData及びfunc2は、まだアドレスがセットされておらず、0のままである。
【0061】
このような実行可能ファイルがメインメモリにロードされ起動されると、外部参照テーブル作成コードの内の一部が実行される。ここでは、実行可能ファイルがメインメモリの0番地にロードされたとする。この場合、コード例40に示すように、データセクション中の外部参照テーブルは、オフセットと同じ値の番地(アドレス)に書き込まれることになる。この例では、コードセクションもデータセクションもロードにより内容は変化しない。
【0062】
そして、外部参照テーブル作成コードが実行されると、例えば3300番地のコードの実行により、6108番地に値4940がセットされることとなる。これにより、外部参照テーブルが完成する。
【0063】
なお、図4及び図5の例では、リンクの時点で判明するfunc2のアドレスを外部参照テーブル作成コードにより、メモリ上の外部参照テーブル中での当該関数のアドレスにセットしたが、これは説明のための便宜的な例に過ぎない。外部参照テーブル作成コードは、典型的には、実行時に動的にアドレスが決定されるようなオブジェクトに対して利用すればよい。
【0064】
このようにしてメインメモリ上に構成された外部参照テーブルのアドレス(典型的には先頭アドレス)は、復号後の原プログラムコードを実行するマイクロプロセッサ300に対し、呼び出しコード128の実行により引数として(例えばスタックやレジスタを介して)渡される。マイクロプロセッサ300は、その引数の値を用いて、原プログラムコード中の外部オブジェクトへの参照を、メインメモリ上の外部参照テーブル中での当該オブジェクトのエントリのアドレスへと変換する。そして、そのアドレスにアクセスすることで、その外部オブジェクトの実行時アドレスを知り、その外部オブジェクトへとアクセスする。
【0065】
開発者及び利用者が用いるコンピュータ200及び210は、図6に例示するような一般的なハードウエア構成を持つものでよい。すなわち、図6に例示するコンピュータは、例えば、CPU等のマイクロプロセッサ300、ランダムアクセスメモリ(RAM)302およびリードオンリメモリ(ROM)304等のメモリ(一次記憶)、HDD(ハードディスクドライブ)コントローラ308を経由して接続されたHDD306、各種I/O(入出力)インタフェース310等が、たとえばバス314を介して接続された回路構成を有する。バス314には、ローカルエリアネットワーク等のネットワークに接続するためのネットワークインタフェース312が接続されていてもよい。また、そのバス314に対し、例えばI/Oインタフェース310経由で、CDやDVDなどの可搬型ディスク記録媒体に対する読み取り及び/又は書き込みのためのディスクドライブ316、フラッシュメモリなどの各種規格の可搬型の不揮発性記録媒体に対する読み取り及び/又は書き込みのためのメモリリーダライタ318などが接続されてもよい。RAM302は、コンピュータ200又は210のメインメモリとして使用される。
【0066】
マイクロプロセッサ300が、ロードされた実行可能ファイル160を実行する処理手順を、図7及び図8を参照して説明する。
【0067】
利用者によりリンク元コードが起動されると、コンピュータ210のメモリ400(図3のRAM302に対応)に実行可能ファイル160がロードされる。図8には、メモリ400にロードされた実行可能イメージのうちライブラリに由来する部分を示している。そして、その実行可能イメージのうちのリンク元コードがマイクロプロセッサ300により実行される。ここで、リンク元コード中にはライブラリの初期化関数122を呼び出すコードが含まれている。マイクロプロセッサ300がこのコードを実行すると(S10)、初期化関数122が呼び出される。すると、マイクロプロセッサ300により復号コード124及び外部参照テーブル作成コード126が実行される。これにより、コンピュータ210は、復号部410及び外部参照テーブル作成部420として機能する。
【0068】
復号部410は、独自セクション130の符号化プログラムコード132を復号する(S12)。ここで、独自セクション130は書き込み可能及び実行可能なセクションなので、復号部410はそのセクション130内のコード132の復号結果(すなわち原プログラムコード)をそのセクション130内に書き戻すことができる。
【0069】
また、外部参照テーブル作成部420は、動的にアドレスを解決する必要のある各外部オブジェクトのアドレスを(例えばAPI関数を用いてオペレーティングシステムから)取得し、外部参照テーブル142に登録する。これにより、外部参照テーブル142が完成する(S14)。
【0070】
初期化関数122の実行が完了すると、リンク元コード側に制御が戻る。マイクロプロセッサ300は、リンク元コードの末尾に達するまで(S16)、リンク元コード内の命令を順番に実行する。この処理の中で、マイクロプロセッサ300で実行されるコードが呼び出しコード128に達すると(S18)、マイクロプロセッサ300は呼び出しコード128を実行する(S20)。これにより、コンピュータ210は呼び出し部430として機能する。呼び出し部430は、独自セクション130内の原プログラムコード中の、当該呼び出しコード128に対応する関数を呼び出す。この呼び出しの際、外部参照テーブル142のアドレスが引数として原プログラムコード側に渡される。
【0071】
この呼び出しに応じて、マイクロプロセッサ300は、原プログラムコード内の呼び出された関数を実行する(S22)。この実行により、コンピュータ210は、その関数が表す機能を提供する機能実行部440として機能する。機能実行部440は、呼び出された関数中で参照される外部オブジェクトにアクセスする際に、外部参照テーブル142を介してアクセスする。すなわち、引数として渡された外部参照テーブル142のアドレス(先頭アドレス)をもとに、その外部参照テーブル142内での当該外部オブジェクトのエントリのアドレスにアクセスし、アクセスしたアドレスにある値(すなわち当該外部オブジェクトの実行時アドレス)を用いて当該外部オブジェクトにアクセスする。
【0072】
呼び出された関数の実行が完了すると、処理がリンク元コード側に戻される。そして、リンク元コードの末尾に達するまで(S16)、S18〜S22の処理が繰り返される。
【0073】
以上、この実施の形態のオブジェクトファイル100の構成とその利用について説明した。以上の説明から理解されるように、この実施の形態の原プログラムコードには、外部オブジェクトを直接参照する記述は含まれない。この代わりに、原プログラムコード中では、外部オブジェクトへの参照は、呼び出しコード128から引数(上述のコード例ではp_table)として渡される外部参照テーブル142中のエントリを用いる間接参照の形で記述される。引数は、コンパイルの結果生成されるシンボルテーブルにも再配置情報(これらはオブジェクトファイル100内に含まれ、リンクやロードの際に参照される)にも登録されないので、上述のコード例でも、独自セクション130の原プログラムコード内のp_table->pHeapAllocやp_table->pHeapなどといった引数p_tableを介した参照はシンボルテーブルや再配置情報に登録されない。したがって、オブジェクトファイル100がリンク元コードとリンクされる際のアドレス解決処理において、独自セクション130内のシンボル又はアドレスが書き換えられることがない。リンクの時点では、独自セクション130内のコードは符号化されているため(符号化プログラムコード132)、アドレス解決のためにそのコードの一部が書き換えられると復号ができなくなるが、この実施の形態では独自セクション130はアドレス解決時に書き換えられないので、そのような不具合は生じない。すなわち、この実施の形態のオブジェクトファイル100の構成を用いれば、通常のコンパイラ及びリンカを用いた場合でも、符号化プログラムコード132がリンク時に破壊されることが防がれる。
【0074】
なお、独自セクション130がリンク時のアドレス解決の際に書き換えられることが防止されるという点は、外部参照テーブル142のエントリが静的に記述されたもの(すなわち静的にアドレスが決まっている外部オブジェクトについてのもの)のみである場合にも成り立つ。
【0075】
<変形例1>
上述の実施の形態では、復号コード124と外部参照テーブル作成コード126とを含む初期化関数122を、リンク元コードから明示的に呼び出す構成を説明したが、これは一例に過ぎない。リンク元コードから初期化関数122を明示的に呼び出す代わりに、リンク元コードから呼び出しコード128が最初に呼び出された際に、初期化関数122を実行するようにしてもよい。このために、ライブラリの初期化が既に実行されたか未実行であるかを示すフラグを例えばデータセクション140などに用意しておき、呼び出しコード128が呼ばれる毎にそのフラグを確認して、最初の呼び出しであれば、初期化関数122を呼び出す構成にすればよい。フラグが既実行を示す場合には、初期化関数122を呼び出さない。この例では、リンク元コードがライブラリの初期化関数122を呼ぶ手間が省かれる。
【0076】
<変形例2>
上述の実施の形態では、原プログラムコードから外部オブジェクトへの参照のために外部参照テーブルを用いたが、外部参照のためのデータがテーブルである必要はなく、外部参照に必要な情報が原プログラムコードに渡すことができるものであればどのような方法を用いてもよい。例えば、個々の外部オブジェクト毎に当該オブジェクトのメモリ400上でのアドレスを示す外部参照情報をデータセクション140上に記述又は生成し、外部オブジェクトを参照する関数に対し、そのオブジェクトに対応する外部参照情報のアドレスを引数として渡すようにしてもよい。すなわち、複数の外部オブジェクトのアドレス情報をテーブルの形で一括して原プログラムコードに渡すのではなく、個々の外部オブジェクトのアドレス情報を個別に原プログラムコード中の関数に渡してもよい。特に、原プログラムコードが複数のインタフェースを持つ場合には、すべてのインタフェースに同一の情報(外部参照テーブル)を渡すのではなく、インタフェース毎に、それぞれ必要な外部参照情報を渡すという方法も取れる。
【0077】
<変形例3>
上述の実施の形態では、符号化プログラムコード132の復号結果である原プログラムコードを、独自セクション130に格納する例を説明したが、これは一例に過ぎない。実施の形態の手法は、原プログラムコードは外部参照テーブルを介して外部オブジェクトにアクセスするため、原プログラムコードがメモリ400のメモリ空間のどこに置かれても正しく動作する。したがって、変形例として、復号コード124の実行により実現された復号部410が、必要な大きさの、書き込み、読み出し及び実行のすべてが可能なメモリ領域をメモリ400のメモリ空間内に確保し、そのメモリ領域上に復号結果の原プログラムコードを置く構成としてもよい。この場合には、呼び出しコード128が、確保されたメモリ領域上の原プログラムコードを呼び出せるように、アドレス解決を行う必要がある。この場合には、復号部410は、原プログラムコードを置いたメモリ領域のアドレスを知っているので、呼び出しコード128に、関数ポインタを用いるなどの方法で、そのアドレスを原プログラムコード中の関数に渡すことで、そのアドレス解決を実現すればよい。
【0078】
<変形例4>
上述の実施の形態では、原プログラムコードを一括して符号化する構成を説明したが、原プログラムコードが複数の機能を提供する場合、機能毎に分割して符号化するようにしてもよい。個々の機能は、それぞれ1つ又は複数の関数により提供される。この場合には、機能を提供するコード毎に当該コードがオブジェクトファイル中のどこに置かれたかの情報を、符号化プログラムと復号コード124(復号部410)が把握する必要がある。この情報は、ライブラリのラベル名を用いれば取得することができる。例えば、原プログラムコード中において複数の対象関数をひとかたまりとして符号化する場合を考える(原プログラムコード中には、そのようなかたまりが1以上存在する)。この場合、ひとかたまりとして符号化する対象関数群のうち最初に置かれた関数の関数名をシンボルとするコード位置から、その符号化する対象関数群の直後に置かれた関数名をシンボルとするコード位置の直前までが、ひとかたまりの符号化対象のコード(すなわち原プログラムコード)であると判断される。また、符号化したい対象となる関数が一つの場合(すなわち符号化の単位が1関数)は、その関数の先頭から次の関数の先頭の直前までが、一単位の符号化対象のコードと認識される。また関数の終了位置がシンボルとして定義されるようなコンパイラを用いる場合の別の方法としては、符号化する対象関数(群)で最初に置かれた関数名をシンボルとするコード位置を開始位置として、符号化する対象関数(群)の最後の関数の終了シンボルのコード位置までを、符号化対象のコードであると判断する方法である。関数の置かれる順番は、ソースコード上の定義の順番であることが一般的である。また、関数を置く順番を外から指定できるコンパイラも存在する。これにより符号化対象の関数を置く順番を制御することができる。別の方法では、一般のリンカではその出力情報の一つとして、生成した実行ファイルのどの位置にどのシンボルの関数を置いたかを示す情報(マップ情報と呼ばれる)を出力させることができる。このマップ情報を参照することで、符号化対象のコードがファイル内のどの位置に置かれたかを知ることができる。このように機能単位で符号化すれば、実行時に必要なコードだけ復号するといった使い方が可能となる。
【0079】
<変形例5>
上述の実施の形態では、一度復号した原プログラムコードは実行されるだけであるが、実行された後に再び符号化する構成としてもよい。符号化の目的が暗号化の様に情報の秘匿である場合には、このように再符号化すれば、原プログラムコードがメモリ上に存在する時間を減らすことで、より強固に情報を秘匿することが期待できる。これには、例えば呼び出しコード128を呼び出す直前に復号コード126を実行し、呼び出しコード128の実行終了後に符号化のためのコードを実行して符号化結果を独自セクション130に上書きするようにプログラミングすればよい。
【0080】
特に、変形例4と組み合せることが考えられる。この場合、個々の機能毎に、当該機能が実行される前に復号し、機能の実行後に再び符号化し、符号化結果を原プログラムコードに上書きすればよい。
【符号の説明】
【0081】
100 オブジェクトファイル、110 オブジェクトヘッダ、120 コードセクション、122 初期化関数、124 復号コード、126 外部参照テーブル作成コード、128 呼び出しコード、130 独自セクション、132 符号化プログラムコード、140 データセクション、142 外部参照テーブル。

【特許請求の範囲】
【請求項1】
原プログラムコードの符号化結果である符号化プログラムコードと、
前記符号化プログラムコードを復号して前記原プログラムコードを復元する処理を前記コンピュータに実行させるための復号プログラムコードと、
前記原プログラムコード中で参照される外部オブジェクトのアドレスを表す外部参照情報と、
外部プログラムからの呼び出しに応じて、前記復号プログラムコードにより復元された前記原プログラムコードを、前記外部参照情報のアドレスを引数として呼び出す処理を、前記コンピュータに実行させるための呼び出しプログラムコードと、
を備え、
前記原プログラムコードは、前記外部参照情報のアドレスにアクセスして前記外部オブジェクトのアドレスを取得し、取得したアドレスを用いて前記外部オブジェクトを参照する処理を前記コンピュータに実行させる、
ことを特徴とするプログラム。
【請求項2】
前記原プログラムコード中で参照される外部オブジェクトのアドレスを取得し、前記外部参照情報として、取得したアドレスを含んだ情報を生成するための処理を前記コンピュータに実行させるための外部参照情報作成プログラムコード、
を更に備えることを特徴とする請求項1記載のプログラム。
【請求項3】
前記プログラムは、
読み出し、書き込み、及び実行が可能なメモリ領域を前記コンピュータのメモリ上に確保する処理を前記コンピュータに実行させるためのプログラムコード、
を更に含み、
前記復号プログラムコードは、復号の結果である前記原プログラムコードを前記確保されたメモリ領域に書き込むための処理を前記コンピュータに実行させる、
ことを特徴とする請求項1記載のプログラム。
【請求項4】
前記コンピュータを、
前記復号プログラムコードが既実行か未実行かを表すフラグを記憶するフラグ記憶手段、
前記呼び出しプログラムコードが呼び出された場合に、前記フラグ記憶手段に記憶された前記フラグが未実行を表す場合には前記復号プログラムコードを実行して前記フラグを既実行に変更し、前記フラグが既実行を表す場合には前記復号プログラムコードを実行しないように制御する制御手段、
として更に機能させることを特徴とする請求項1記載のプログラム。
【請求項5】
原プログラムコードの符号化結果である符号化プログラムコードを復号して前記原プログラムコードを復元する復号手段と、
前記原プログラムコード中で参照される外部オブジェクトのアドレスを表す外部参照情報を記憶する外部参照情報記憶手段と、
外部プログラムからの呼び出しに応じて、前記復号プログラムコードにより復元された前記原プログラムコードを、前記外部参照情報のアドレスを引数として呼び出す呼び出し手段と、
前記呼び出し手段により呼び出された前記原プログラムコードを実行する実行手段と、
を備え、
前記原プログラムコードは、前記外部オブジェクトを参照する場合に、前記外部参照情報のアドレスにアクセスして前記外部オブジェクトのアドレスを取得し、取得したアドレスを用いて前記外部オブジェクトを参照する処理を前記実行手段に実行させる、
ことを特徴とするプログラム実行装置。

【図1】
image rotate

【図2】
image rotate

【図3】
image rotate

【図4】
image rotate

【図5】
image rotate

【図6】
image rotate

【図7】
image rotate

【図8】
image rotate