管道

命名管道

匿名管道-父子进程之间的数据传输

创建:CreatePipe

读:ReadFile

写:WriteFile

获取句柄:GetStdHandle

查看管道是否有数据可读:PeekNamedPipe

image-20240709124215672

image-20240709124240554

image-20240709131232272

新建两个MFC应用程序

image-20240709123646396

image-20240709123812999

image-20240709130847927

ParentDlg.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

// ParentDlg.h: 头文件
//

#pragma once


// CParentDlg 对话框
class CParentDlg : public CDialogEx
{
// 构造
public:
CParentDlg(CWnd* pParent = nullptr); // 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_PARENT_DIALOG };
#endif

protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持


// 实现
protected:
HICON m_hIcon;
HANDLE m_hRead = NULL;//
HANDLE m_hWrite = NULL;//添加两个句柄
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
};

ParentDlg.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void CParentDlg::OnBnClickedButton1()
{
//创建管道
BOOL bRet = ::CreatePipe(&m_hRead, &m_hWrite, NULL, 0);
if (!bRet)
{
AfxMessageBox("创建管道失败");
return;
}
//创建子进程
STARTUPINFO si = {};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = m_hRead;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
"Child.exe", // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

image-20240709131048635

修改Child的输出路径

image-20240709131524806

image-20240709133402181

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void CChildDlg::OnBnClickedButton1()
{
HANDLE hInput = ::GetStdHandle(STD_INPUT_HANDLE);

DWORD dwBytesAvail = 0;
BOOL bRet = ::PeekNamedPipe(hInput, NULL, 0, NULL, &dwBytesAvail, NULL);
if (!bRet)
{
AfxMessageBox("无法查看管道剩余数据");
return;
}
//管道中有数据再读
if (dwBytesAvail > 0)
{
CString strBuf;
DWORD dwBytesToRead = 0;
BOOL bRet = ::ReadFile(
hInput,
strBuf.GetBufferSetLength(MAXBYTE),
MAXBYTE,
&dwBytesToRead,
NULL
);
if (!bRet)
{
AfxMessageBox("读取数据失败");
return;
}
strBuf.ReleaseBuffer(dwBytesToRead);
SetDlgItemText(EDT_READ, strBuf);
}
}

运行Parent,点击创建子进程,则可以创建一个Child进程

image-20240709132940017

在Parent里面写入数据,然后子进程可以读取数据

image-20240709133047282

image-20240709152416755

image-20240709152435724

新建句柄

image-20240709152951856

修改编辑框设置

image-20240709155207365

ParentDlg.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
void CParentDlg::OnBnClickedButton3()
{
//创建管道
SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
::CreatePipe(&m_hSelfRead, &m_hCmdWrite, &sa, 0);
::CreatePipe(&m_hCmdRead, &m_hSelfWrite, &sa, 0);

//创建子进程
STARTUPINFO si = {};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = m_hCmdRead;
si.hStdOutput = m_hCmdWrite;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
"cmd.exe", // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}


void CParentDlg::OnBnClickedButton4()
{
CString strBuf;
GetDlgItemText(EDT_COMD, strBuf);
strBuf += "\r\n";
BOOL bRet = WriteFile(m_hSelfWrite, strBuf.GetBuffer(), strBuf.GetLength(), NULL, NULL);
if (!bRet)
{
AfxMessageBox("写入管道失败");
}
}


void CParentDlg::OnBnClickedButton5()
{
DWORD dwBytesAvail = 0;
BOOL bRet = ::PeekNamedPipe(m_hSelfRead, NULL, 0, NULL, &dwBytesAvail, NULL);
if (!bRet)
{
AfxMessageBox("无法查看管道剩余数据");
return;
}
//管道中有数据再读
if (dwBytesAvail > 0)
{
CString strBuf;
DWORD dwBytesToRead = 0;
BOOL bRet = ::ReadFile(
m_hSelfRead,
strBuf.GetBufferSetLength(MAXBYTE),
MAXBYTE,
&dwBytesToRead,
NULL
);
if (!bRet)
{
AfxMessageBox("读取数据失败");
return;
}
strBuf.ReleaseBuffer(dwBytesToRead);
SetDlgItemText(EDT_SHOW, strBuf);
}
}

分析:

1
2
3
4
5
6
7
8
9
::CreatePipe(&m_hSelfRead, &m_hCmdWrite, &sa, 0);
::CreatePipe(&m_hCmdRead, &m_hSelfWrite, &sa, 0);

//创建子进程
STARTUPINFO si = {};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = m_hCmdRead;
si.hStdOutput = m_hCmdWrite;

第一个管道:::CreatePipe(&m_hSelfRead, &m_hCmdWrite, &sa, 0);

  • m_hSelfRead:父进程读取句柄。父进程通过这个句柄从管道中读取数据,即从子进程cmd.exe的输出中读取数据
  • m_hCmdWrite:子进程写入句柄。子进程通过这个句柄向管道中写入数据,即将cmd.exe的输出写入管道

第二个管道:::CreatePipe(&m_hCmdRead, &m_hSelfWrite, &sa, 0);

  • m_hCmdRead:子进程读取句柄。子进程通过这个句柄从管道中读取数据,即从父进程输入的数据
  • m_hSelfWrite:父进程写入句柄。父进程通过这个句柄向管道中写入数据,即将命令输入到cmd.exe

STARTUPINFO结构体中,si.hStdInputsi.hStdOutput应该分别设置为用于输入和输出的管道句柄,一编父进程可以通过这些句柄与子进程cmd.exe进行通信。正确的设置方式如下:

  1. si.hStdInput:设置为子进程的读取句柄m_hCmdRead(由句柄m_hSelfWrite写入,m_hCmdRead在子进程读出)这意味着子进程将从此管道中读取数据
  2. si.hStdOutput:设置为子进程的读取句柄m_hCmdWrite(由句柄m_hCmdWrite写入,m_hSelfRead在父进程读出)这意味着子进程将把输出数据写入此管道

运行后点击启动cmd可以打开cmd窗口

image-20240709164325669

点击读取回显可以读取cmd窗口的回显

image-20240709164424700

输入命令后再读取回显可以读取cmd窗口输入命令后的回显

image-20240709164524452

进程遍历

进程快照

创建快照:CreateToolhelp32Snapshot

GetDesktopwindow

GetChildWindow-GetnextWindow

image-20240709162540001

第一个参数是保存快照的信息,第二个参数保存指定线程的信息

image-20240709162833586

image-20240709162906785

image-20240709162944443

image-20240709163118845

image-20240709163101521

image-20240709163210556

例子:Taking a Snapshot and Viewing Processes

image-20240709163531161

新建控制台应用

image-20240709163702103

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// ProcessList.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include <TlHelp32.h>
#include <stdio.h>
BOOL GetProcessModule(DWORD dwPID, char* szExeName,
LPMODULEENTRY32 lpMe32, DWORD cbMe32)
{
BOOL bRet = FALSE;
BOOL bFound = FALSE;
HANDLE hModuleSnap = NULL;
MODULEENTRY32 me32 = { 0 };

// Take a snapshot of all modules in the specified process.

hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
return (FALSE);

// Fill the size of the structure before using it.

me32.dwSize = sizeof(MODULEENTRY32);

// Walk the module list of the process, and find the module of
// interest. Then copy the information to the buffer pointed
// to by lpMe32 so that it can be returned to the caller.

if (Module32First(hModuleSnap, &me32))
{
do
{
if (strcmp(szExeName, me32.szModule) == 0)
{
CopyMemory(lpMe32, &me32, cbMe32);
bFound = TRUE;
}
} while (!bFound && Module32Next(hModuleSnap, &me32));

bRet = bFound; // if this sets bRet to FALSE, dwModuleID
// no longer exists in specified process
}
else
bRet = FALSE; // could not walk module list

// Do not forget to clean up the snapshot object.

CloseHandle(hModuleSnap);

return (bRet);
}
BOOL GetProcessList()
{
HANDLE hProcessSnap = NULL;
BOOL bRet = FALSE;
PROCESSENTRY32 pe32 = { 0 };
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return (FALSE);
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hProcessSnap, &pe32))
{
DWORD dwPriorityClass;
BOOL bGotModule = FALSE;
MODULEENTRY32 me32 = { 0 };
do
{
bGotModule = GetProcessModule(pe32.th32ProcessID,
pe32.szExeFile, &me32, sizeof(MODULEENTRY32));
if (bGotModule)
{
HANDLE hProcess;
hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE, pe32.th32ProcessID);
dwPriorityClass = GetPriorityClass(hProcess);
CloseHandle(hProcess);
printf("PID\t\t\t%d\n", pe32.th32ProcessID);
printf("Thread Count\t\t%d\n", pe32.cntThreads);
printf("Module Name\t\t%s\n", me32.szModule);
printf("Full Path\t\t%s\n\n", me32.szExePath);

}
}
while (Process32Next(hProcessSnap, &pe32));
bRet = TRUE;
}
else
bRet = FALSE;
CloseHandle(hProcessSnap);
return (bRet);
}

