跨进程使用句柄
- 每个程序都有自己
句柄索引表
- 这个
句柄索引表
一开始是没有记录的,程序每查询一个 句柄,这个表中就增加一条记录 - 相同的 进程在不同程序中 有 不同的
进程句柄
/进程id
在某个程序中 获取到的
进程句柄
/进程id
是当前程序的句柄表的索引- 他们保存在一棵树中
- 具体的对应关系 由操作系统负责
进程句柄
/进程id
都是索引(指向具体的某个进程)
- 所有句柄(所有资源句柄)都遵守这个规则
- 句柄的传递的本质是 不同程序之间 共有某个 进程 的句柄记录(只是他们的表中 都有某个 进程实体的 句柄/句柄id(但是他们是不同的,参见第三条))
方案一: 句柄的继承/自动获取
- 只有当进程具有父子关系时,才能使用对象句柄的继承性。
CreateProcess
创建进程父进程创建
某个新进程
时要设定SECURITY_ATTRIBUTES.bInheritHandle=true
表示这个进程句柄 可被继承
父进程创建
子进程时
要设定bInheritHandles=true
表示这个子进程
继承
可被继承的句柄
实例
//假定我们启动这个程序作为被传递句柄的程序
char szCmdline[256] = { 0 };
strcpy_s(szCmdline, 256, "H:\\CR31\\windows\\04communicate\\SubProcess\\Debug\\SubProcess.exe");
//获取程序启动的一些 回掉信息
STARTUPINFOA si = { 0 };
si.cb = sizeof(STARTUPINFOA);
PROCESS_INFORMATION pi;
//设置该进程可被 子进程 继承句柄
SECURITY_ATTRIBUTES sa = {0};
sa.bInheritHandle = TRUE;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
//创建该进程
BOOL bRet = CreateProcessA(NULL,
szCmdline,
&sa,
NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi);
/*
我们在创建一个子进程
只要把 CreateProcessA 中 bInheritHandles 设置为 true就可以继承 这个句柄了
*/
CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles, //这里要设置为true
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
方案二: 句柄的拷贝/主动复制
- 获取句柄
- 拷贝句柄
- 本质是把某个句柄记录 附加到 指定子进程的进程索引表中
- 只是把句柄记录复制过去了,接收端仍然不知道这个句柄是什么,需要我们通过其他方式传递
获取进程句柄
/*
这两个函数获取到的 是 当前 进程/线程 的进程索引表中的 当前进程/线程的 的句柄id
不管在那个 进程中调用 结果都是 -1
*/
GetCurrentProcess ()
GetCurrentThread ()
拷贝句柄
DuplicateHandle
实例
下面例子演示在 ApiDuplicateHandleSource.exe
中创建一个线程,将该线程句柄复制到 ApiDuplicateHandle.exe
中去,在进程 ApiDuplicateHandle.exe
中结束该线程
- 先打开
ApiDuplicateHandle
- 这时候打开
ApiDuplicateHandleSource
,ApiDuplicateHandleSource
会把他的一个线程的句柄记录增加到ApiDuplicateHandle
中 - 由于 只是增加了 记录
ApiDuplicateHandle
并不会主动感知,所以我们要手动把 生成的句柄发送给ApiDuplicateHandle
ApiDuplicateHandle
收到 他新增加的句柄后 直接去 kill掉这个句柄
ApiDuplicateHandleSource的CPP
// ApiDuplicateHandleSource.cpp
#include <iostream>
#include <Windows.h>
#include <process.h>
#include <tchar.h>
#include <TlHelp32.h>
using namespace std;
unsigned __stdcall thread (void * lpPragma);
HANDLE GetProcessHandle(LPCTSTR szName);
int main (void)
{
HANDLE hThread = NULL;
hThread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL);
cout << "My thread handle is " << hThread << endl;
HANDLE hTarget = NULL;
BOOL bSucc = FALSE;
//你是不是想说这里的hThread与调用DuplicateHandle相关?
bSucc = DuplicateHandle (GetCurrentProcess(), //当前进程的源进程句柄
hThread, //当前进程中存在的线程资源句柄(内核对象)
GetProcessHandle(_T("ApiDuplicateHandle.exe")), //目标进程的句柄
&hTarget, //该 句柄记录 增加到 ApiDuplicateHandle后,在 ApiDuplicateHandle 中的句柄
0, //访问的方式
FALSE, //得到的句柄能不能被得到的其的进程的子进程继承
DUPLICATE_SAME_ACCESS ); //访问选项
if (bSucc)
{
cout << "句柄复制成功, 其句柄值为:" << hTarget << endl;
}
cin.get();
return 0;
}
unsigned __stdcall thread (void * lpPragma)
{
while (1)
{
Sleep (1000);
cout << "Please terminal me!" << endl;
}
return 0;
}
//根据程序名称 获取进程句柄
HANDLE GetProcessHandle(LPCTSTR szName)
{
HANDLE hSanpshot = NULL;
hSanpshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if ( INVALID_HANDLE_VALUE == hSanpshot )
{
return NULL;
}
PROCESSENTRY32 pe;
BOOL bOk = FALSE;
pe.dwSize = sizeof(pe);
bOk = Process32First (hSanpshot, &pe);
if (!bOk)
return NULL;
do
{
if ( !_tcscmp (pe.szExeFile, szName) )
{
return OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
}
bOk = Process32Next (hSanpshot, &pe);
}
while (bOk);
return NULL;
}
ApiDuplicateHandle 的CPP
// ApiDuplicateHandle.cpp
#include <iostream>
#include <Windows.h>
#include <stdlib.h>
#include <process.h>
using namespace std;
int main (void)
{
HANDLE hRecv = NULL;
cout << "请输入复制过来的句柄 : " << endl;
cin >> hRecv;
TerminateThread(hRecv, 0);
cin.get();
return 0;
}