Windows核心编程&内核对象
1. 一个进程在初始化时,系统将会他分配一个空的句柄表,这个句柄表仅供内核对象使用,不供用户对象和GDI对象使用。进程在首次
初始化时,该句柄表为空。句柄表是一个由数据结构组成的数组,包含一个内核对象指针,一个访问掩码和一些标志。系统用索引来
标识内核对象的信息保存在进程句柄表中的具体位置,句柄值除以4即为索引值(针对不同版本的windows系统可能不同)。
2. 要注意内核对象返回值INVALID_HANDLE_VALUE(-1)和NULL(0)的区别,凡是用于创建内核对象的函数,在检查它们的返回值时
务必相当仔细。一般只有CreateFile才返回INVALID_HANDLE_VALUE。
3. 对于内核对象,操作系统执行操作过程为:进程终止时,系统会自动扫描进程句柄表。如果这个表中有任何有效的记录项(即进程进程终
止前未关闭的对象),操作系统会为我们关闭这些对象句柄(只要这些对象的使用计数为0)。
4. 进程共享内核对象机制
(1). 对象句柄继承
a.创建内核对象时将SECURITY_ATTRIBUTES结构的bInheritHandle设为TRUE
b.将CreateProcess参数的bInheritHandle设为TRUE,注:对象句柄的继承只会在生成子进程的时候发生
c.子进程无法查看自己继承了任何的对象句柄,在开发阶段最好用文档表明
(2). 改变句柄标志
SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags)
两个关键标志HANDLE_FLAG_INHERIT和HANDLE_FLAG_PROTECT_FROM_CLOSE
(3). 为对象命名
许多(但不是全部)内核对象都可以进行命名
(4). 复制对象句柄
从一个进程的句柄表中获得一个记录项,然后在另一个进程的句柄表中创建这个记录项的副本(DuplicateHandle)
5. 实例
typedef HANDLE (_stdcall* BOUNDARYDESCRIPTOR)(LPTSTR, DWORD);
BOUNDARYDESCRIPTOR CreateBoundaryDescriptor;
typedef BOOL (_stdcall* ADDSIDTOBOUNDARYDESCRIPTOR)(HANDLE *, PSID);
ADDSIDTOBOUNDARYDESCRIPTOR AddSIDToBoundaryDescriptor;
typedef HANDLE (_stdcall *CREATEPRIVATENAMESPACE)(LPSECURITY_ATTRIBUTES, LPVOID, LPCSTR);
CREATEPRIVATENAMESPACE CreatePrivateNamespace;
typedef HANDLE (_stdcall* OPENPRIVATENAMESPACE)(PVOID, LPCSTR);
OPENPRIVATENAMESPACE OpenPrivateNamespace;
void CSingletonDlg::CheckInstances()
{
HMODULE hKernel = LoadLibrary("Kernel32.dll");
if (hKernel)
{
CreateBoundaryDescriptor = (BOUNDARYDESCRIPTOR)GetProcAddress(hKernel, "CreateBoundaryDescriptorA");
// 注意函数名AddSIDToBoundaryDescriptor后面没带'A'
AddSIDToBoundaryDescriptor = (ADDSIDTOBOUNDARYDESCRIPTOR)GetProcAddress(hKernel, "AddSIDToBoundaryDescriptor");
CreatePrivateNamespace = (CREATEPRIVATENAMESPACE)GetProcAddress(hKernel, "CreatePrivateNamespaceA");
OpenPrivateNamespace = (OPENPRIVATENAMESPACE)GetProcAddress(hKernel, "OpenPrivateNamespaceA");
}
);
if (NULL == m_hBoundaryDescriptor)
{
// 创建边界描述符失败
return;
}
// 为边界描述符关联一个SID
BYTE localAdminSID[SECURITY_MAX_SID_SIZE];
PSID pLocalAdminSID = &localAdminSID;
DWORD cbSID = sizeof(localAdminSID);
if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, pLocalAdminSID, &cbSID))
{
// 创建SID失败
return;
}
if (!AddSIDToBoundaryDescriptor(&m_hBoundaryDescriptor, pLocalAdminSID))
{
// 链接边界描述符失败
return;
}
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = FALSE;
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
TEXT("D:(A;;GA;;;BA)"), SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL))
{
return;
}
// 创建命名空间
/*HANDLE */m_hPrivateNameSpace = CreatePrivateNamespace(&sa, m_hBoundaryDescriptor, "3-Namespace");
LocalFree(sa.lpSecurityDescriptor);
// 检查已创建的命名空间:看是否有权限访问ERROR_ACCESS_DENIED和该命名空间是否存在ERROR_ALREADY_EXISTS
DWORD dwLastErro = GetLastError();
if (m_hPrivateNameSpace == NULL)
{
if (ERROR_ACCESS_DENIED == dwLastErro)
{
return;
}
else if (ERROR_ALREADY_EXISTS == dwLastErro)
{
m_hPrivateNameSpace = OpenPrivateNamespace(m_hBoundaryDescriptor, "3-Namespace");
if (NULL == m_hPrivateNameSpace)
{
return;
}
}
}
// 创建互斥对象
};
StringCchPrintf(cMutexName, sizeof(MAX_PATH), "%s\\%s", "3-Namespace", "Single");
g_hSingleton = CreateMutex(NULL, FALSE, cMutexName);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
AddText(TEXT("Another instance of Singleton is running:\r\n"));
AddText(TEXT("--> Impossible to access application features.\r\n"));
} else
{
AddText(TEXT("First instance of Singleton:\r\n"));
AddText(TEXT("--> Access application features now.\r\n"));
}
FreeLibrary(hKernel);
}
6. 附录
boundary 分界线;范围
descriptor 描述符
(1). HANDLE CreateBoundaryDescriptor(PCTSTR pszName, DWORD dwFlags)
创建边界描述符
第二个参数为以后保留,目前没什么用,为0
函数返回的并非是一个句柄,而是一个指向用户模式结构的指针,结构中包含了边界的定义,不要把返回的句柄值传给
CloseHandle,而要传给DeleteBoundaryDescriptor
(2). BOOL AddSIDToBoundaryDescriptor(HANDLE *phBoundaryDescriptor, PSID pRequireSid)
将一个特权用户组的SID与边界描述符关联起来
(3). HANDLE CreatePrivateNameSpace(PSECURITY_ATTRIBUTES, PVOID pvBoundaryDescriptor, pszAliasPrefix)
对创建好的命名空间进行检查GetLastError(),ERROR_ACCESS_DENIED、ERROR_ALREADY_EXISTS
(4). HANDLE OpenPrivateNameSpace( PVOID pvBoundaryDescriptor, pszAliasPrefix)
(5). ClosePrivateNameSpace(HANDLE hNamespace, DWORD dwFlags)
如果我们已经创建了命名空间,而且不希望它在关闭后仍然可见,可以用PRIVATE_NAMESPACE_FLAG_DESTRPY作为第二个参数,反之则为0
(6). BOOL WINAPI CreateWellKnowSid()
创建一个SID
参数1:WellKnowSidType SID类型,WELL_KNOW_SID_TYPE是枚举类型,它包含一系列的安全描述符类型
参数2: _in_opt PSID DomainSid 指向创建了SID的域的指针,为NULL时表示本地计算机
参数3:_out_opt PSID pSid 指向存储SID地址
参数4: _inout DWORD *cbSid 指向存储pSid的大小的地址
Windows核心编程&内核对象的更多相关文章
- windows核心编程-信号量(semaphore)
线程同步的方式主要有:临界区.互斥区.事件.信号量四种方式. 前边讲过了互斥器线程同步-----windows核心编程-互斥器(Mutexes),这章我来介绍一下信号量(semaphore)线程同步. ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- Windows核心编程学习九:利用内核对象进行线程同步
注:源码为学习<Windows核心编程>的一些尝试,非原创.若能有助于一二访客,幸甚. 1.程序框架 #include "Queue.h" #include <t ...
- windows核心编程 - 线程同步机制
线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- 回忆读windows 核心编程
看<windows 核心编程> 第五版到纤程了,下一章节即将介绍内存体系编程.如果做window平台下的开发,我感觉此书一定要读.记得开始讲解了window的基础,然后讲解内核对象.内核对 ...
- 《Windows核心编程》第5版 学习进度备忘
学习资源:<Windows核心编程>第5版 知识基础支持: 本书与<Windows程序设计>第5版珍藏版结合很好,二者重叠内容不多,二者互补性强,而且相关方面的优秀书籍 跳过的 ...
- 【windows核心编程】 第八章 用户模式下的线程同步
Windows核心编程 第八章 用户模式下的线程同步 1. 线程之间通信发生在以下两种情况: ① 需要让多个线程同时访问一个共享资源,同时不能破坏资源的完整性 ② 一个线程需要通知其他线程 ...
- 【windows核心编程】 第六章 线程基础
Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ① 一个是线程的内核 ...
随机推荐
- JDK1.8中的线程池
上面这段代码一直在用,面试的时候也经常被问到,却从未深究过,不知道线程池到底是怎么回事,今天看看源代码,一探其究竟 线程池主要控制的状态是ctl,它是一个原子的整数,其包含两个概念字段: worker ...
- PyQt4 开发入门
参考资料:PyQt4教程
- Linux之 网卡发包、接包 error 、droped 情况
1. 查看各个网卡发送.接受包情况oracle@hbdw2:/oratmp2$netstat -niKernel Interface tableIface MTU Met RX-OK RX-ERR R ...
- 聊聊ThreadLocal原理以及使用场景-JAVA 8源码
相信很多人知道ThreadLocal是针对每个线程的,但是其中的原理相信大家不是很清楚,那咱们就一块看一下源码. 首先,我们先看看它的set方法.非常简单,从当前Thread中获取map.那么这个ge ...
- 五分钟学习React(四):什么是JSX
JSX,即javscript XML,是js内定义的一套XML语法.目前是使用babel作为JSX的编译器.这也是在前几期中载入babel的原因. Facebook引入JSX是为了解决前端代码工程复杂 ...
- fiddler抓手机报文的配置指南
前言 1.fiddler大名鼎鼎的抓包工具,而且支持重发,自动解码报文之类. 2.做爬虫时经常遇到需要抓移动端(手机/pad等)报文的情况. 网上各种资料比较,下面这篇是最准确的,转载自csdn:ht ...
- JavaScript细节成败
1.var 众所周知var用来定义变量 如 undefined,number,string,bool,array,function,object,null. 但有时候为了省事,就会出现一些内存泄露的情 ...
- Android刮刮卡自定义控件
网上的都是自己绘制的或者图片,我的需求是可以随意的自定义底部和顶部的布局.所以自己重写一个,原理就是直接继承 View 来实现一个刮层,让这个刮层和图片以及文字不产生任何依赖,再结合 FrameLay ...
- TCP/IP和UDP之间的区别(转载)
在分析两者之间的区别之前,我们先搞清楚这两者的关系, TCP/IP协议簇 是一种网络控制协议,简单点说就是一种网络协议,我们网络中的计算机就是通过这套协议簇来进行数据通信的.这套协议簇里面包含了很多 ...
- python实现简单函数发生器
最近学校又抽风把我自动化系的苦逼童鞋留下做课设,简直无聊到爆的-->用VB实现函数发生器,(语言不限制) 大伙不知从哪搞来的MATLAB版本,于是几十个人就在这基础上修修改改蒙混过关了,可我实在 ...