第三章:内核对象

1:内核对象只是一个内存块,这个内存块是一个数据结构,只能由操作系统访问,程序通过调用API控制他,创建一个内核对象会返回一个Handle,在32位系统下是32位的一个值,在64位系统下是64位的一个值,Handle是进程相关的

2:内核对象所有者是操作系统,所以其生命周期可能会比进程长,内核对象数据结构中有个使用计数,创建是被初始化为1,当变成0后,内核对象被操作系统删除

3:每个内核对象都有一个安全描述符,创建时一般传入NULL,NULL为默认安全性,这取决于当前进程安全令牌(security token).如果用Openxxx函数打开一个内核对象,会进行一次安全检查,与创建时制定的安全描述符比对,内核对象和GDI对象的区别就是有没有安全描述符

4:进程创建时,会创建一个句柄表,表的每一行包括:索引,指向内核对象内存快指针,访问掩码,标志

5:一个进程首次初始化后,句柄表为空,如果创建了一个内核对象,会分配一块内存,根据安全描述符分配访问掩码,根据当前句柄是否能继承设置标志,句柄值右移4位就是句柄表的索引,但这可能在以后windows版本中发生变化,后4位右windows维护,所以目前最小的句柄值是4

6:CloseHandle()关闭内核对象,操作系统会将引用计数-1,当计数为0后,操作系统删除次内核对象,进程销毁的时候,操作系统会检查句柄表,帮助进程关闭所有忘记关闭的内核对象,与此相似,进程结束后,不会泄露任何句柄,内存,GDI对象,可以使用Process Explorer查看句柄相关信息

7:为何要把内核对象设计成进程相关而不是操作系统相关,是因为如果是后者,一个进程会很容易破坏另外一个进程内核对象

8:跨进程共享内核变量

8.1:使用对象句柄继承

注意这是句柄继承,不是内核对象继承,创建内核对象时,安全描述符如下

SECURITY_ATTRIBUTES sa;
sa.nLength=sizeof(sa);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=true;

安全描述符bInheritHandle为true则句柄表标志位将被值1,一帮情况下为0

然后CreateProcess参数中设置bInheritHandle=true;

这样创建进程后,子进程会不忙执行自己的代码,而是遍历父进程句柄表,如果句柄值有效,则复制到自己句柄表相应的位置,注意这里位置是一一对应的,复制会导致此内核对象使用计数+1

对象句柄继承只发生在CreateProcess()的一瞬间,如果子进程创建完成,父进程又创建新的句柄,则这些句柄不会被继承

需要通过进程共享手段告诉子进程继承了那些句柄

方法1:将句柄值作为命令行参数传递给子进程

方法2:使用进程通信计数

方法3:让子进程继承父进程的环境变量

8.2:改变句柄的标志

调用函数SetHandleInformation()改变句柄标志

//打开继承标志
SetHandleInformation(hd,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);
//关闭继承标志
SetHandleInformation(hd,HANDLE_FLAG_INHERIT,0);

检查一个句柄是否可以继承

DROWD dwFlags;
GetHandleInformation(hobj,&dwFlags);
bool IsInheritable=(0!=dwFlags&HANDLE_FLAG_INHERIT));

8.3:为内核对象命名

用Createxxx函数创建内核对象并加上名字,系统会首先检查是否有同名对象存在,如果是,检查类型是否相同,不同则返回,否则系统执行一次安全检查,验证调用者是否拥有对该对象的完全访问权限,如果是,系统会在调用者进程句柄表中找到一个空白项并赋值,注意这个句柄值可能和创建者句柄值不同

Openxxx同样能打开一个内核对象,但如果不存在,不会自动创建,Openxxx和Createxxx打开既有内核对象,会忽略打开时使用的安全描述符和继承属性

用于创建内核对象的函数,总是返回具有完全访问权限的句柄,如果想限制一个句柄的访问权限,可以使用ex扩展版本
8.4:命名空间

1:获得自己当前会话ID

DWORD processID=GetCurrentProcessID();
DWORD sessionID;
ProecssIdToSessionId(processID,&sessionID);

2:可以通过创建专有命名空间防止名称冲突

8.5:复制对象句柄

DuplicateHandle();此函数将一个进程句柄复制到另外一个进程,复制后句柄值不一定相同,dwOptions可以指定DUPLICATE_SAME_ACCESS,表示复制和原进程同样的访问掩码

1:以下代码演示原进程复制一个句柄到目的进程

HANDLE hd=CreateMutex(NULL,FALSE,NULL);
HANDLE hdProcessT=OpenProcess(PROCESS_ALL_ACCESS,NULL,dwProcessID);
HANDLE hdDup;
DuplicateHandle(GetCurrentProcess(),hd,hdProcessT,&hdDup,0,FALSE,DUPLICATE_SAME_ACCESS);
//用进程通信手段将此句柄hdDup传给hdProcessT
CloseHandle(hd);
CloseHandle(hdProcessT);

2:以下代码展示使用DupcliteHandle的另一个目的:创建一个句柄后,将此句柄传递给一个函数,但是想给他不同的访问权限

如下,创建时时读写权限,但只想给调用函数只读权限

HANDLE hFileMapView=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,10240,NULL);
HANDLE hDup;
DuplicateHandle(GetCurrentProcess(),hFileMapView,GetCurrentProcess(),&hDup,FILE_MAP_READ,FALSE,0);
//使用这个hDup
CloseHandle(hFileMapView);
CloseHandle(hDup);

 

最后:一个句柄通过命令行继承的例子
B进程等A进程退出后再打印文字

//进程A
#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	STARTUPINFO si={sizeof(si)};
	PROCESS_INFORMATION pi;
	ZeroMemory(&pi,sizeof(pi));

	SECURITY_ATTRIBUTES sa;  
	sa.nLength=sizeof(sa);  
	sa.lpSecurityDescriptor=NULL;  
	sa.bInheritHandle=true; 

	TCHAR szBuf[]=_T("TestCall.exe");
	HANDLE hdProcessT=OpenProcess(PROCESS_ALL_ACCESS,true,GetCurrentProcessId());  
	TCHAR szHandle[100]={0};
	_stprintf(szHandle,_T("%d"),(int)hdProcessT);
	//这里不ClosheHandle(hdProcessT);

	bool ret=CreateProcess(szBuf,szHandle,&sa,NULL,true,NULL,NULL,NULL,&si,&pi);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	CloseHandle(hdProcessT);//这里Close
	system("pause");
	return 0;
}
//进程B
#include "stdafx.h"
#include <Windows.h>
#include <vector>
#include <algorithm>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	LPSTR p=GetCommandLine();
	HANDLE hd=(HANDLE)(atoi(p));
	WaitForSingleObject(hd,INFINITE);
	Sleep(1);
	cout<<"OVER"<<endl;
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值