いやぁ、なやんだわぁw
というわけで、私的技術メモ。
※内容の正誤も含め、これらを利用したことによる被害について、管理人は一切の責任を負いません。
まぁ、つまり間違っている可能性も多々ありますので、その点はご留意ください…。
★リフレクションのアセンブリロード関数の制限について。
アセンブリを読み込む関数に、生バイトを流し込むオーバーロード関数があります。
System.Reflection.Assembly.Load
http://msdn2.microsoft.com/ja-jp/library/system.reflection.assembly.load(VS.80).aspx
や、
System.AppDomain.Load
http://msdn2.microsoft.com/ja-jp/library/system.appdomain.load(VS.80).aspx
の、第一引数にバイト配列を受け取る関数が該当します。
これらは、アセンブリのファイルバイナリデータをそのまま渡して、ロードするというもの。
ぉ、ということは!
ファイルアーカイバデコーダーを作る
↓
アーカイブからアセンブリDLLをバイナリデータをして取得
↓
バイナリデータをそのままアセンブリとしてロード
…つまり、アーカイブファイル内のDLLをメモリ内で展開し、直接読み込めるので、
複数のDLLがひとまとめにでき、スッキリ( ゚Д゚)ウマウマー
と、思ったので、やってみるテスト。
まずは、ファイルストリームから直読み込みで。
System::IO::FileInfo^ infFileIO = gcnew System::IO::FileInfo(“infinity.FileIO.dll”);
System::IO::FileStream^ streamFileIO = gcnew System::IO::FileStream(infFileIO->FullName, System::IO::FileMode::Open, System::IO::FileAccess::Read, System::IO::FileShare::Read);
// バイトを読み込む
array
streamFileIO->Seek(0, System::IO::SeekOrigin::Begin);
streamFileIO->Read(bytesFileIO, 0, bytesFileIO->Length);
// ストリームを閉じる
streamFileIO->Close();
// 読み込むよ
assemblyFileIO = System::AppDomain::CurrentDomain->Load(bytesFileIO);
…実行時にこんなエラーが。
System.IO.FileLoadException が発生しました。
Message=”確認不可能なコードによるポリシー チェックが失敗しました。 (HRESULT からの例外: 0x80131402)”
Source=”mscorlib”
StackTrace:
場所 System.Reflection.Assembly.nLoadImage(Byte[] rawAssembly, Byte[] rawSymbolStore, Evidence evidence, StackCrawlMark& stackMark, Boolean fIntrospection)
場所 System.AppDomain.Load(Byte[] rawAssembly)
場所 infinity.Core.infinityCore.PluginManager..ctor(infinityCore objCore)
Σ(´Д`lll)ナンデストー
というわけで、テキトーに証拠を自前で指定してみりゅ。
System::IO::FileInfo^ infFileIO = gcnew System::IO::FileInfo(“infinity.FileIO.dll”);
System::IO::FileStream^ streamFileIO = gcnew System::IO::FileStream(infFileIO->FullName, System::IO::FileMode::Open, System::IO::FileAccess::Read, System::IO::FileShare::Read);
// バイトを読み込む
array
streamFileIO->Seek(0, System::IO::SeekOrigin::Begin);
streamFileIO->Read(bytesFileIO, 0, bytesFileIO->Length);
// SHA1を計算
System::Security::Cryptography::SHA1Managed^ shaFileIO = gcnew System::Security::Cryptography::SHA1Managed();
streamFileIO->Seek(0, System::IO::SeekOrigin::Begin);
shaFileIO->ComputeHash(streamFileIO);
// 証拠
System::Security::Policy::Evidence^ evidenceFileIO = gcnew System::Security::Policy::Evidence();
evidenceFileIO->AddHost(gcnew System::Security::Policy::Zone(System::Security::SecurityZone::MyComputer));
evidenceFileIO->AddHost(gcnew System::Security::Policy::Url(“file://” + infFileIO->FullName));
evidenceFileIO->AddAssembly(System::Security::Policy::Hash::CreateSHA1(shaFileIO->Hash));
// ストリームを閉じる
streamFileIO->Close();
// 読み込むよ
// ちなみに、第2引数はデバッグシンボルのバイナリを流し込むことができる(*.pdbのバイナリ)
assemblyFileIO = System::AppDomain::CurrentDomain->Load(bytesFileIO, nullptr, evidenceFileIO);
実行してみよう。
System.IO.FileLoadException が発生しました。
Message=”Attempt to load an unverifiable executable with fixup を含む確認できない実行可能ファイルを読み込もうとしています (3 セクション以上、または TLS セクションを含む IAT です)。 (HRESULT からの例外: 0x80131019)”
Source=”mscorlib”
StackTrace:
場所 System.Reflection.Assembly.nLoadImage(Byte[] rawAssembly, Byte[] rawSymbolStore, Evidence evidence, StackCrawlMark& stackMark, Boolean fIntrospection)
場所 System.AppDomain.Load(Byte[] rawAssembly, Byte[] rawSymbolStore, Evidence securityEvidence)
場所 infinity.Core.infinityCore.PluginManager..ctor(infinityCore objCore)
(´・ω・`)ショボーン
検証できないコードがあるとのご指摘のようです。
検証可能なタイプ セーフ コードの作成
http://msdn2.microsoft.com/ja-jp/library/01k04eaf(VS.80).aspx
確かに、コンパイラはC++/CLIであるし、コンパイラオプションは /clr、
つまり、アンマネージコードと混在しているため、PEVerifyでも警告が出る。
しかしながら、混在アセンブリがロードできないのでは、実用性として微妙なので、
どうにかならないものかと調べてみるが、衝撃の事実が…
以下のフォーラムを参照されたし。
http://www.dotnet247.com/247reference/msgs/26/134245.aspx
一番最後のレスポンスがトドメデアリマシタ。
意訳してみると、こんな感じでしょうか。
バイトストリームから、アンマネージコードを含むマネージアセンブリを読み込むことはできません。
CLRローダーのその部分の実装ではWindowsのLoadLibraryを使用していないため、
一切のアンマネージコードを扱うことができません。
ションボリダ…
■今日のまとめ
リフレクションでバイト配列からアセンブリをロードする場合、
対象のアセンブリは純粋なマネージコード(=検証可能なタイプセーフコード)で無ければなりません。
VB.NETやC#では、基本的には検証可能なタイプセーフコードになります。
C++/CLIの場合は、/clr:safe でコンパイルされたアセンブリが読み込めます。
■最後に
すごい長くなりましたが、これらのエラーで悩んでいた方の手助けになれば幸いです…orz