web-dev-qa-db-ja.com

DLL CreateRemoteThreadによるインジェクション

単純なDLLインジェクションの次の作業コードを見てください:

  //Open the target process with read , write and execute priviledges
   Process = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, FALSE, ID); 

   //Get the address of LoadLibraryA
   LoadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); 

   // Allocate space in the process for our DLL 
   Memory = (LPVOID)VirtualAllocEx(Process, NULL, strlen(dll)+1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 

   // Write the string name of our DLL in the memory allocated 
   WriteProcessMemory(Process, (LPVOID)Memory, dll, strlen(dll)+1, NULL); 

   // Load our DLL 
   CreateRemoteThread(Process, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, (LPVOID)Memory, NULL, NULL); 

   //Let the program regain control of itself
   CloseHandle(Process); 

私を混乱させるのは、GetProcAddress現在のプロセスLoadLibraryA関数アドレスを返すことです。これをパラメータとしてCreateRemoteThreadに渡すにはどうすればよいですか。期待ターゲットプロセスそれを実行しますか?

16
James King

偶然に動作します。これは非常に一般的な事故です。Microsoftは、kernel32.dllなどのオペレーティングシステムDLLのベースアドレスが次のようになるように多大な努力を払っています。他のDLLと競合しません。 kernel32.dllがプロセスの初期化の非常に早い段階でロードされるため、優先ベースアドレスを取得するために戦わなければならない可能性が非常に低いため、さらに強化されています。

あなたは簡単に逃げるでしょう。この has が過去に間違っていたことは注目に値します。XPセキュリティアップデートのoopsが原因で、gdi32.dllが再配置され、多くのことが発生しました。起動時に多くのマシンがフォールオーバーします。正しい方法はかなり面倒です。CreateToolhelp32Snapshot()+ Module32First/Next()を使用して、再配置オフセットを見つけることは大きな喜びではありません。率直に言って、オペレーティングシステムがそのような「奇妙な」。

20
Hans Passant

LoadLibraryAkernel32.dllにあります。これは、常にすべてのプロセスにロードされ、たまたますべてのプロセスの同じアドレスにロードされるモジュールです。

アドレス空間配置のランダム化(ASLR)は、Windowsによって処理されるエクスプロイト防止の緩和機能であり、アドレスの再配置を可能にして、攻撃者がメモリ内の何かを悪用するためにアドレスを決定するのを防ぎます(アドレス/オフセットのハードコーディングを停止します)。ただし、Windowsモジュールは、セッションごとにアドレスを変更するだけです。

Kernel32.dllを使用するプロセスがある場合(すべてのプロセスがkernel32.dllを使用するわけではなく、これについては数分で詳しく説明します)、ルーチンのアドレスは例として55AA1122である可能性があります(これは無効な例のアドレスです)。これで、kernel32.dllを使用する次のプロセスは、前のプロセスと同じルーチンの55AA1122に対して同じアドレスを持ちます。プロセスが両方とも同じアーキテクチャである場合のみ。

32ビットプロセスは、他のWindowsモジュールエクスポート(NTDLL、USER32など)の中でも、kernel32.dllエクスポートに対して同じアドレスを持ちます。 64ビットプロセスは32ビットプロセスとは異なるアドレスを持ちますが、64ビットプロセスはすべてWindowsモジュールに対しても同じアドレスを持ちます。

リモートスレッドの作成は「事故」ではなく、Microsoftが意図的に実装しました。どうして? Microsoftは、Windows自体の間、非同期プロシージャコールにもこれを頻繁に使用します。マイクロソフトはまた、逆戻り防止のトリックとして、または独自のプロジェクトのソースコードを失った場合に、独自のルーチンに対して頻繁にホットパッチを適用します。

現在、kernel32.dllがプロセスにロードされていることに関しては、Win32APIを使用するプロセスにのみロードされます。これには、世界のプログラムの99%が含まれますが、それを使用しないネイティブプロセスをコンパイルすることは可能です。ただし、これにより、Win32 APIではなくネイティブAPIを完全に使用する必要があり、smss.exeと呼ばれるWindowsプロセスがこれを正確に実行します。通常のWin32API DLLエントリルーチンさえも持たないネイティブDLLをコンパイルすることもできます。

簡単に言うと、Windowsモジュールルーチンのアドレスは、起動ごとに1回変更されます。次の再起動まで同じ状態を維持します。 32ビットプロセスには、64ビットプロセスと同様に、プロセスごとにWindowsモジュールの独自の共有アドレスがあります。したがって、32ビットのKernel32.dll LoadLibraryAアドレスを使用しない限り、32ビットプロセスのDLLインジェクション)をターゲットにしている間は、64ビットプロセスのLoadLibraryAアドレスを使用できません。とにかくLdrLoadDllを使用するか、リフレクティブDLLローダースタブのシェルコードインジェクションのみを使用します。

Visual Studioを起動する場合は、空のプロジェクトを作成し、新しいmain.cppファイルを追加して、次のように書き留めます。

#include <windows.h>
void main()
{
}

そして、このプログラムをコンパイルします。作成された実行可能ファイルが何もしないことを期待しないでください。

ソースコードにコマンドがないため、Visual C++コンパイラがオブジェクトファイルにコマンドを書き留めなかった可能性がありますが、実行可能ファイルのLoadLibrary呼び出しのメインプロシージャの先頭にリンカーが書き留めました。 user32.dllkernel32.dllgdi32.dllなどへ。

したがって、Visual Studio C++で記述されたすべてのアプリケーションは、この実行可能ファイルのソースコードに関係なく、最初はLoadLibraryに対して同じ順序で多くの同じ呼び出しを行います。

ソースコードは、LoadLibrary呼び出しの後に来る必要があるコマンドのみを決定します。

したがって、すべてのVisual Studio C++アプリケーションは実行の開始時にkernel32.dllLoadLibraryをロードするため、LoadLibraryはプロセスアドレスを基準にしてすべてのプロセスで同じエントリポイントまたはアドレスを持ちます。

理論的には、kernel32.dllのLoadLibraryプロシージャをプログラムのメモリにロードしないkernel32.libをリンクすると、プログラムを挿入しようとする悪意のあるプログラムであるインジェクターが失敗する可能性があります。

プログラムが実行ロードdll中に動的にできない場合、インジェクターは実行中にプログラムに動的にいくつかのdllをロードさせることができません。これを行うことを想定しているプロシージャLoadLibraryがプロセスメモリに存在しないためです。

したがって、インジェクターによって作成されたリモートスレッドは、被害者のメモリに存在しないLoadLibraryを実行できません。

ただし、攻撃者がVirtualAllocExを使用して被害者のメモリにブロックを作成し、WriteProcessMemoryに実行可能コードを作成してから、CreateRemoteThreadを実行して実行する可能性があります。

0
user9820482