2009-10-15 5 views
4

J'essaie de rediriger la sortie standard d'un processus déjà en cours d'exécution sur Windows XP en utilisant C#. Je suis conscient que je peux le faire si je lance le processus moi-même, mais pour cette application, je préférerais un "auditeur" que je pourrais simplement attacher à un autre processus.Est-il possible de pirater standard

Est-ce possible en .Net pur et si ce n'est pas possible avec Win32?

Merci

MISE À JOUR: Il y a plusieurs processus que je suis en train de surveiller qui sont tout a commencé par un processus de « gardien de la porte » qui relancera ces processus si l'accident. Cela rend difficile toute redirection à l'avance.

+0

Contrôlez-vous la source de l'application qui est déjà en cours d'exécution? Ou est-ce une application tierce que vous aimeriez gratter? – user7116

+0

L'application peut-elle être enveloppée dans un assembly .NET? Ce qui signifie que vous pouvez le lancer comme un processus dans le code que vous avez écrit, ou est-ce un service qui échoue s'il est enveloppé de cette façon. –

+0

@sixlettervariables: C'est une application interne mais je ne possède pas le code, et il serait difficile de faire des changements. @ Agent_9191: J'ai mis à jour la question pour répondre à votre commentaire. – Justin

Répondre

3

Ce serait assez facilement facile à faire dans Win32 en utilisant le Detours Library. Vous regardez tous les appels à WriteFile, et vérifiez s'ils vont à la sortie standard. Vous pouvez également consulter les fonctions de sortie de la console (par exemple WriteConsoleOutput), mais elles sont rarement utilisées, ce qui vous évite d'avoir à vous soucier de la plupart des programmes. Je ne me souviens pas si les détours supportent directement l'utilisation des langages .NET ou non. Si ce n'est pas le cas, je suppose que vous pourriez toujours l'utiliser via P/Invoke, mais je ne pense pas que ce serait joli du tout ...

Editer: Il existe plusieurs bibliothèques similaires (libres). Pour un exemple, le livre de Jeffrey Richter Advanced Windows utilisé pour en inclure un qui devrait fonctionner dans ce but. Un coup d'oeil rapide indique que son Windows actuel via C/C++ comprend toujours une section sur "l'injection de DLL et l'accrochage API." Cela inclut probablement (et une version mise à jour de) le même code, ce qui devrait être adéquat pour ce genre de travail.

+0

Très intéressant. Je n'ai jamais vu ça auparavant, mais ça a l'air vraiment cool. Je vais y jeter un coup d'oeil – Justin

+2

Malheureusement, la licence de détours me limite de l'utiliser dans un environnement commercial à moins que je ne paye des frais de 10 000 $ à temps. Donc, bien que ce soit cool, c'est un non. – Justin

1

La méthode SetOut vous permet de rediriger la sortie standard.

var sb = new StringBuilder(); 
using (var writer = new StringWriter(sb)) 
{ 
    Console.SetOut(writer); 
    Console.WriteLine("Hello World"); 
} 
var result = sb.ToString(); 
// The result variable will contain Hello World\r\n 
+2

Cela fonctionne uniquement pour votre propre console, pas pour la sortie standard d'un autre processus en cours d'exécution. – itowlson

+0

Je ne possède pas le code du processus que j'essaie de rediriger – Justin

0

Je n'ai pas l'expérience de le faire réellement, mais je pense que vous devriez jeter un oeil à ce StackOverflow question. La prochaine étape consisterait à ouvrir des objets associés à ces poignées pour la lecture et à déterminer en quelque sorte quelle est la sortie et l'erreur standard. Je doute que vous serez en mesure de détourner les poignées. Par exemple, imaginez le scénario où un autre processus a déjà redirigé la sortie standard et possède un handle et peut-être même utilisé un IPC pour que d'autres processus aient aussi ce handle.

Désolé de ne pas donner une réponse définitive si cela est possible. J'aimerais le savoir moi-même.

+0

Je vais regarder dans ce – Justin

0

Cela fera ce que vous cherchez Je ne savais pas si vous utilisiez C++ alors j'ai juste utilisé les conventions c. Vous devez nettoyer cela avant de l'utiliser. Je l'ai juste banni aussi assurez-vous de fermer les poignées au tuyau ou vous fuire.

