|
Nun im zweiten Teil möchte ich das eigentliche Programm vorstellen. Es handelt sich um eine Konsolenanwendung, welche eine PID einliest. Danach wird versucht, diesem Prozess den Code zu injizieren. Wichtig dabei ist, das man über entsprechende Rechte verfügt. Ganz konkret ist das Debug Recht gemeint ( SE_PRIVILEGE_ENABLED ). Mittles der Funktionen OpenProcessToken, LookupPrivilegeValue und AdjustTokenPrivileges ist es recht einfach die Rechte eines Prozesses zu verändern. Hier ein kleines Code Schnipsel: OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hAppToken ) LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &debugLuid )
AdjustTokenPrivileges( hAppToken, FALSE, &tokenPrivileges, sizeof( tokenPrivileges ), NULL, NULL ) Kommen wir nun zum wichtigsten Programmteil, die Erstellung des Threads in einem anderen Prozess. Wie beschrieben sollte zuerst geprüft werden ob Debugrechte vorhanden sind, bzw ob diese erlangt werden können. Danach öffnet man mittles der OpenProcess API den entsprechenden Prozess.Nun wird mittels der Funktion VirtualAllocEx Arbeitsspeicher im entsprechenden Prozess allokiert. Danach müssen noch die eigentlichen Daten in diesen Speicher geschrieben werden, dies übernimmt WriteProcessMemory. War auch das schreiben erfolgreich, wird nun die eigentliche Funktion zum erstellen eines Threads aufgerfuen. Die CreateRemoteThread Funktion, bei Erfolg erhält man ein HANDLE auf den Thread im anderen Prozess. Nun schauen wir uns die 3 Schritte im Detail an: VirtualAllocEx: const std::string dll = "botox.dll";
VirtualAllocEx( hRemoteProcessHandle, NULL, dll.length(), MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ) Wir übergeben das Prozess HANDLE, die Länge des DLL Names ( Anzahl der zu reservierenden Bytes , danach noch die entsprechenden Flags das der Speicher auch ausführbaren Code enthält. Wir erhalten einen void Pointer als Antwort. WriteProcessMemory: Nach dem erfolgreichen reservieren von Arbeitsspeicher müssen wir nun noch die Daten in diesen schreiben. In diesem Fall der Name der Dll, welche vom Prozess geladen werden soll. WriteProcessMemory( hRemoteProcessHandle, reinterpret_cast<LPVOID>( pRemoteMemory ), dll.c_str(), dll.length(), NULL ) Wieder wird das Prozess HANDLE übergeben, sowie den Pointer der auf den zuvor allokierten Arbeitsspeicher zeigt. Danach die eigentlichen Daten, mit Längeangabe. CreateRemoteThread: Nun die eigentliche Erstellung mittels CreateRemoteThread: reinterpret_cast<LPVOID>( GetProcAddress( GetModuleHandle( L"kernel32.dll" ), "LoadLibraryA" ) );
CreateRemoteThread( hRemoteProcessHandle, NULL, NULL, reinterpret_cast<LPTHREAD_START_ROUTINE>(pLoadLibrary), reinterpret_cast<LPVOID>(pRemoteMemory), NULL, NULL ); Auch hier zuerst das Prozess HANDLE, danach einen Pointer auf eine ThreadProc in diesem Fall die LoadLibrary Funktion der kernel32.dll. Danach den Arbeitsspeicher, fertig. Zurück bekommt man ein HANDLE auf den Thread. Bei meinen Recherchen, hatten viele Leute Probleme mit dieser Lösung unter Windows Vista. Dies kann ich aber nicht bestätigen, mein Programm wurde unter Windows Vista 64 bit entwickelt und getestet. Bei allen Versuchen war die Adresse von LoadLibraryA in der kernel32.dll konstant gleich. Weiterführende Links: |