web-dev-qa-db-ja.com

「任意のCPU」の.NETアセンブリにx86 CLRを強制する

.NETでは、「プラットフォームターゲット:任意のCPU」コンパイラオプションを使用すると、.NETアセンブリをx64マシンでは64ビット、x86マシンでは32ビットとして実行できます。 「プラットフォームターゲット:x86」コンパイラオプションを使用して、x64マシン上でアセンブリを強制的にx86として実行することもできます。

「任意のCPU」フラグを使用してアセンブリを実行することはできますが、x86またはx64 CLRで実行する必要があるかどうかを決定しますか?通常、この決定は、基礎となるシステムのビット数に基づいて、CLR/OSローダー(私の理解では)によって行われます。

他の実行中のプロセスと対話(読み取り:コードの挿入)できるC#.NETアプリケーションを作成しようとしています。 x64プロセスは他のx64プロセスにのみ挿入でき、x86でも同じです。理想的には、JITコンパイルとAny CPオプションを利用して、単一のアプリケーションを使用して(x64マシン上の)x64またはx86プロセスに注入できるようにしたいと思います。

アイデアは、アプリケーションがAny CPとしてコンパイルされるということです。 x64マシンでは、x64として実行されます。ターゲットプロセスがx86の場合、それ自体を再起動して、CLRに強制的にx86として実行させる必要があります。これは可能ですか?

56
jeffora

CorFlags アプリケーションを使用して、アプリケーションの実行方法を確認し、静的に変更できます。アプリケーションの実行方法を確認するには、次を使用します。

corflags <PathToExe>

アプリケーションの実行方法を変更するには、次を使用します。

corflags /32bit+  <PathToExe>

これにより、EXEファイルが32ビットプロセスとして実行されます。アセンブリの実行方法に関する情報は、PEヘッダーに格納されています。スタックオーバーフローの質問を参照してくださいネイティブDLLファイルがx64またはx86としてコンパイルされているかどうかを調べる方法)

実行時にコードを挿入する場合は、 C++ /COMに 。NET プロファイラーを記述する必要があります。 。NET Internals:The Profiling APIおよびProfiling(Unmanaged APIリファレンス)詳細については、.

JitCompilationStartedコールバックを実装し、そこで作業を行う必要があります。この方向に進む場合は、インジェクションDLLファイルをx86とx64の両方としてビルドする必要があります。ネイティブのDLLファイルは、 [〜#〜] clr [〜#〜] 次の環境変数が設定されると、

Cor_Enable_Profiling=0x1
COR_PROFILER={CLSID-of-your-native-DLL-file}

正しく設定されている場合、64ビットバージョンは64ビットプロセスを「認識」し、32ビットバージョンは32ビットプロセスを「認識」します。

60
Ohad Horesh

私がこれを試してから久しぶりですが、アセンブリを呼び出すプロセスのビットネスが、それがx86とx64のどちらとしてJITされるかを決定すると思います。

したがって、小さなコンソールアプリケーションを記述してx86としてビルドし、別のコンソールアプリケーションをx64としてビルドした場合、どちらか一方を実行すると、プロセスに読み込まれた他のアセンブリが32ビットまたは64ビットとして実行されます。もちろん、これは64ビットマシンで実行していることを前提としています。

9
jnoss

これであなたを助けることができるかどうかわかりません。しかし、これは私の経験です。

私はホストアプリケーションA.exe(x86としてコンパイル)を使用しており、ホストアプリケーションからクライアントアプリケーションB.exeANY CPUとしてコンパイル)を使用しています。そして、_ System.Diagnostic.Process クラスを使用して、B.exeからA.exeを起動します。

ここで問題は、2つをx64マシンに置くと、A.exeはx86として実行されますが、B.exeはx64として実行されます。

ただし、A.exeがアセンブリc(c.dllとしてコンパイルされるAny CPU)を呼び出し、B.exec.dllを呼び出す場合、c.dllはアプリケーションに従いますそれを呼び出します。つまり、64ビットマシンでは、A.exex86 dllを呼び出すと動作し、B.exex64を呼び出すと動作します。

6
Graviton

2つ(実際には3つ)のバイナリを作成することで、同様のことを行いました。注入しようとしているプロセスが32ビットか64ビットかを検出しました。このプロセスは、32ビットまたは64ビットバージョンのインジェクションバイナリを起動します(前述のようにそれ自体を再起動するのではありません)。

乱雑に聞こえますが、ビルド時に、出力バイナリのコピーを作成し、 CorFlags ユーティリティを使用してコピーを強制的に32ビットとして実行するビルド後のイベントを使用して、これを簡単に実現できます。この方法では、アプリケーションと一緒にCorFlagsユーティリティを展開する必要はありません。これは、おそらく何らかの理由で合法ではありません。

これは最初のアイデアと非常によく似ていると思います。2行のビルドイベントを除いて、これ以上の作業は必要ありません。

6
KarlW