解説インサイド .NET Framework第8回 アセンブリのロードとセキュリティ インフォテリア株式会社 |
CLRのロードと厳密名の検証
mscoree.dllに入っている_CorExeMain(あるいは_CorDllMain)関数の仕事はあまり多くない。このDLLはshimと呼ばれていて、実際の仕事はほとんどしない。_CorExeMain関数はすぐにmscorwks.dllかmscorsvr.dllを呼び出し、すべての処理はそこで行われる。どちらのDLLを呼び出すかを選択するのがmscoree.dllの_CorExeMain関数の役割だ。ほとんどの場合はmscorwks.dllがロードされる。マルチプロセッサのシステム上でプログラムが明示的に選択すれば、mscorsvr.dllを使うこともできる。mscorwks.dll(mscorsvr.dll)がCLRの実体だといっていいだろう。
mscorwks.dllが呼び出されると、CLR環境が動作を開始する。CLRはまずロードされたEXE/DLLのメタデータ(マニフェスト)を読んで、これがアセンブリのプライマリ・モジュール(マニフェストが含まれているモジュール)であることを確認する。プライマリ・モジュールではなかった場合は、そこで例外が発生して、処理は終了する。
次に、CLRはこのアセンブリに電子署名が施されているかどうかを確認する。厳密名付きアセンブリだった場合は、まず署名の検証を行わなくてはならない。そのために、CLRはmscoree.dllのStrongNameSignatureVerification関数を呼び出す。mscoree.dllはmscorsn.dllのStrongNameSignatureVerification関数を呼び出して、公開キーを使った署名の検証を行う。検証に失敗した場合は、ファイルに改ざんがあったものと見なして、例外を発生させて処理を中止する。ここがCLRのセキュリティ機能の第1チェック・ポイントになる。アセンブリに署名して改ざんを防止することで、ウイルス感染などによる不正なプログラムの実行を防げるようになる。
.NETアプリケーション実行時の流れ |
プログラムの開始
署名の検証が終わると、CLRはロードされているプログラム(この場合はuser.exe)からエントリ・ポイントを探す。同じエントリ・ポイントという名前ではあっても、ここで探されるエントリ・ポイントは「マネージ・コードのエントリ・ポイント」だ。このエントリ・ポイントは、PEファイルの拡張部分に書き込まれているCLRヘッダに設定されている。CLRヘッダは、先ほどのdumpbin.exeを次のように実行すれば見ることができる。なおCLRヘッダの構造は、.NET Framework SDKに付属しているCorHdr.hファイルに定義されている(IMAGE_COR20_HEADER構造体)。
% dumpbin.exe /clrheader user.exe
dumpbin.exe /clrheaderの実行結果画面 |
出力されたデータの中ほどに「6000001 entry point token」というエントリがある。これがマネージ・コードのエントリ・ポイントを表している。マネージ・コードには必ずそれに対応するメタデータがある。6000001というのは、マネージ・コードのエントリ・ポイントについての情報が書いてあるメタデータ・テーブルのキーを表すトークンである。頭の60という値をCorHdr.hファイルで検索してみると、CorTokenTypeというenum(列挙)の中に次のような定義があることが確認できる。
|
|
CorHdr.hファイル内のCorTokenType列挙体にあるメソッド定義テーブルの定義(抜粋) |
つまり6000001という数値は、「メタデータ中のメソッド定義テーブルの1番目のレコード」を表している。メタデータをたどってこのレコードを探し出せば、C#やVisual Basic .NETにおけるMainメソッドの定義が取り出せるというわけだ。この検索結果は、この連載で最初からお世話になっているildasm.exeで見ることができる。
ildasm.exeで表示したMainメソッドのメソッド定義テーブル部分 |
表示方法については「第4回 アセンブリのロード(前編)」の「2.アセンブリのロード 1〜2段階」を参照 |
メソッド定義テーブルの中には、RVAという名前の付いているエントリがある。RVA(Relative Virtual Address)とは、PE形式においてメモリ上にロードされたときのアドレスを相対的に表したものである。つまり、この場合はuser.exeファイルの中の0x00402050アドレスに当たる部分に、Mainメソッドの実体が格納されていることを意味している。先ほど出てきたdumpbin.exe /headersの結果をもう1度見ると、このアドレスはファイル上では0x00000250バイト目ということになる。ここは次のような内容になっている。
13 30 01 00 12 00 00 00 01 00 00 11 73 02 00 00
0A 0A 06 6F 03 00 00 0A 28 04 00 00 0A 2A 00 00
最初の12バイトはメソッド・ヘッダと呼ばれる情報である。ildasm.exeでMainメソッドの中身を出力してみると、「.entrypoint」「// Code size 18 (0x12)」「.maxstack 1」「.locals init (class [.module util.netmodule]Util V_0)」という情報が表示されるが、これらの情報がこの12バイトの中に収められている。
13バイト目からがILコードである。このILコードを少し読みやすくすると次のようになる。
73 0x0A000002
0A
06
6F 0x0A000003
28 0x0A000004
2A
これをILアセンブラ言語に直すと次のようなコードになる。
newobj 0x0A000002
stloc.0
ldloc.0
callvirt 0x0A000003
call 0x0A000004
ret
ildasm.exeで表示したMainメソッドの中身(下図)と一致するのが分かるだろう。つまり、ここに入っているデータがILそのものなのである。
ildasm.exeで表示したMainメソッドの中身 |
INDEX | ||
解説 インサイド .NET Framework | ||
第8回 アセンブリのロードとセキュリティ | ||
1.Windowsローダーの動作 | ||
2.署名の検証とプログラムの開始 | ||
3.いくつものセキュリティ・チェック | ||
「解説:インサイド .NET Framework 」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|