是否有可能劫持标准出

问题描述:

我想重定向已经运行的进程在Windows XP上使用C#的标准输出。我意识到,如果我自己产生这个过程,我可以做到这一点,但是对于这个应用程序,我更喜欢一个“侦听器”,我可以将它附加到另一个进程。是否有可能劫持标准出

这是纯粹的.Net中可能的,如果不是,甚至可以使用Win32吗?

感谢

UPDATE:有都是由一个“守门人”的过程,如果他们崩溃,将重新启动这些进程启动多个进程我想显示器。这使我很难事先做任何重定向。

+0

您是否将源代码控制到已运行的应用程序?或者这是你想要刮的一些第三方应用程序? – user7116 2009-10-15 20:25:25

+0

应用程序是否可以包装在.NET程序集中?这意味着你可以将它作为你写的代码中的一个进程来启动它,或者如果它以这种方式结束,它就是一个失败的服务。 – 2009-10-15 20:34:42

+0

@sixlettervariables:这是一个内部应用程序,但我不拥有代码,并且很难进行更改。 @ Agent_9191:我更新了问题以解决您的评论。 – Justin 2009-10-15 21:08:27

这将是相当容易在Win32中使用Detours Library来做到这一点。你会看到所有对WriteFile的调用,并检查他们是否要进行标准输出。您可能还想查看控制台输出函数(例如WriteConsoleOutput),但它们使用的很少,您可能不需要为大多数程序使用而烦恼。

副手我不记得是否detours直接支持从.NET语言使用或不。如果它不,我想你仍然可以通过P/Invoke使用它,但我认为它不会很漂亮......

编辑:有各种类似的(免费)库。举一个例子,Jeffrey Richter的书Advanced Windows曾经包括一个应该为此目的工作的书。快速查看表明,他目前使用Windows的Windows通过C/C++仍包含“DLL注入和API挂钩”部分。这可能包括(和更新版本)相同的代码,对于这类工作应该足够了。

+0

非常有趣。我从来没有见过这个,但它看起来非常酷。我会研究它 – Justin 2009-10-15 21:00:34

+2

不幸的是,绕道许可证限制了我在商业环境中使用它,除非我按时支付$ 10,000的费用。所以,虽然很酷,但这是不行的。 – Justin 2009-10-15 21:05:08

SetOut方法允许您重定向标准输出。

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

这仅适用于您自己的控制台,不适用于其他正在运行的进程的标准输出。 – itowlson 2009-10-15 20:41:11

+0

我没有自己的代码,我试图重定向 – Justin 2009-10-15 20:58:11

我没有实际操作的经验,但我认为你应该看看这个* question。下一步是打开与阅读器相关的对象,并以某种方式确定哪一个是标准输出和错误。我怀疑你将能够劫持手柄。例如,想象一下当某些其他进程已经重定向标准输出并拥有一个句柄并且甚至可能使用某个IPC来让其他进程也具有该句柄时的场景。

抱歉没有给出明确的答案,这是否可能。我想亲自知道这一点。

+0

我会考虑这个 – Justin 2009-10-15 21:10:17

这将做你所寻找的我不知道你是否使用C++所以我只使用c约定。在使用之前,您需要清理干净这个问题我只是把它放开,同时确保关闭手柄,否则会漏水。

// 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); 
}