Kommandozeile eines anderen Prozesses auslesen



  • Ich hab mal gegooglet und dort wurde das auch genannt mit dem Hook. Wenn man den Hook in eine DLL packt wird die DLL in jeden Prozess geladen.
    Und CreateRemoteThread wurde noch genannt.



  • CreateRemoteThread ist das beste nur es geht nicht unter Win95/98. Damit kannst du einfach eine DLL in den Prozeß laden und in der DLL kannst du dann machen was du willst 🙂



  • Ja CreateRemoteThread klingt wirklich gut, habt vielen Dank! ich werde das ausprobieren.
    Schade das es unter den alten Betriebssystemen nicht geht, aber das werde ich halt verschmerzen müssen.



  • Hallo,

    ich habe jetzt mal ein bißchen ausprobiert. Leider geht es nicht 😞
    Es gibt scheinbar keine error codes != 0 aber der Thread läuft auch nicht los.

    void getProcessCommandLine (int processID, char* commandLineBuffer, int bufferSize)
    {
    	HANDLE pHandle = OpenProcess (
    		PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, TRUE, processID);
    	DWORD threadID = 0;	
    	HANDLE hThread = CreateRemoteThread (pHandle, NULL, 0, getCommandLineThreadProc, (LPVOID)commandLineBuffer, 0, &threadID);
    	if (!hThread)
    	{
    		MessageBox (NULL, "Thread nicht erzeugt", NULL, 0);
    		return;
    	}
    	WaitForSingleObject (hThread, INFINITE);
    }
    
    DWORD WINAPI getCommandLineThreadProc(LPVOID lpParameter)
    {	
    	lpParameter = (LPVOID)GetCommandLine ();
    	return 1;
    }
    

    Jemand ne Idee was ich falsch gemacht hab?



  • Hi, die Adresse deiner Funktion ist nur in deinem Prozeß gültig, im anderen Prozeß gibts deine Funktion an der Adresse nicht. Normalerweise ruft man mit CreateRemoteThread LoadLibrary auf, weil diese Funktion bei jedem Prozeß an der gleichen Adresse liegt und kann dann seine Dll in den Adressraum von dem Prozeß laden.

    Schau mal hier vorbei : http://www.codeproject.com/threads/winspy.asp

    # Retrieve a HANDLE to the remote process (OpenProcess).
    # Allocate memory for the DLL name in the remote process (VirtualAllocEx).
    # Write the DLL name, including full path, to the allocated memory (WriteProcessMemory).
    # Map your DLL to the remote process via CreateRemoteThread & LoadLibrary.
    # Wait until the remote thread terminates (WaitForSingleObject); this is until the call to LoadLibrary returns. Put another way, the thread will terminate as soon as our DllMain (called with reason DLL_PROCESS_ATTACH) returns.
    # Retrieve the exit code of the remote thread (GetExitCodeThread). Note that this is the value returned by LoadLibrary, thus the base address (HMODULE) of our mapped DLL.
    # Free the memory allocated in Step #2 (VirtualFreeEx).
    # Unload the DLL from the remote process via CreateRemoteThread & FreeLibrary. Pass the HMODULE handle retreived in Step #6 to FreeLibrary (via lpParameter in CreateRemoteThread).
    Note: If your injected DLL spawns any new threads, be sure they are all terminated before unloading it.
    # Wait until the thread terminates (WaitForSingleObject).



  • Ein bisschen aufwändiger ist das mit dem RemoteThread schon. Dein Speicher ist zum Beispiel nicht prozessübergreifend gültig und deshalb kann auf der Gegenseite nichts aus deinem Adressraum ausgeführt werden und auch sonst wären alle übergebenen Pointer ungültig.
    Du müsstest Speicher im fremden Prozess allokieren, den Code deiner Thread-Einstiegsfunktion rüberkopieren und den RemoteThread mit diesem starten. Dabei ist aber zu beachten, dass in der eingeschleusten Threadfunktion nicht auf Stringliterale zugegriffen werden kann oder auch sonst keine Funktionen aufrufbar sind ohne eine Zugriffsverletzung zu erzeugen. Das liegt daran, dass die Adressen der Stringliterale und Funktionen ungültig werden, wenn die Funktion in einen fremden Prozess kopiert wird. Deshalb werden in einem Argumentstruct die Funktionspointer auf die Funktionen übergeben, die notwendig sind um eine DLL zu laden. Diese stammen aus der Kernel32.dll, die eigentlich bei jedem Prozess an die gleiche Stelle gemappt wird, deshalb sind diese Funktionspointer auch im fremden Prozess gültig. In der DLL kann man dann normal mit Funktionen und Stringliteralen arbeiten.

    Ich hab hier mal nen Code von mir hochgeladen in dem die ganze RemoteThread-Sache behandelt wird, bei Fragen stehe ich zur Verfügung 🙂

    http://www.mmsources.de/pub/ProcessCodeInjection.rar



  • das sieht sehr gut aus, danke. hätte nicht gedacht, dass es so kompliziert ist...



  • Mit nem Hook isses wahrscheinlich einfacher. 🤡



  • Mit NtQueryInformationProcess geht es auch, aber die Funktion ist undokumentiert und ich konnte keine Beschreibung der Parameter finden, um an die entsprechende Information zu kommen.



  • Also ich finde da keine Information, die diese Kommandozeile enthält:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/ntqueryinformationprocess.asp



  • Habs jetzt hinbekommen, ist zwar alles irgendwie schwammig weil nur dürftig dokumentiert, erscheint mir aber sauberer als die Variante mit dem RemoteThread. Naja, mach es, wie du denkst 😉

    #include <windows.h>
    
    typedef LONG NTSTATUS;
    typedef LONG KPRIORITY;
    typedef struct _PEB *PPEB;
    
    struct INFOBLOCK
    {
        CHAR stuff[68];
        PWCHAR cmdline;
    };
    
    struct PEB
    {
        CHAR   stuff[16];
        INFOBLOCK *pinfoblock;
    };
    
    struct PROCESS_BASIC_INFORMATION {
        NTSTATUS ExitStatus;
        PEB *PebBaseAddress;
        ULONG_PTR AffinityMask;
        KPRIORITY BasePriority;
        ULONG_PTR UniqueProcessId;
        ULONG_PTR InheritedFromUniqueProcessId;
    };
    
    enum PROCESSINFOCLASS {
        ProcessBasicInformation,
    	// [...]
    };
    
    typedef NTSTATUS (NTAPI *PNtQueryInformationProcess) (HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
    
    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
    {
    	DWORD dwPID = 0x8B8; //Hardcoded pid
    
    	HMODULE hmod = LoadLibrary("ntdll.dll");
    
    	PNtQueryInformationProcess pNtQueryInformationProcess = 
    		(PNtQueryInformationProcess) GetProcAddress(hmod,"NtQueryInformationProcess");	
    
    	HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPID);
    
    	if (!hProc) {
    		MessageBox(NULL,"OpenProcess failed","Error",MB_ICONERROR | MB_OK);
    		return -1;
    	}
    
    	PROCESS_BASIC_INFORMATION pbi;
    	ZeroMemory(&pbi,sizeof(pbi));
    
    	ULONG cbRet = 0;
    	NTSTATUS Ret = pNtQueryInformationProcess(hProc,ProcessBasicInformation,(PVOID)&pbi,sizeof(pbi),&cbRet);
    
    	if (Ret!=0) {
    		MessageBox(NULL,"NtQueryInformationProcess failed","Error",MB_ICONERROR | MB_OK);
    		CloseHandle(hProc);
    		return -1;
    	}
    
    	PEB peb;
    	INFOBLOCK infoblock;
    	WCHAR cmdline[256];
    
    	SIZE_T bytesread = 0;
    
    	BOOL bRet = ReadProcessMemory(hProc,pbi.PebBaseAddress,&peb,sizeof(peb),&bytesread);
    	bRet = ReadProcessMemory(hProc,peb.pinfoblock,&infoblock,sizeof(infoblock),&bytesread);
    	bRet = ReadProcessMemory(hProc,infoblock.cmdline,cmdline,256,&bytesread);
    
    	if (!bRet) {
    		MessageBox(NULL,"ReadProcessMemory failed","Error",MB_ICONERROR | MB_OK);
    		CloseHandle(hProc);
    		return -1;
    	}
    
    	CloseHandle(hProc);
    
    	MessageBoxW(NULL,cmdline,L"huhu",MB_OK);
    
    	return 0;
    }
    


  • Vielen Dank für Deinen Code, funktiniert prächtig. Die MSDN-Doku ist tatsächkich nicht hinreichend - da muss man schon mehr wissen.



  • Naja, wäre schon schön, wenn Microsoft solche Dinge doch etwas mehr dokumentieren würde. Sie könnten es ja als volatil oder sowas angeben, sodass man als Softwareentwickler darauf eingestellt sein muss, dass sich diese systemnahen Angelegenheiten mit einer neuen Version des Betriebssystems drastisch ändern könnten. In dem Fall hätte Microsoft ja weiterhin freie Hand und muss bei sowas nicht zu sehr auf Abwärtskompatibilität bei der Weiterentwicklung achten.



  • Jetzt die alles entscheidende Frage: Wofür brauch man die Kommandozeile eines anderen Prozesses? 😉



  • um z.b. eine gui für ein kommandozeilen programm zu machen prominentes beispiel dafür sind die serverschnittstelle cgi bzw die benutzung von php in servern

    aber normalerweise macht man das einfach mit der umleitung von stdin und stdout also standart input und output

    wenn jemand nen kleinen code dazu gebrauchen kann schreibt es ich stell dann die funktion hier rein ist zwar nicht fertig aber funktioniert schon halbwegs


Anmelden zum Antworten