web-dev-qa-db-ja.com

2つのプロセス間でメモリを共有する(C、Windows)

私は答えを見つけていないので 前にここで尋ねた質問に対する 私は別のアプローチを試みています。

2つのプロセス間でメモリを共有する方法はありますか?

2番目のプロセスは、サポートされなくなったレガシープログラムであるため、注入から情報を取得します。

私のアイデアは、そこにいくつかのコードを挿入することです。注入されたプログラムに渡す構造体では、実行する必要のあるデータが存在する共有メモリにアドレス(または何でも)を渡します。データを取得したら、注入したスレッド内に独自の変数を設定します。

これは可能ですか?どうやって?

コードは大歓迎です。

編集:

はっきりしないので、明確にします。私は注入する方法を知っています。すでにやっています。ここでの問題は、動的データをインジェクションに渡すことです。

28
wonderer

memory-mapped file を試すことができます。

This は、もう少し詳細なステップを提供します。

10
Scott Marlowe

Windowsは ファイルマッピングAPI を介して共有メモリをサポートしていますが、 MapViewOfFileEx はプロセス引数を受け取らないため、共有メモリマッピングを別のプロセスに直接簡単に挿入することはできません。

ただし、 VirtualAllocEx および WriteProcessMemory を使用して別のプロセスにメモリを割り当てることにより、一部のデータを注入できます。 DuplicateHandle を使用してハンドルをコピーしてから MapViewOfFileEx を呼び出すスタブを挿入すると、別のプロセスで共有メモリマッピングを確立できます。とにかくコードを注入するように聞こえるので、これはあなたのためにうまくいくはずです。

要約すると、次のことが必要です。

  • CreateFileMapping をhFileにINVALID_HANDLE_VALUEで、lpNameにNULLを呼び出して、匿名共有メモリセグメントハンドルを作成します。
  • DuplicateHandle を使用して、このハンドルをターゲットプロセスにコピーします。
  • VirtualAllocEx を使用してflAllocationType = MEM_COMMIT |を使用して、コード用にメモリを割り当てます。 MEM_RESERVEおよびflProtect = PAGE_EXECUTE_READWRITE
  • WriteProcessMemory を使用して、このメモリにスタブコードを書き込みます。このスタブは、おそらくアセンブラーで作成する必要があります。 DuplicateHandleからハンドルを渡すには、ここに書き込みます。
  • CreateRemoteThread を使用してスタブを実行します。スタブは、取得したハンドルを使用して MapViewOfFileEx を呼び出す必要があります。プロセスには、共通の共有メモリセグメントがあります。

スタブが外部ライブラリをロードする場合、つまり、LoadLibraryを呼び出して(LoadLibraryのアドレスを見つけることは読者に任せます)、ライブラリのdllmainエントリポイントから作業を行うと、少し簡単になります。この場合、名前付き共有メモリを使用する方が、DuplicateHandleをいじるよりも簡単です。詳細については、MSDNの記事 CreateFileMapping を参照してください。ただし、本質的に、hFileにはINVALID_HANDLE_VALUEを、lpNameには名前を渡します。

Edit:問題は実際のコードインジェクションではなくデータの受け渡しであるため、いくつかのオプションがあります。

  1. 可変サイズの共有メモリを使用します。スタブは、サイズと共有メモリの名前またはハンドルを取得します。これは、データの交換が1回だけ必要な場合に適しています。 共有メモリセグメントのサイズは、作成後に簡単に変更できないことに注意してください。
  2. 名前付きパイプ を使用します。スタブは、パイプの名前またはハンドルを取得します。その後、適切なプロトコルを使用して可変サイズのブロックを交換できます。たとえば、長さのsize_tを書き込み、その後に実際のメッセージを続けます。または、PIPE_TYPE_MESSAGEおよびPIPE_READMODE_MESSAGEを使用し、ERROR_MORE_DATAを監視して、メッセージの終了場所を判別します。これは、データを複数回交換する必要がある場合に適しています。

Edit 2:以下は、スタブのハンドルまたはポインタストレージを実装する方法のスケッチです。

.db B8            ;; mov eax, imm32
.dl handle_value  ;; fill this in (located at the start of the image + one byte)
;; handle value is now in eax, do with it as you will
;; more code follows...

固定名を使用することもできますが、これはおそらくより簡単です。

25
bdonlan
3
JaredPar

パイプ(メモリ用)またはシリアル化(オブジェクト用)を使用しようとしましたか?ファイルを使用して、プロセス間のメモリを管理できます。ソケットは、プロセス間の通信を取得するのにも適しています。

1
hackus

メモリマッピングを使用する方法です。永続的なメモリスペースを作成する必要さえありません。メモリセクタは、それを共有するすべてのプロセスがシャットダウンされると範囲外になります。他の方法もあります。あるCアプリから別のCアプリにデータを渡す素早い方法は、単にOSを使用することです。コマンドラインでapp1 | app2。これにより、app2がapp1の出力先になるか、app1からのprintfコマンドがapp2にapp2に送信します(これはパイピングと呼ばれます)。

1
gumby

Windowsについて話している場合、主な障害は、各プロセスが独自の仮想アドレス空間に存在することです。残念ながら、プロセス間で通常のメモリアドレスを渡すことはできず、期待どおりの結果を得ることができません。 (一方、スレッドはすべて同じアドレス空間に存在するため、スレッドは同じ方法でメモリを見ることができます。)

ただし、Windowsには共有メモリスペースがあり、正しく管理するには細心の注意が必要です。共有メモリ領域に領域を割り当てるプロセスは、そのメモリを明示的に解放する責任があります。これは、プロセスが終了すると多かれ少なかれ消失するローカルメモリとは対照的です。

このMSDNサンプル記事 を参照して、共有メモリ空間を使用して世界を支配する方法に関するいくつかのアイデアを確認してください。えー、レガシーソフトウェアとのインターフェース。または何でも:)あなたが何をすることでも幸運を!

0
Mike

Boost.Interprocess を使用して、2つのプロセス間で通信を試みることができます。ただし、サポートされていない既存のソフトウェアにコードを挿入するには、おそらく WriteProcessMemory を使用して@bdonlanの方法を使用する必要があります。

0
Vargas