Win32 プロセスのどのメモリ領域にグローバル データと各スレッドのスタック データが含まれているかを特定するにはどうすればよいですか?
3 に答える
これを行うための (私が知っている) API はありません。ただし、プロセスに DLL がある場合は、各スレッドが作成されるときにDllMainで DLL_PROCESS_ATTACH/DLL_THREAD_ATTACH 通知を受け取ります。新しいスレッドで呼び出されるため、これらの通知を受け取ったときに、そのスレッドのスレッド ID とスタック オブジェクトのアドレスを記録できます。したがって、その時点で作成するテーブルにスレッド ID とスタック アドレスを格納します。DllMain で多くの作業を実行しようとしないでください。スタックの場所を記録して戻るだけです。
その後、 VirtualQueryを使用して、各スレッド スタックの変数のアドレスを仮想割り当て範囲に変換できます。これにより、スタックのベース アドレスが得られます (スタックは上位アドレスから下位アドレスに成長することに注意してください)。スタックのデフォルトの割り当てサイズは 1Mb ですが、これはリンカー スイッチまたはスレッド作成者によってオーバーライドできますが、スタックは連続している必要があります。したがって、返されるのはその時点でVirtualQuery
の完全なスタックになります
ヒープの場所については、ヒープには複数の場所が存在する可能性がありますが、一般に、単一の連続したヒープの場所を想定する場合は、HeapAllocを使用してヒープ オブジェクトのアドレスを取得し、VirtualQuery
そのセクションのページの範囲を決定します。ヒープの。
VirtualQuery
または、EXE および各 DLL の hModule で使用できます。そして、読み書き可能で、スタックでもモジュールでもないものはすべてヒープの一部であると想定できます。これはほとんどのプロセスに当てはまりますが、一部のプロセスでは当てはまらない可能性があることに注意してください。これは、アプリケーションが直接呼び出しVirtualAlloc
たりCreateFileMapping
、スタックまたはヒープからではない有効なデータ ポインターを生成したりする可能性があるためです。EnumProcessModulesを使用して、プロセスにロードされたモジュールのリストを取得します。
VirtualQuery は基本的にランダムなアドレスを取得し、そのアドレスが属するページのコレクションのベース アドレスとページ保護を返します。そのため、割り当ての「タイプ」である特定のポインターから移動するのに適しています。
グローバルデータ
「グローバル」とは、new、malloc、HeapAlloc、VirtualAlloc などを使用して動的に割り当てられないすべてのデータを意味すると仮定します。ソース コードで宣言できるデータで、関数の外側およびクラス定義の外側にあります。 .
各 DLL を PE ファイルとして PE ファイル リーダーにロードし、.data セクションと .bss セクションの場所を特定することで、これらを見つけることができます (これらの名前は、コンパイラによって異なる場合があります)。これは、DLL ごとに行う必要があります。これにより、各 DLL のこのデータの一般的な場所がわかります。次に、デバッグ情報がある場合、または MAP ファイルに失敗した場合は、DLL アドレスをデバッグ情報/マップファイル情報に対してマップして、各変数の名前と正確な場所を取得できます。
PE フォーマット DLLを使用すると、自分で PE ファイルを照会するコードを記述するよりも、このタスクをはるかに簡単に実行できることがわかる場合があります。
スレッドスタック
ToolHelp32 (Windows NT 4 の場合は PSAPI ライブラリ) を使用して、アプリケーションのスレッドを列挙します。スレッドごとに、スレッド コンテキストを取得し、ESP レジスタ (x64 の場合は RSP) を読み取ります。次に、各コンテキストから読み取った ESP/RSP レジスタのアドレスに対して VirtualQuery を実行します。そのアドレスの周囲の 1MB (デフォルト値) の領域 (mbi.AllocationBase から始まり、1MB まで) がスタックの場所です。スタック サイズは 1MB ではない場合があることに注意してください。必要に応じて、スレッドを開始した DLL/EXE の PE ヘッダーからこれを照会できます。
編集、いくつかのレジスタ名を入れ替えたタイプミスを修正、@interjay に感謝
関心のあるメモリ領域に割り当てられた変数のアドレスを取得します。アドレスを取得したときにそのアドレスをどうするかは、まったく別の問題です。
データセクションを含むセクションアドレスをリストすることもできますobjdump -h
(-hだと思いますが、-xかもしれません)。