Windows

管道

管道分为命名管道、匿名管道

命名管道

命名管道是一个命名的管道服务器和一个或多个管道客户端之间的通信。命名管道的所有实例共享相同的管道名称,但每个实例都有自己的缓冲区和句柄,并为客户端/服务器通信提供单独的管道。一个命名管道链接多个管道客户端

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

创建: createpipe

读: readfile

写: writefile

获取句柄:GetStdHandle

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

img

img

img

img

于上述结构体中的句柄一一对应

父进程:

img

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
void CParentDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
//创建管道

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
)
{
AfxMessageBox("CreateProcess falied.");
return;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

void CParentDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
CString strBuf;
GetDlgItemText(EDT_WRITE, strBuf);
BOOL bRet = WriteFile(m_hWrite,strBuf.GetBuffer(),strBuf.GetLength(),NULL,NULL);
if (!bRet) {
AfxMessageBox("写入管道失败 ");
}
}

子进程:

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void CChildDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
HANDLE hInput = ::GetStdHandle(STD_INPUT_HANDLE);
CString strBuf;
DWORD dwByteToRead = 0;
BOOL bRet = ::ReadFile(hInput,
strBuf.GetBufferSetLength(MAXBYTE),
MAXBYTE,
&dwByteToRead,
NULL);
if (!bRet) {
AfxMessageBox("读取数据失败");
}
strBuf.ReleaseBuffer(dwByteToRead);
SetDlgItemText(EDT_READ, strBuf);
}

img

由于使用的句柄错误 导致子进程无法读取数据

句柄类型:

img

将创建管道的API修改 获取正确的句柄

1
2
3
4
5
6
7
8
SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
BOOL bRet=CreatePipe(&m_hRead,&m_hWrite,&sa,0);
if (!bRet) {
AfxMessageBox("创建管道失败");
return ;
}

img

当写入的数据为空时 readfile会阻塞进程 直到写入的数据不为空

用peeknamedpipe即可+

img

可以从匿名管道或者命名管道中获取数据且不会将数据从管道移除

参数5:缓冲区中还有多少数据可读

参数6:还有多少数据没读 (一般为0)

child:

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
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 dwByteToRead = 0;
BOOL bRet = ::ReadFile(hInput,
strBuf.GetBufferSetLength(MAXBYTE),
MAXBYTE,
&dwByteToRead,
NULL);
if (!bRet) {
AfxMessageBox("读取数据失败");
return;
}
strBuf.ReleaseBuffer(dwByteToRead);
SetDlgItemText(EDT_READ, strBuf);
}

子进程向父进程传输数据 需再添加一条匿名管道

调用cmd 从cmd获得回显

img

img

修改编辑框设置

img

添加两条管道

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

img

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
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
)
{
AfxMessageBox("CreateProcess falied.");
return;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}


void CParentDlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
CString strBuf;
GetDlgItemText(EDT_COMD, strBuf);
BOOL bRet = WriteFile(m_hSelfWrite, strBuf.GetBuffer(), strBuf.GetLength(), NULL, NULL);
if (!bRet) {
AfxMessageBox("写入管道失败 ");
}
}


void CParentDlg::OnBnClickedButton5()
{
// TODO: 在此添加控件通知处理程序代码
DWORD dwBytesAvail = 0;
BOOL bRet = PeekNamedPipe(m_hSelfRead,
NULL,
0,
NULL,
&dwBytesAvail,
NULL);
if (!bRet) {
AfxMessageBox("无法查看管道剩余数据");
return;
}
//管道中有数据可读
if (dwBytesAvail > 0) {
CString strBuf;
DWORD dwByteToRead = 0;
BOOL bRet = ::ReadFile(m_hSelfRead,
strBuf.GetBufferSetLength(MAXBYTE),
MAXBYTE,
&dwByteToRead,
NULL);
if (!bRet) {
AfxMessageBox("读取数据失败");
return;
}
strBuf.ReleaseBuffer(dwByteToRead);
SetDlgItemText(EDT_SHOW, strBuf);
}
}

img

img

但是向cmd输入命令dir 再次读取回显 发现cmd并没有返回数据 (缺少回车键这个命令)

img

1
2
3
4
5
6
7
8
9
10
11
void CParentDlg::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
CString strBuf;
GetDlgItemText(EDT_COMD, strBuf);
strBuf += "\r\n";//添加回车
BOOL bRet = WriteFile(m_hSelfWrite, strBuf.GetBuffer(), strBuf.GetLength(), NULL, NULL);
if (!bRet) {
AfxMessageBox("写入管道失败 ");
}
}

