前几天问了朋友关于怎样捕捉控制台信息的问题,原来是用了管道技术,而且我这儿还有这方面的资料,只是我平时没注意罢了,真是.......
下面就简单介绍一下管道,说白了就是进程或网络间通信,有两种管道,即有名管道和匿名管道。匿名管道就是没有名字的管道了,也就是说在使用它们时不需要知道其名字。而有名管道正好相反,在使用前必须知道其名字。
也可以根据管道的特性来分类,即是单向的还是双向的。单向管道,数据只能沿一个方向移动,从一端流向另一端,而双向管道数据可以在两端间自由交换。匿名管道通常是单向的而有名管道通常是双向的。有名管道常用于一个服务器联络多个客户端的网络环境。
网络的我不了解,先说说进程的罢,我这人表达能力不行,就举个例子吧,比如说我们现在要捕捉ping程序的输出信息用管道就很容易实现,我们首先在程序中创建一个管道(通过CreatePipe)这样我们就得到了一个管道的写端口和一个读端口,然后我们通过CreateProcess创建控制台子进程,其中要用到STARTUPINFO这个结构,这个结构中就有控制台的三个标准句柄,(输入,输出,错误)我们要做的就是把上面CreatePipe中得到的写端口送给这里的输出端口,这样控制台应用程序的输出就会被我们偷偷的捕捉了,而它不知道这一切,它还是以为它是向控制台做标准输出,是不是挺爽的.说了这么多的废话下面是一个捕获PING程序输出信息的小程序,大家将就着看看吧!别扔砖啊!
#include "windows.h"
#include "resource.h"
HWND hInst;
LRESULT CALLBACK PING(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD hWrite,hRead;
STARTUPINFO startupinfo;
PROCESS_INFORMATION pinfo;
SECURITY_ATTRIBUTES sat;
TCHAR szBuffer[1024],ipBuffer[20];
int bytesRead;
HWND hwndEdit;
switch (message)
{
case WM_INITDIALOG:
SendMessage(hDlg,WM_SETICON,ICON_BIG,LoadIcon(hInst,ICO_PING));
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_EXIT:
EndDialog(hDlg, LOWORD(wParam));
break;
case IDOK:
RtlZeroMemory(ipBuffer,20);
strcpy(ipBuffer,"ping ");
GetDlgItemText(hDlg,IDC_IPADDRESS,ipBuffer+5,20);
hwndEdit=GetDlgItem(hDlg,IDC_OUTINFOR);
sat.nLength=sizeof(SECURITY_ATTRIBUTES);
sat.bInheritHandle=TRUE;
sat.lpSecurityDescriptor=NULL;
if(CreatePipe(&hRead,&hWrite,&sat,0)==0) //创建匿名管道
MessageBox(hDlg,TEXT("创建管道失败"),TEXT("PING"),MB_OK);
else
{
startupinfo.cb=sizeof(STARTUPINFO);
GetStartupInfo(&startupinfo);
startupinfo.hStdOutput=hWrite; //用管道的写端代替控制台程序的输出端以便得到输出的信息
startupinfo.hStdError=hWrite;
startupinfo.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES ;
startupinfo.wShowWindow=SW_HIDE; //隐藏控制台程序窗口
if(CreateProcess(NULL, ipBuffer,NULL,NULL,TRUE,NULL,NULL,NULL,&startupinfo,&pinfo)==NULL)
MessageBox(hDlg,TEXT("创建进程失败"),TEXT("PING"),MB_OK);
else
{
CloseHandle(hWrite); //关关闭写端,因为写端已经给了控制台程序,不能存在两个写端
while(TRUE)
{
RtlZeroMemory(szBuffer,1024);
if(ReadFile(hRead,szBuffer,1023,&bytesRead,NULL)==NULL) //注意ReadFile的第一个参数正是读端的句柄
break;
SendMessage(hwndEdit,EM_SETSEL,-1,0);
SendMessage(hwndEdit,EM_REPLACESEL,FALSE,szBuffer); //循环读入信息直到没有信息可读
}
}
CloseHandle(hWrite);
}
break;
}
return TRUE;
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
hInst=hInstance;
DialogBoxParam(hInstance,(LPCTSTR)DLG_MAIN,NULL,(DLGPROC)PING,NULL);
return 0;
}
下面就简单介绍一下管道,说白了就是进程或网络间通信,有两种管道,即有名管道和匿名管道。匿名管道就是没有名字的管道了,也就是说在使用它们时不需要知道其名字。而有名管道正好相反,在使用前必须知道其名字。
也可以根据管道的特性来分类,即是单向的还是双向的。单向管道,数据只能沿一个方向移动,从一端流向另一端,而双向管道数据可以在两端间自由交换。匿名管道通常是单向的而有名管道通常是双向的。有名管道常用于一个服务器联络多个客户端的网络环境。
网络的我不了解,先说说进程的罢,我这人表达能力不行,就举个例子吧,比如说我们现在要捕捉ping程序的输出信息用管道就很容易实现,我们首先在程序中创建一个管道(通过CreatePipe)这样我们就得到了一个管道的写端口和一个读端口,然后我们通过CreateProcess创建控制台子进程,其中要用到STARTUPINFO这个结构,这个结构中就有控制台的三个标准句柄,(输入,输出,错误)我们要做的就是把上面CreatePipe中得到的写端口送给这里的输出端口,这样控制台应用程序的输出就会被我们偷偷的捕捉了,而它不知道这一切,它还是以为它是向控制台做标准输出,是不是挺爽的.说了这么多的废话下面是一个捕获PING程序输出信息的小程序,大家将就着看看吧!别扔砖啊!
#include "windows.h"
#include "resource.h"
HWND hInst;
LRESULT CALLBACK PING(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD hWrite,hRead;
STARTUPINFO startupinfo;
PROCESS_INFORMATION pinfo;
SECURITY_ATTRIBUTES sat;
TCHAR szBuffer[1024],ipBuffer[20];
int bytesRead;
HWND hwndEdit;
switch (message)
{
case WM_INITDIALOG:
SendMessage(hDlg,WM_SETICON,ICON_BIG,LoadIcon(hInst,ICO_PING));
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_EXIT:
EndDialog(hDlg, LOWORD(wParam));
break;
case IDOK:
RtlZeroMemory(ipBuffer,20);
strcpy(ipBuffer,"ping ");
GetDlgItemText(hDlg,IDC_IPADDRESS,ipBuffer+5,20);
hwndEdit=GetDlgItem(hDlg,IDC_OUTINFOR);
sat.nLength=sizeof(SECURITY_ATTRIBUTES);
sat.bInheritHandle=TRUE;
sat.lpSecurityDescriptor=NULL;
if(CreatePipe(&hRead,&hWrite,&sat,0)==0) //创建匿名管道
MessageBox(hDlg,TEXT("创建管道失败"),TEXT("PING"),MB_OK);
else
{
startupinfo.cb=sizeof(STARTUPINFO);
GetStartupInfo(&startupinfo);
startupinfo.hStdOutput=hWrite; //用管道的写端代替控制台程序的输出端以便得到输出的信息
startupinfo.hStdError=hWrite;
startupinfo.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES ;
startupinfo.wShowWindow=SW_HIDE; //隐藏控制台程序窗口
if(CreateProcess(NULL, ipBuffer,NULL,NULL,TRUE,NULL,NULL,NULL,&startupinfo,&pinfo)==NULL)
MessageBox(hDlg,TEXT("创建进程失败"),TEXT("PING"),MB_OK);
else
{
CloseHandle(hWrite); //关关闭写端,因为写端已经给了控制台程序,不能存在两个写端
while(TRUE)
{
RtlZeroMemory(szBuffer,1024);
if(ReadFile(hRead,szBuffer,1023,&bytesRead,NULL)==NULL) //注意ReadFile的第一个参数正是读端的句柄
break;
SendMessage(hwndEdit,EM_SETSEL,-1,0);
SendMessage(hwndEdit,EM_REPLACESEL,FALSE,szBuffer); //循环读入信息直到没有信息可读
}
}
CloseHandle(hWrite);
}
break;
}
return TRUE;
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
hInst=hInstance;
DialogBoxParam(hInstance,(LPCTSTR)DLG_MAIN,NULL,(DLGPROC)PING,NULL);
return 0;
}