タイトルが少し複雑だと気付いたので、私がやろうとしていることを説明しましょう。
書き込もうとしている概念実証のために、単純なDLLインジェクションを書き終えたところです。プログラムは、現在のプロセスのスナップショットを取り、プロセスツリーを列挙し、DLLを直接の親プロセスに挿入します。現在、理想的な条件下では、これは正常に機能します。32ビットバージョンのインジェクターは32ビットの親プロセスに注入でき、64ビットバージョンのインジェクターは64ビットの親プロセスに注入できます。
ただし、現在私が探しているのは、x64インジェクターから32ビットの親プロセスに32ビットのDLLを挿入することです。そのDLLが挿入されたら、挿入されたDLLによってエクスポートされた関数の1つへの呼び出しを挿入したいと思っていました。しかし、それが実際に可能かどうかはわかりません。(親プロセスが32ビットプロセスであるか64ビットプロセスであるかを識別するためのコードをすでにまとめているので、問題にはなりません)
さて、プリコンパイルされたマシンコードをプロセスに挿入することで最初の部分を実行しているように見えるコードをすでに見つけました。(少なくとも、それが実行されていると思います)通常、LoadLibraryWへの呼び出しを挿入した後、その呼び出しによって返されたアドレスを取得し、呼び出したいエクスポートされた関数に相対オフセットを追加し、それに呼び出しを挿入します働き。ただし、この場合、32ビットライブラリを64ビットインジェクターにロードできないため、通常のようにGetProcAddressを使用して関数の相対オフセットを見つけることができません。私は次のことを行うことでこの問題を乗り越えました:
通常の方法では32ビットDLLの関数オフセットを見つけることができないため、現在、ファイルをバッファーに読み込み、そのバッファーを使用してIMAGE_NT_HEADERS32構造体にデータを入力し、IMAGE_EXPORT_DIRECTORYを列挙して名前と相対オフセットを見つけています。エクスポートされたすべての関数の。
したがって、この時点で、私は次のようになります。
- 32ビットプロセスにロードされた32ビットDLL
- 32ビットプロセスで次のコードを実行する場合のfuncAddrと同等の値:
コード:
HMODULE hInjectedDLL = LoadLibrary("mydll.dll");
DWORD funcAddr = (DWORD)GetProcAddress(hInjectedDLL, "ExportedFunc") - (DWORD)hInjectedDLL;
理論的には、今必要なのはhInjectedDLLの値だけであり、その関数を呼び出すことができるはずです。残念ながら、アセンブリやマシンコードについては、その値を取得する方法を知るのに十分な知識がありません。
何か案は?
(また、2つのバージョンのインジェクターをコンパイルし、親プロセスのプロセッサーアーキテクチャーが一致しない場合に一方を実行するだけで、多くの問題を回避できることを認識しています。ただし、このルートです。)
編集:この概念実証で私が実際に達成しようとしていることを説明するのに役立つかもしれないと考えました。
元のプロセスが子プロセスの終了を待つ必要なしに、現在のコンソールで子プロセスの実行を許可する必要があるという考えを実験しています。コンソールアプリケーションでこれを行うための組み込みAPIがないため、通常はプロセスのツリーで立ち往生しており、すべてがそれぞれの子プロセスが完了するのを待っています。この機能を容易にするために、私は次のことをしたいと思います。
注入
DLLインジェクションは、「プロセスの実行」の役割を果たします。(通常、子プロセスが終了するまで待機する必要があるプロセス)実行時に、親プロセスのプラットフォームを判別し、親プロセスがコンソールベースのアプリケーションであるかどうかを判別します。そうでない場合、プロセスは単にexecファミリーの関数を使用して目的のサブプロセスを実行し、すぐに終了します。親プロセスがコンソールアプリケーションの場合、インジェクターは使用するDLLを決定し、インジェクタープロセスを最初に作成したスレッドを一時停止してから、DLLを親プロセスに挿入します。
私たちの機能を解決する
DLLが配置されると、インジェクターはDLLによってエクスポートされた関数のアドレスを判別します。(通常、これを行うには、 CreateRemoteThreadを呼び出して最初のインジェクションを実行し、次にそのスレッドでGetExitCodeThreadを使用して、親プロセスのDLLのベースアドレスを取得します。これを取得したら、次のアドレスを見つけるのは簡単な計算です。エクスポートされた関数。これを使用して、その関数への2番目の呼び出しを挿入できます。
私たちの関数を呼び出す
エクスポートされた関数は、次のようになります。
BOOL RewriteHProcess(HANDLE hProcess)
インジェクターは再びCreateRemoteThreadを使用して、親プロセスのコンテキストからこの関数を呼び出します。hProcessはインジェクタープロセスへのハンドルです。DLL側では、関数は2つのことのいずれかを実行します(スレッド間のメモリアクセスのセキュリティ制限を考えると、最初のアイデアが可能かどうかはよくわかりません。そのため、フォールバックする2番目のアイデアをまとめました。最初はうまくいきません。)
RewriteHProcessは、以前に中断されたスレッドを読み取りと書き込みのために開き、 ReadProcessMemoryを使用して、プロセスのメモリでインジェクタープロセスへのハンドルを検索します。(親プロセスが現在、 WaitForSingleObjectを使用してそれ以上の実行をブロックしていると想定しています。働き。コマンドプロンプトが少なくとも実行することはわかっています。当面はそれが私の焦点です)次に、DLLは内部関数を呼び出して目的の子プロセスを作成し、古いハンドルを閉じて、メモリを新しいハンドルで上書きします。子プロセス。この時点で、可能なことをクリーンアップして戻ります。次に、インジェクターは必要な残りのクリーンアップを実行し、中断されたスレッドを再開し、プロセスとスレッドへのハンドルを閉じて終了し、新しい子プロセスが終了するのを待つ間、親プロセスをブロックし続けます。
そのルートが不可能な場合、私のフォールバックは、インジェクターからブロッキングスレッドを一時停止し、挿入されたDLLに新しい子プロセスを作成し、インジェクターをクリーンアップして終了し、子プロセスが完了するまでDLLで待機することでした。その時点で、DLLはクリーンアップし、中断されたスレッドを再開し、それ自体をアンロードします。(ただし、このルートの欠点は、親プロセスがインジェクターから返す戻りコードが、ターゲットの子プロセスからの戻りコードと同じでない場合があることです)