大家好,又见面了,我是你们的朋友全栈君。
0x01.CreatePipe函数
管 道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另 一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。
先详细介绍一下管道,这里以匿名管道为例: 第一:匿名管道只能实现本地进程之间的通信,不能实现跨网络之间的进程间的通信。 第二:匿名管道只能实现父进程和子进程之间的通信,而不能实现任意两个本地进程之间的通信。
创建管道函数原型:
代码语言:javascript复制BOOL WINAPI CreatePipe(
_Out_ PHANDLE hReadPipe,
_Out_ PHANDLE hWritePipe,
_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,
_In_ DWORD nSize
);
返回值
如果函数成功,返回值不为零。 如果函数失败,返回值为零。要获取扩展错误信息,请调用GetLastError。
备注
CreatePipe
创建管道,将指定的管道大小分配给存储缓冲区。 CreatePipe
还会在随后的ReadFile
和WriteFile
函数调用中创建该进程用于读取和写入缓冲区的句柄。
要从管道读取,一个进程在调用ReadFile
函数时使用读取句柄。当以下任一条件为真时,ReadFile
返回:写操作在管道的写入端完成,请求的字节数已被读取或发生错误。
当一个进程使用WriteFile
写入匿名管道时,写操作在所有字节都被写入之前不会完成。如果在写入所有字节之前管道缓冲区已满,则WriteFile
不会返回,直到另一个进程或线程使用ReadFile
来创建更多的缓冲区空间。
使用具有唯一名称的命名管道实现匿名管道。因此,您经常可以将匿名管道的句柄传递给需要命名管道句柄的函数。
如果CreatePipe
失败,输出参数的内容是不确定的。在这个事件中,不应该假设他们的内容。
要释放管道使用的资源,应用程序应该不再需要关闭句柄,这可以通过调用CloseHandle
函数或与实例句柄关联的进程结束。请注意,管道的一个实例可能有多个与之关联的句柄。当命名管道的实例的最后一个句柄关闭时,管道的实例总是被删除。
0x02、CreateProcess
创建一个新进程及其主要线程。新进程在调用进程的安全上下文中运行。
代码语言:javascript复制BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);
0x03.example
代码语言:javascript复制#include <iostream>
#include <windows.h>
#include <Shlwapi.h>
using namespace std;
#define BUFSIZE 4096
int main()
{
BOOL bRet = FALSE;
DWORD dwRead = 0;
DWORD dwAvail = 0;
char cbBuf[4096] = { 0 };
HANDLE hReadPipe = NULL;
HANDLE hWritePipe = NULL;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
char *pCommandLine = new TCHAR[0x200];//
char szPath[] = "C:\Windows\System32\calc.exe";
CreatePipe(&hReadPipe, &hWritePipe, &sa, 0);
STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdError = hWritePipe;
si.hStdOutput = hWritePipe;
PROCESS_INFORMATION pi = { 0 };
memset(pCommandLine, 0, sizeof(szPath));
lstrcpy(pCommandLine, szPath);
if (!CreateProcess(NULL, pCommandLine, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))//创建子进程
{
if (pCommandLine)
delete pCommandLine;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
return 1;
}
std::string strResult;
do
{
cout << "test.." << endl;
if (!PeekNamedPipe(hReadPipe, NULL, NULL, &dwRead, &dwAvail, NULL) || dwAvail <= 0)//PeekNamePipe用来预览一个管道中的数据,用来判断管道中是否为空
{
break;
}
if (ReadFile(hReadPipe, cbBuf, BUFSIZE, &dwRead, NULL))//这里是读管道,即便已经没有数据,仍然会等待接收数据,因为,子进程会认为父进程仍有数据要发送,只是暂时没法送,
{ //所以,会“卡”在这里。所以才需要PeekNamePipe
if (dwRead == 0)
break;
cout << dwRead << endl;
cout << cbBuf << endl;
}
} while (TRUE);
if (pCommandLine)
delete pCommandLine;
cout << "delete" << endl;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
return 0;
}
例二:
直接程序放入主程序:
代码语言:javascript复制 HANDLE hRead,hWrite;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL; //使用系统默认的安全描述符
sa.bInheritHandle = TRUE; //创建的进程继承句柄
if (!CreatePipe(&hRead,&hWrite,&sa,0)) //创建匿名管道
{
MessageBox("CreatePipe Failed!","提示",MB_OK | MB_ICONWARNING);
return;
}
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;
char cmdline[200];
CString tmp,stredit2;
GetDlgItemText(IDC_EDIT2,stredit2); //获取编辑框中输入的命令行
tmp.Format("cmd /C %s",stredit2);
sprintf(cmdline,"%s",tmp);
if (!CreateProcess(NULL,cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)) //创建子进程
{
MessageBox("CreateProcess Failed!","提示",MB_OK | MB_ICONWARNING);
return;
}
CloseHandle(hWrite); //关闭管道句柄
char buffer[4096] = {
0};
CString strOutput;
DWORD bytesRead;
while (true)
{
if (ReadFile(hRead,buffer,4095,&bytesRead,NULL) == NULL) //读取管道
break;
strOutput = buffer;
SetDlgItemText(IDC_EDIT1,strOutput); //显示输出信息到编辑框,并刷新窗口
UpdateWindow();
Sleep(100);
}
CloseHandle(hRead);
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/159395.html原文链接:https://javaforall.cn