単純な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
に渡すにはどうすればよいですか。期待ターゲットプロセスそれを実行しますか?
偶然に動作します。これは非常に一般的な事故です。Microsoftは、kernel32.dllなどのオペレーティングシステムDLLのベースアドレスが次のようになるように多大な努力を払っています。他のDLLと競合しません。 kernel32.dllがプロセスの初期化の非常に早い段階でロードされるため、優先ベースアドレスを取得するために戦わなければならない可能性が非常に低いため、さらに強化されています。
あなたは簡単に逃げるでしょう。この has が過去に間違っていたことは注目に値します。XPセキュリティアップデートのoopsが原因で、gdi32.dllが再配置され、多くのことが発生しました。起動時に多くのマシンがフォールオーバーします。正しい方法はかなり面倒です。CreateToolhelp32Snapshot()+ Module32First/Next()を使用して、再配置オフセットを見つけることは大きな喜びではありません。率直に言って、オペレーティングシステムがそのような「奇妙な」。
LoadLibraryA
はkernel32.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.dll
、kernel32.dll
、gdi32.dll
などへ。
したがって、Visual Studio C++で記述されたすべてのアプリケーションは、この実行可能ファイルのソースコードに関係なく、最初はLoadLibrary
に対して同じ順序で多くの同じ呼び出しを行います。
ソースコードは、LoadLibrary
呼び出しの後に来る必要があるコマンドのみを決定します。
したがって、すべてのVisual Studio C++アプリケーションは実行の開始時にkernel32.dll
のLoadLibrary
をロードするため、LoadLibrary
はプロセスアドレスを基準にしてすべてのプロセスで同じエントリポイントまたはアドレスを持ちます。
理論的には、kernel32.dllのLoadLibrary
プロシージャをプログラムのメモリにロードしないkernel32.libをリンクすると、プログラムを挿入しようとする悪意のあるプログラムであるインジェクターが失敗する可能性があります。
プログラムが実行ロードdll中に動的にできない場合、インジェクターは実行中にプログラムに動的にいくつかのdllをロードさせることができません。これを行うことを想定しているプロシージャLoadLibrary
がプロセスメモリに存在しないためです。
したがって、インジェクターによって作成されたリモートスレッドは、被害者のメモリに存在しないLoadLibrary
を実行できません。
ただし、攻撃者がVirtualAllocExを使用して被害者のメモリにブロックを作成し、WriteProcessMemoryに実行可能コードを作成してから、CreateRemoteThreadを実行して実行する可能性があります。