img

同时给的缓冲区较小需要多次读取回显 才可完整获得

进程遍历

进程快照

创建快照: CreateToolhelp32Snapshot

img

参数1:标志 快照中保存什么信息

参数2:进程ID 只对TH32CS_SNAPHEAPLIST or TH32CS_SNAPMODULE 起作用(其他时为可忽略)

一个进程可以有多个模块、多个线程

获取相关信息的API

img

以进程为例(其他与进程相似)

img

参数1:快照的句柄

进程相关信息

img

img

示例:

img

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// ProcessList.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//


#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <stdio.h>

// Forward declarations:
BOOL GetProcessList();
BOOL ListProcessModules(DWORD dwPID);
BOOL ListProcessThreads(DWORD dwOwnerPID);
void printError(TCHAR const* msg);

int main(void)
{
GetProcessList();
return 0;
}
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 ListProcessModules(DWORD dwPID)
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;

// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
{
printError(TEXT("CreateToolhelp32Snapshot (of modules)"));
return(FALSE);
}

// Set the size of the structure before using it.
me32.dwSize = sizeof(MODULEENTRY32);

// Retrieve information about the first module,
// and exit if unsuccessful
if (!Module32First(hModuleSnap, &me32))
{
printError(TEXT("Module32First")); // show cause of failure
CloseHandle(hModuleSnap); // clean the snapshot object
return(FALSE);
}

// Now walk the module list of the process,
// and display information about each module
do
{
_tprintf(TEXT("\n\n MODULE NAME: %s"), me32.szModule);
_tprintf(TEXT("\n Executable = %s"), me32.szExePath);
_tprintf(TEXT("\n Process ID = 0x%08X"), me32.th32ProcessID);
_tprintf(TEXT("\n Ref count (g) = 0x%04X"), me32.GlblcntUsage);
_tprintf(TEXT("\n Ref count (p) = 0x%04X"), me32.ProccntUsage);
_tprintf(TEXT("\n Base address = 0x%08X"), (DWORD)me32.modBaseAddr);
_tprintf(TEXT("\n Base size = %d"), me32.modBaseSize);

} while (Module32Next(hModuleSnap, &me32));

CloseHandle(hModuleSnap);
return(TRUE);
}

BOOL ListProcessThreads(DWORD dwOwnerPID)
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;

// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE)
return(FALSE);

// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32);

// Retrieve information about the first thread,
// and exit if unsuccessful
if (!Thread32First(hThreadSnap, &te32))
{
printError(TEXT("Thread32First")); // show cause of failure
CloseHandle(hThreadSnap); // clean the snapshot object
return(FALSE);
}

// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if (te32.th32OwnerProcessID == dwOwnerPID)
{
_tprintf(TEXT("\n\n THREAD ID = 0x%08X"), te32.th32ThreadID);
_tprintf(TEXT("\n Base priority = %d"), te32.tpBasePri);
_tprintf(TEXT("\n Delta priority = %d"), te32.tpDeltaPri);
_tprintf(TEXT("\n"));
}
} while (Thread32Next(hThreadSnap, &te32));

CloseHandle(hThreadSnap);
return(TRUE);
}

void printError(TCHAR const* msg)
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;

eNum = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL);

// Trim the end of the line and terminate it with a null
p = sysMsg;
while ((*p > 31) || (*p == 9))
++p;
do { *p-- = 0; } while ((p >= sysMsg) &&
((*p == '.') || (*p < 33)));

// Display the message
_tprintf(TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg);
}



运行结果:

img

将权限提升到管理员可以看到更多的进程 但是也不能获取所有的 (有的应用存在特权)

遍历窗口(无z无序):

img

回调函数

img

EnumWindows每遍历到一个窗口就会调用EnumWindowsProc将信息传输

EnumWindowsProc返回true就会继续遍历返回false就结束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BOOL CALLBACK EnumWindowsProc(
HWND hwnd, // handle to parent window
LPARAM lParam // application-defined value
)
{
char szBuff[MAXBYTE] = {};
GetWindowText(hwnd, szBuff, MAXBYTE);
printf("%s \r\n", szBuff);
return TRUE;//一直遍历直到所有窗口都被遍历完
}
int main(void)
{
EnumWindows(EnumWindowsProc,NULL);
return 0;
}

img

获取子窗口:使用EnumChildWindows

img

(有z序)有序遍历

img

img