VC 模拟CMD 匿名管道
#include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <stdlib.h> int Call(char Cmd[]) { SECURITY_ATTRIBUTES sa; HANDLE Hread,Hwrite; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; if (!CreatePipe(&Hread,&Hwrite,&sa,0)) { printf("Create Pipe in error\r\n"); return 0; } STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); GetStartupInfo(&si); si.hStdError = Hwrite; si.hStdOutput = Hwrite; si.wShowWindow = SW_HIDE; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; memset(&pi,0,sizeof(PROCESS_INFORMATION)); char cmdline[1024 ] = "cmd /c"; strcat(cmdline,Cmd); if (!CreateProcessA(NULL,cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)) { printf("Create process error\r\n"); return 0; } CloseHandle(Hwrite); char buff[1024] = {0}; //char cres[MAX_PATH] = {0}; DWORD bytesread; while (true) { if (ReadFile(Hread,buff,1024,&bytesread,NULL) == NULL) { break; } int ilen = strlen(buff); for (int i =0;i<ilen;i++) { if (buff[i] == '\n' || buff[i] == '\r') { buff[i] = '\0'; } } printf(buff); } CloseHandle(Hread); //sprintf() return 0; } int _tmain(int argc, _TCHAR* argv[]) { char* Cmd = argv[1]; Call(Cmd); return 0; }
使用管道CREATEPIPE,来进行进程间的相互通信,然后在进行数据的读取。
什么是管道,管道就是一种通信机制,也就是内存共享,一个进程向管道写入数据后,由另外一个管道读出。
匿名管道是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。
匿名管道由CreatePipe()函数创建,该函数在创建匿名管道的同时返回两个句柄:管道读句柄和管道写句
柄。CreatePipe()的函数原型为:
BOOL CreatePipe(
PHANDLE hReadPipe, // 指向读句柄的指针
PHANDLE hWritePipe, &nb sp; // 指向写句柄的指针
LPSECURITY_ATTRIBUTES lpPipeAttributes, // 指向安全属性的指针
DWORD nSize // 管道大小
);
返回值
Long,非零表示成功,零表示失败。会设置GetLastError
在调用CreatePipe()函数时,如果管道服务器将lpPipeAttributes 指向的SECURITY_ATTRIBUTES数据结构的数据成员bInheritHandle设置为TRUE,那么CreatePipe()创建的管道读、写句柄将会被继承。
在用WriteFile()函数向管道写入数据时,只有在向管道写完指定字节的数据后或是在有错误发生时函数才会返回。如管道缓冲已满而数据还没有写完,WriteFile()将要等到另一进程对管道中数据读取以释放出更多可用空间后才能够返回。管道服务器在调用CreatePipe()创建管道时以参数nSize对管道的缓冲大小作了设定。
匿名管道并不支持异步读、写操作,这也就意味着不能在匿名管道中使用ReadFileEx()和WriteFileEx(),而且ReadFile()和WriteFile()中的lpOverLapped参数也将被忽略。匿名管道将在读、写句柄都被关闭后退出,也可以在进程中调用CloseHandle()函数来关闭此句柄。
程序具体实现过程:
(1) 初始化安全属性的指针 //创建匿名管道前期,就得初始化安全属性的指针。
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = TRUE;
(2) 创建匿名管道 //开始创建匿名管道
HANDLE hReadPipe1,hWritePipe1;
CreatePipe(&hReadPipe1,&hWritePipe1,&sa,0);
(3) 创建cmd进程
BOOL CreateProcess(
LPCTSTR lpApplicationName, //可执行模块的字符串
LPTSTR lpCommandLine, //执行的命令行字符串
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles, //新进程是否从调用进程处继承了句柄
DWORD dwCreationFlags, //标志
LPVOID lpEnvironment, //新进程的环境块
LPCTSTR lpCurrentDirectory, //子进程的工作路径
LPSTARTUPINFO lpStartupInfo, //决定新进程的主窗体如何显示
LPPROCESS_INFORMATION lpProcessInformation //接收新进程的识别信息
);
在创建进程前,先初始化两个结构体:LPSTARTUPINFO 和LPPROCESS_INFORMATION
STARTUPINFO结构用于指定新进程的主窗口特性,应用程序必须将cb初始化为sizeof(STARTUPINFO)
STARTF_USESHOWWINDOW使用wShowWindow成员:wShowWindow用于设定如果子应用程序初次调用的ShowWindows将SW_SHOWDEFAULT作为nCmdShow参数传递时,该应用程序的第一个重叠窗口应该如何出现。
STARTF_USESTDHANDLES使用hstdInput、hstdOutput和hstdError成员:HANDLE hStdInput用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,hstdInput 用于标识键盘缓存,hstdOutput和hstdError用于标识控制台窗口的缓存。
STARTUPINFO si;
memset(&si,0,sizeof(si));
GetStartupInfo(&si); //该函数返回进程在启动时被指定的STARTUPINFO 结构
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdOutput = si.hStdError = hWritePipe1;
PROCESS_INFORMATION pInfo;
memset(&pInfo,0,sizeof(PROCESS_INFORMATION));
创建进程
char szCmd[MAXLENGTH] = "cmd.exe /c";
//接收远程传入的进程执行参数
int dwSize = ((RatProto*)szRecvCmd)->RatLen - sizeof(RatProto);
strncat(szCmd,szRecvCmd+sizeof(RatProto),dwSize);
CreateProcessA(NULL,szCmd,NULL,NULL,1,0,NULL,NULL,&si,&pInfo);
(3) 通过管道通信,得到进程执行结果
memset(szCmd,0,MAXLENGTH);
int dwRead;
//判断管道内是否有传入数据
int nRet = PeekNamedPipe(hReadPipe1,szCmd,MAXLENGTH,(LPDWORD)&dwRead,NULL,NULL);
for (int i=0;i<5&&dwRead==0;i++)
{
Sleep(100);
nRet = PeekNamedPipe(hReadPipe1,szCmd,MAXLENGTH,(LPDWORD)&dwRead,NULL,NULL);
}
if (dwRead)
{
nRet = ReadFile(hReadPipe1,szCmd,dwRead,(LPDWORD)&dwRead,0);
if (!nRet)
{
sprintf(szCmd,"%s","CMD COMMAND EXCUTE ERROR!");
}
}
(4) 将执行结果传给客户端
.......