1. 父子进程间实现跨进程使用进程句柄
首先来查看一个创建进程的关键API,有关于跨进程使用进程句柄中最关键的2个参数已经用红框框出
首先知道一个概念,每个进程被创建后内部都有一张句柄表。
来看第一个参数bInheritHandles, 这个参数决定了创建的子进程能否继承父进程的句柄表。如果是TRUE则创建的子进程会继承父进程句柄表否则不会。
BOOL bInheritHandles,
也就是说假设有2个进程A和B。A进程通过CreateProcess创建了B进程。如果A进程创建B时CreateProcess中bInheritHandles为TRUE。那B进程就可以获取使用A进程句柄表中所有句柄。
接下来看第二个参数lpProcessttributes
LPSECURITY_ATTRIBUTES lpProcessAttributes
查一下这个结构体内容:
可以看到里面还有一个bInheritHandles值。该值决定的是父进程创建子进程后,子进程自身的句柄是否能被父进程获取。如果该值为TRUE,代表子进程自身句柄是可以被父进程获取,否则不行。
那假设现在A进程以CreateProcess中的bInheritHandle为TRUE,并且SECURITY_ATTRIBTES中的bInheritHandle为TRUE的方式创建了B进程。可以知道CreateProcess中的bInheritHandle为TRUE代表A进程内的句柄可被B进程继承。SECURITY_ATTRIBTES中的bInheritHandle为TRUE则可知B进程的句柄可以被继承。
可以看到A进程的句柄表内的确包含了B进程的句柄。现在尝试创建C进程。如果正确,C进程句柄表内应含有B进程的句柄, 则C进程可以利用该句柄杀死B进程。
结果发现果然如此。
那假设在A进程创建B进程时,把B进程的SECURITY_ATTRIBTES中的bInheritHandle改为FALSE会如何, 可以看到虽然B进程的句柄也存在于A进程的句柄表,但是标注是Non-existent process。这时候就算A进程创建了C进程。C进程也无法使用B进程的句柄。
所以可以得出一个结论就是SECURITY_ATTRIBUTES中bInheritHandle作用是决定自身进程是否可以被继承。
但如果说CreateProcess中的bInheritHandle项都是FALSE,那就算SECURITY_ATTRIBUTES中bInheritHandle是TRUE也无法被继承。因为这就意味着父进程所有句柄都不能被子进程继承。子进程自身句柄能否被父进程创建的其他子进程继承也就没意义了,因为反正整个句柄表都无法被继承。
2. 复制句柄实现跨进程使用进程句柄
主要原理图如下:
解释一下:
来查看一下演示代码:
B进程代码:
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <cstdio>
#include <iostream>
using namespace std;
int main()
{
HWND hWnd = NULL;
HANDLE hProcess = NULL;
UINT uiPid;
SetConsoleTitle("B");
cout << "请输入进程句柄值: ";
cin >> uiPid;
hProcess = (HANDLE)uiPid;
TerminateProcess(hProcess, 0);
system("pause");
return(0);
}
A进程代码:
#include <windows.h>
#include <cstdio>
#define CALCPID 34552
UINT GetPidByHwnd(LPCSTR lpcszWindowName)
{
HWND hWnd = NULL;
DWORD dwPid = 0;
if (NULL == lpcszWindowName)
{
return(0);
}
hWnd = FindWindow(NULL, lpcszWindowName);
if (NULL == hWnd)
{
return(0);
}
GetWindowThreadProcessId(hWnd, &dwPid);
return(dwPid);
}
int main()
{
HANDLE hCalc = NULL;
HANDLE hB = NULL;
HANDLE hDup = NULL;
UINT uiPid = 0;
BOOL fOk = FALSE;
SetConsoleTitle("A");
hCalc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, CALCPID);
if (NULL == hCalc)
{
printf("OpenProcess failed... %d\r\n", GetLastError());
return(-1);
}
// 显示被拷贝的进程句柄
printf("被拷贝的进程句柄为: %I64X\r\n", hCalc);
// 获取窗口B的PID
uiPid = GetPidByHwnd("B");
if (!uiPid)
{
return(-1);
}
// 打开B进程的窗口句柄
hB = OpenProcess(PROCESS_ALL_ACCESS, FALSE, uiPid);
if (NULL == hB)
{
return(-1);
}
// 把进程Calc的句柄复制过去
fOk = DuplicateHandle(GetCurrentProcess(), hCalc, hB, &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (!fOk)
{
return(-1);
}
printf("复制过去的句柄值: %I64u\r\n", hDup);
if (NULL != hCalc)
{
CloseHandle(hCalc);
hCalc = NULL;
}
if (NULL != hB)
{
CloseHandle(hB);
hA = NULL;
}
if (NULL != hDup)
{
CloseHandle(hDup);
hDup = NULL;
}
system("pause");
return(0);
}
(完)