ReadProcessMemory
このP/Invoke署名を介してC#で呼び出すと、非常に奇妙な動作が発生します。
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
int dwSize,
out int lpNumberOfBytesRead
);
私のアプリケーションでは、読み取りおよび書き込みアクセス権を持つメモリ領域のメモリ全体をスキャンしています(さらにいくつかのフィルターが適用されていますが、それは別の部分です)。
スキャン部分のコードは次のようなものです。
int numberOfBytes;
if (!NativeMethods.ReadProcessMemory(handle, region.StartAddress,
buffer, (int)region.RegionSize, out numberOfBytes))
// The handle, region (custom struct containing some fields from the
// MEMORY_BASIC_INFORMATION struct), and buffer come from parameters.
そして、コードは完全に機能します。メモリ全体をスキャンして一連のバイトを探します。そこに問題はありません。
プログラムのフローのもう少し先に、このコードがあります。
注:前のコード(チェック済み)と同じハンドルIntPtrを使用しており、同じスレッドで実行されます。
int bytesRead;
byte[] buffer = new byte[128]; // In my real app this is some calculated value
// however that irrelevant. It's calculated 128.
if (!NativeMethods.ReadProcessMemory(handle, location.Location,
buffer, buffer.Length, out bytesRead))
continue; // Error while reading
// At this point buffer == null, so the next line causes an exception
if (bytesRead != buffer.Length) continue;
コードは非常に似ていますが、何らかの理由でバッファへの参照が失われ、バッファがnullに設定されます。外部呼び出しでない場合は、バッファがref
またはout
パラメータとして渡されないため、バグであると100%確信しています。ただし、外部呼び出し(マーシャリングなど)に関しては、.NETがいくつかのvodoo機能を実行することを私は知っています。
状況をさらに奇妙にするのは、そのコードを次のように置き換えるとです。
int bytesRead;
byte[] buffer = new byte[128];
byte[] bufferRef = buffer;
if (!NativeMethods.ReadProcessMemory(handle, location.Location,
buffer, buffer.Length, out bytesRead))
continue; // Error while reading
buffer = bufferRef;
if (bytesRead != buffer.Length) continue;
コードは単純に機能します。メモリー読み取りとすべて!つまり、何らかの理由でbuffer
変数が実際のバッファーへの参照を失うだけです。そして、それは私を混乱させます。
この動作は、私が間違ったこと(P / Invokeの障害など)の結果であり、危険であり(メモリリーク?)、説明可能ですか?
私の構成:
- .NET Framework 4.0
- Visual Studio Professional 2012(バージョン11.0.51106.01アップデート1)
- インストールされた.NETFramework4.5.50709
- 管理者として実行
- Visual Studioホスト実行可能ファイルと通常のビルド実行可能ファイルの両方で、リリースビルドとデバッグビルドの両方で発生します。
- Windows764ビット
- 私がメモリを読み取っているプロセスは32ビットです
- ビルド構成:プラットフォーム:任意のCPU
編集:私が使用している完全なNativeMethodsクラスはここにあります:http://paste2.org/p/2770271
Edit2:問題を修正するために実行した簡単な手順を、ここにある回答として追加しました。