int main()
{
GetProcessList();
std::cout << "Hello World!\n";
}

运行结果

image-20240709221323960

image-20240709221252376

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// ProcessList.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <windows.h>
#include <TlHelp32.h>
#include <stdio.h>
BOOL GetProcessModule(DWORD dwPID, char* szExeName,
LPMODULEENTRY32 lpMe32, DWORD cbMe32)
{
BOOL bRet = FALSE;
BOOL bFound = FALSE;
HANDLE hModuleSnap = NULL;
MODULEENTRY32 me32 = { 0 };

// Take a snapshot of all modules in the specified process.

hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
return (FALSE);

// Fill the size of the structure before using it.

me32.dwSize = sizeof(MODULEENTRY32);

// Walk the module list of the process, and find the module of
// interest. Then copy the information to the buffer pointed
// to by lpMe32 so that it can be returned to the caller.

if (Module32First(hModuleSnap, &me32))
{
do
{
if (strcmp(szExeName, me32.szModule) == 0)
{
CopyMemory(lpMe32, &me32, cbMe32);
bFound = TRUE;
}
} while (!bFound && Module32Next(hModuleSnap, &me32));

bRet = bFound; // if this sets bRet to FALSE, dwModuleID
// no longer exists in specified process
}
else
bRet = FALSE; // could not walk module list

// Do not forget to clean up the snapshot object.

CloseHandle(hModuleSnap);

return (bRet);
}
BOOL GetProcessList()
{
HANDLE hProcessSnap = NULL;
BOOL bRet = FALSE;
PROCESSENTRY32 pe32 = { 0 };
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return (FALSE);
}
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hProcessSnap, &pe32))
{
DWORD dwPriorityClass;
BOOL bGotModule = FALSE;
MODULEENTRY32 me32 = { 0 };
do
{
bGotModule = GetProcessModule(pe32.th32ProcessID,
pe32.szExeFile, &me32, sizeof(MODULEENTRY32));
if (bGotModule)
{
HANDLE hProcess;
hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE, pe32.th32ProcessID);
dwPriorityClass = GetPriorityClass(hProcess);
CloseHandle(hProcess);
printf("PID\t\t\t%d\n", pe32.th32ProcessID);
printf("Thread Count\t\t%d\n", pe32.cntThreads);
printf("Module Name\t\t%s\n", me32.szModule);
printf("Full Path\t\t%s\n\n", me32.szExePath);

}
}
while (Process32Next(hProcessSnap, &pe32));
bRet = TRUE;
}
else
bRet = FALSE;
CloseHandle(hProcessSnap);
return (bRet);
}

BOOL CALLBACK EnumWindowsProc(HWND hwnd,
LPARAM lParam
)
{
char szBuff[MAXBYTE] = {};
GetWindowText(hwnd, szBuff, MAXBYTE);
printf("%s \r\n", szBuff);
return TRUE;//一直遍历,直到所有窗口都被遍历完
}
int main()
{
//GetProcessList();
EnumWindows(EnumWindowsProc, NULL);
std::cout << "Hello World!\n";
}

运行结果

image-20240709224132924

image-20240709224137735