// RunCmd.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 
#include <windows.h> 
#include <strsafe.h> 
int RunCmd(_TCHAR * Command,_TCHAR **OutPut); 
bool HasTerminated(PROCESS_INFORMATION PI,DWORD *ExitCode); 
bool HasData(HANDLE H); 
void ErrorExit(LPTSTR lpszFunction); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
_TCHAR * Buffer; 
_TCHAR CmdLine[] = _TEXT("Outputter.exe"); 
RunCmd(CmdLine,&Buffer); 
wprintf(_TEXT("Buffer from other pgm \n%s"),Buffer); 
free(Buffer); 
} 


int RunCmd(_TCHAR * Command,_TCHAR ** OutPut) 
{ 
_TCHAR * CpBUff = NULL; 
STARTUPINFO SI; 
memset(&SI,0,sizeof(SI)); 
*OutPut = NULL; 
SECURITY_ATTRIBUTES SA; 
SA.nLength = sizeof(SECURITY_ATTRIBUTES); 
SA.lpSecurityDescriptor = NULL; 
SA.bInheritHandle = true; 
HANDLE ReadOutPut, WriteOutPut; 
if(!CreatePipe(&ReadOutPut,&WriteOutPut,&SA,0)) 
{ 
    wprintf(_TEXT("Error")); 
} 
SI.hStdOutput = WriteOutPut; 
SI.cb = sizeof(STARTUPINFO); 
SI.dwFlags = STARTF_USESTDHANDLES; 
PROCESS_INFORMATION PI; 

if (!CreateProcess(NULL,Command,&SA,NULL,true,CREATE_NO_WINDOW,NULL,NULL,&SI,&PI)) 
{ 

    ErrorExit(TEXT("CreateProcess")); 
} 
Sleep(500); 
DWORD ExitCode; 
char Buffer[512]; 
_TCHAR ConvBuff[512]; 
int Total =0; 
bool Zero; 
while (!HasTerminated(PI,&ExitCode) & HasData(ReadOutPut)) 
{ 
    ZeroMemory(Buffer,512*sizeof(char)); 
    ZeroMemory(ConvBuff,512 * sizeof(_TCHAR)); 
    DWORD NumBytesRead; 
    ReadFile(ReadOutPut,Buffer,512,&NumBytesRead,NULL); 
    Zero = Total == 0; 
    Total += NumBytesRead +1; 
    *OutPut = ((_TCHAR *) realloc(*OutPut,Total*sizeof(_TCHAR))); 
    if(Zero) 
    { 
    ZeroMemory(*OutPut,Total * sizeof(_TCHAR)); 
    } 
    size_t ConChar; 
    mbstowcs_s(&ConChar,ConvBuff,strlen(Buffer)+1,Buffer,511); 
    StringCchCat(*OutPut,Total,ConvBuff); 
} 
CloseHandle(PI.hProcess); 
CloseHandle(PI.hThread); 
return ExitCode; 

} 

bool HasTerminated(PROCESS_INFORMATION PI,DWORD *ExitCode) 
{ 
return (STILL_ACTIVE == GetExitCodeProcess(PI.hProcess,ExitCode)); 
} 

bool HasData(HANDLE H) 
{ 
char Buffer[25]; 
DWORD ReadBytes,TotalBytes,TotalLeft; 

PeekNamedPipe(H,Buffer,25,&ReadBytes,&TotalBytes,&TotalLeft); 
return ReadBytes > 0; 

} 

void ErrorExit(LPTSTR lpszFunction) 
{ 
    // Retrieve the system error message for the last-error code 

    LPVOID lpMsgBuf; 
    LPVOID lpDisplayBuf; 
    DWORD dw = GetLastError(); 

    FormatMessage(
     FORMAT_MESSAGE_ALLOCATE_BUFFER | 
     FORMAT_MESSAGE_FROM_SYSTEM | 
     FORMAT_MESSAGE_IGNORE_INSERTS, 
     NULL, 
     dw, 
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
     (LPTSTR) &lpMsgBuf, 
     0, NULL); 

    // Display the error message and exit the process 

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
     (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
     LocalSize(lpDisplayBuf)/sizeof(TCHAR), 
     TEXT("%s failed with error %d: %s"), 
     lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 

    LocalFree(lpMsgBuf); 
    LocalFree(lpDisplayBuf); 
    ExitProcess(dw); 
}