windows中以最低权限(SECURITY_ATTRIBUTES)创建内核对象

本文解决Win8下IE10访问共享内存失败的问题,通过降低服务端创建的共享内存对象权限,实现客户端正常访问。适用于保护模式开启的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近工作中用到共享内存进行进程间通信,客户端在win8的IE10中老是报无法打开服务端以默认权限创建的共享内存等内核对象,环境是:1. 使用win8的默认等级的用户帐户控制,2. IE10的安全属性中开启了“启用保护模式”。开始是想办法提升客户端的权限,尝试了好多方法,最终都无法达到效果,最后转换思路,尝试以低权限来创建内核对象,又进行了好长时间的搜索,最终在Writing to Global Shared memory from an Application in Vista中找到相关信息,并整理如下。


BOOL createLowSecurityDescriptor(SECURITY_ATTRIBUTES& secAttr)
{
	BOOL succ = FALSE;
	DWORD lassErr = 0;
	PACL pSacl = NULL;                  // not allocated


	PSECURITY_DESCRIPTOR pSD = NULL;

	//OSVERSIONINFO osvi;
	//osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	//succ = GetVersionEx (&osvi);
	////bool bIsWindowsXPOrLater = ( (osvi.dwMajorVersion > 5) || ( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
	//bool bIsVistaOrLater = ( osvi.dwMajorVersion > 5);
	//if (bIsVistaOrLater)
	//{
		succ = ConvertStringSecurityDescriptorToSecurityDescriptor(
			_T("S:(ML;;NW;;;LW)"), // this means "low integrity"
			SDDL_REVISION_1,
			&pSD,
			NULL);
		lassErr = GetLastError();
		srlog_func_return_ret(succ,
			(_T("::createLowSecurityDescriptor | ConvertStringSecurityDescriptorToSecurityDescriptor return:%d, lassErr:%lu"), succ, lassErr),
			NULL
			);

		BOOL fSaclPresent = FALSE;
		BOOL fSaclDefaulted = FALSE;
		succ = GetSecurityDescriptorSacl(
			pSD,
			&fSaclPresent,
			&pSacl,
			&fSaclDefaulted);
		lassErr = GetLastError();
		srlog_func_return_ret(succ,
			(_T("::createLowSecurityDescriptor | GetSecurityDescriptorSacl return:%d, lassErr:%lu"), succ, lassErr),
			NULL
			);
	//}
	

	succ = InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
	lassErr = GetLastError();
	srlog_func_return_ret(succ,
		(_T("::createLowSecurityDescriptor | InitializeSecurityDescriptor return:%d, lassErr:%lu"), succ, lassErr),
		NULL
		);

	succ = SetSecurityDescriptorSacl(secAttr.lpSecurityDescriptor, TRUE, pSacl, FALSE);
	lassErr = GetLastError();
	srlog_func_return_ret(succ,
		(_T("::createLowSecurityDescriptor | SetSecurityDescriptorSacl return:%d, lassErr:%lu"), succ, lassErr),
		NULL
		);

	return TRUE;
}

HANDLE openMutex(const TCHAR* gMutexName)
{
	HANDLE hMutex = NULL;
	hMutex = OpenMutex(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, gMutexName);
	if (hMutex == NULL)
	{
		srlog_warn(TEXT("createOrOpenMutex::Could not open mutex object (%d).\n"), 
			GetLastError());
		hMutex = NULL;
	}
	return hMutex;

}
HANDLE createOrOpenMutex(const TCHAR* gMutexName)
{
	srlog_tracer(::createOrOpenMutex);

	HANDLE hMutex = NULL;


	BOOL succ  = FALSE;
	DWORD lassErr = 0;
	SECURITY_ATTRIBUTES secAttr;	
	SECURITY_DESCRIPTOR secDesc;

	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	succ = GetVersionEx (&osvi);
	//bool bIsWindowsXPOrLater = ( (osvi.dwMajorVersion > 5) || ( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
	bool bIsVistaOrLater = ( osvi.dwMajorVersion > 5);
	if (bIsVistaOrLater)
	{
		secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
		secAttr.bInheritHandle = FALSE;
		secAttr.lpSecurityDescriptor = &secDesc;

		succ = createLowSecurityDescriptor(secAttr);
		srlog_info(_T("::createOrOpenMutex | createLowSecurityDescriptor return:%d"), succ);		
	}
	else
	{
		
		if(InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION)) //Revision level
		{
			if(SetSecurityDescriptorDacl(&secDesc,
				TRUE, // DACL presence
				NULL, // DACL (NULL DACL means all access granted)
				FALSE)) // default DACL
			{
				secAttr.nLength = sizeof(SECURITY_DESCRIPTOR);
				secAttr.lpSecurityDescriptor = (LPVOID)&secDesc;
				secAttr.bInheritHandle = FALSE;
				// now you can fill param LPSECURITY_ATTRIBUTES while &secAttr
			}
		}
	}

	hMutex = CreateMutex(&secAttr, FALSE, gMutexName);
	if (hMutex == NULL)
	{
		srlog_warn(TEXT("createOrOpenMutex::Could not create mutex object (%d).\n"), 
			GetLastError());
		hMutex = openMutex(gMutexName);
	}
	return hMutex;
}


HANDLE openEvent(const TCHAR* gEventName)
{
	srlog_tracer(::openEvent);
	HANDLE hMutex = NULL;
	hMutex = OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE, gEventName);
	if (hMutex == NULL)
	{
		srlog_warn(TEXT("createOrOpenMutex::Could not open mutex object (%d).\n"), 
			GetLastError());
		hMutex = NULL;
	}	
	return hMutex;
}

HANDLE createOrOpenEvent(const TCHAR* gEventName, BOOL bManualReset, BOOL bInitialState)
{
	srlog_tracer(::createOrOpenEvent);
	HANDLE hEvent = openEvent(gEventName);
	DWORD lastErr = GetLastError();
	if (hEvent == NULL)
	{
		srlog_warn(TEXT("createOrOpenMutex::Could not open mutex object (%d).\n"), 
			lastErr);

		BOOL succ  = FALSE;
		DWORD lassErr = 0;
		SECURITY_ATTRIBUTES secAttr;	
		SECURITY_DESCRIPTOR secDesc;

		OSVERSIONINFO osvi;
		osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
		succ = GetVersionEx (&osvi);
		//bool bIsWindowsXPOrLater = ( (osvi.dwMajorVersion > 5) || ( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
		bool bIsVistaOrLater = ( osvi.dwMajorVersion > 5);
		if (bIsVistaOrLater)
		{
			secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
			secAttr.bInheritHandle = FALSE;
			secAttr.lpSecurityDescriptor = &secDesc;

			succ = createLowSecurityDescriptor(secAttr);
			srlog_info(_T("::createOrOpenEvent | createLowSecurityDescriptor return:%d"), succ);		
		}
		else
		{

			if(InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION)) //Revision level
			{
				if(SetSecurityDescriptorDacl(&secDesc,
					TRUE, // DACL presence
					NULL, // DACL (NULL DACL means all access granted)
					FALSE)) // default DACL
				{
					secAttr.nLength = sizeof(SECURITY_DESCRIPTOR);
					secAttr.lpSecurityDescriptor = (LPVOID)&secDesc;
					secAttr.bInheritHandle = FALSE;
					// now you can fill param LPSECURITY_ATTRIBUTES while &secAttr
				}
			}
		}

		hEvent = CreateEvent(&secAttr, bManualReset, bInitialState, gEventName);
		lastErr = GetLastError();
		if (hEvent == NULL)
		{
			srlog_warn(TEXT("createOrOpenMutex::Could not create mutex object (%d).\n"), 
				lastErr);
		}
	}
	return hEvent;
}

HANDLE openFileMapping(const TCHAR* gFileMappingName)
{
	HANDLE hMapFile = OpenFileMapping(
		FILE_MAP_WRITE | FILE_MAP_READ,   // read/write access
		FALSE,                 // do not inherit the name
		gFileMappingName);               // name of mapping object 
	if (hMapFile == NULL) 
	{ 
		_tprintf(TEXT("Could not open file mapping object (%d).\n"), 
			GetLastError());		
	}
	return hMapFile;
}

HANDLE createOrOpenFileMapping(const TCHAR* gFileMappingName, int size)
{
	BOOL succ  = FALSE;
	DWORD lassErr = 0;
	SECURITY_ATTRIBUTES secAttr;	
	SECURITY_DESCRIPTOR secDesc;

	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	succ = GetVersionEx (&osvi);
	//bool bIsWindowsXPOrLater = ( (osvi.dwMajorVersion > 5) || ( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
	bool bIsVistaOrLater = ( osvi.dwMajorVersion > 5);
	if (bIsVistaOrLater)
	{
		secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
		secAttr.bInheritHandle = FALSE;
		secAttr.lpSecurityDescriptor = &secDesc;

		succ = createLowSecurityDescriptor(secAttr);
		srlog_info(_T("::createOrOpenFileMapping | createLowSecurityDescriptor return:%d"), succ);		
	}
	else
	{

		if(InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION)) //Revision level
		{
			if(SetSecurityDescriptorDacl(&secDesc,
				TRUE, // DACL presence
				NULL, // DACL (NULL DACL means all access granted)
				FALSE)) // default DACL
			{
				secAttr.nLength = sizeof(SECURITY_DESCRIPTOR);
				secAttr.lpSecurityDescriptor = (LPVOID)&secDesc;
				secAttr.bInheritHandle = FALSE;
				// now you can fill param LPSECURITY_ATTRIBUTES while &secAttr
			}
		}
	}

	HANDLE hMapFile = CreateFileMapping(
		INVALID_HANDLE_VALUE,    // use paging file
		&secAttr,          // default security 
		PAGE_READWRITE,          // read/write access
		0,                       // maximum object size (high-order DWORD) 
		size,					// maximum object size (low-order DWORD)  
		gFileMappingName);                 // name of mapping object
	lassErr = GetLastError();
	srlog_func_ret(hMapFile != NULL,
		(_T("::createLowSecurityDescriptor | CreateFileMapping return:%d, lassErr:%lu"), succ, lassErr)
		);

	if (hMapFile == NULL)
	{ 
		_tprintf(TEXT("Could not create file mapping object (%d).\n"), 
			GetLastError());
		hMapFile = openFileMapping(gFileMappingName);
	}
	return hMapFile;
}




参考资料:

http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx?PageIndex=2

http://social.msdn.microsoft.com/forums/en-US/windowssecurity/thread/08e18474-5f8c-4294-a9cf-7ede1ff8ae1f/

<think>好的,我需要回答用户关于操作系统内核对象继承的问题。首先,用户提供的引用中提到,继承性仅适用于具有父子关系的进程,父进程需要创建可继承的句柄。根据引用[1],父进程在创建内核对象时必须使用SECURITY_ATTRIBUTES结构,并设置bInheritHandle为TRUE。同时,子进程在创建时需要允许继承句柄,比如使用CreateProcess并设置bInheritHandles参数为TRUE。子进程可以通过GetCommandLine或命令行参数获取句柄值,或者通过进程间通信传递句柄信息。 接下来,我要确保回答符合用户的要求:结构清晰,分步骤解释机制和作用。需要引用提供的参考文献,特别是引用[1]中的具体步骤。另外,要避免使用Markdown,使用中文,并正确使用LaTeX格式。例如,提到句柄继承时,使用$...$格式的变量,如$hMutex$。 然后,生成相关问题。根据用户提供的示例问题,可能的问题包括内核对象继承的限制、与其他继承机制的区别、安全性影响、应用场景以及如何检测可继承句柄等。需要确保问题相关且有针对性,帮助用户深入理解主题。 最后,检查回答是否符合所有系统级指令,特别是引用标识的正确添加,如[^1]。确保LaTeX语法正确,例如独立公式用$$...$$,但当前问题可能不涉及复杂公式,所以主要检查行内表达式是否正确。例如,在代码示例中变量是否用$包裹,如$sa.bInheritHandle$。 总结步骤: 1. 解释内核对象继承的作用和机制,分步骤说明实现方式。 2. 引用文献中的具体内容,特别是创建可继承句柄的步骤。 3. 生成相关问题,覆盖机制、应用、安全性等方面。 4. 确保格式正确,无Markdown,正确使用LaTeX和引用标识。</think>### 内核对象继承的实现机制与作用 在操作系统中,**内核对象继承**是进程间共享资源的重要机制,主要用于父子进程间传递对内核对象的访问权限。以下是实现内核对象继承的具体步骤和作用分析: --- #### **一、内核对象继承的实现步骤** 1. **创建可继承的句柄** 父进程在创建内核对象时,必须显式声明句柄的可继承性。通过初始化$SECURITY\_ATTRIBUTES$结构并设置$bInheritHandle=TRUE$,确保返回的句柄可被子进程继承。 **示例代码:** ```c SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; // 关键:标记句柄为可继承 HANDLE hMutex = CreateMutex(&sa, FALSE, NULL); ``` 2. **子进程继承句柄** 父进程调用`CreateProcess`创建子进程时,需将参数$bInheritHandles$设为$TRUE$,表示允许子进程继承所有可继承的句柄[^1]。 ```c BOOL success = CreateProcess( NULL, commandLine, NULL, NULL, TRUE, // 启用句柄继承 0, NULL, NULL, &startupInfo, &processInfo ); ``` 3. **子进程访问继承的句柄** 子进程启动后,其句柄表中会自动包含父进程传递的可继承句柄。子进程可通过以下方式获取句柄值: - 通过命令行参数或环境变量传递句柄值(需父进程显式设置)。 - 通过进程间通信(如管道、共享内存)传递句柄信息。 --- #### **二、内核对象继承的作用** 1. **资源高效共享** 父子进程可直接复用同一内核对象(如文件、互斥锁),无需重复创建或通过复杂通信机制传递资源。例如,父子进程共享一个互斥锁$hMutex$以同步对共享内存的访问。 2. **权限隔离与安全控制** 内核对象本身不具备继承性,仅句柄可继承。父进程通过控制哪些句柄可继承,实现细粒度的权限管理。例如,父进程可仅暴露文件句柄,而隐藏其他敏感资源。 3. **简化进程协作** 在管道通信、进程池等场景中,子进程可直接使用父进程预分配的资源(如管道句柄),减少初始化开销。 --- #### **三、关键限制与注意事项** 1. **仅限父子进程** 句柄继承仅在父子进程间有效,无亲缘关系的进程需通过其他机制(如命名对象、DuplicateHandle)共享资源。 2. **句柄值可能变化** 子进程中的继承句柄值可能与父进程不同,需通过显式传递实际值或索引来定位。 3. **安全性配置** $SECURITY\_ATTRIBUTES$中的$lpSecurityDescriptor$字段可定义对象的安全属性,防止未授权访问。 --- §§ 1. 内核对象继承与面向对象编程中的继承有何本质区别?[^2] 2. 如何防止子进程滥用继承的内核对象句柄? 3. 在Linux内核中,进程间共享文件描述符的实现机制是否类似?[^3] 4. 使用DuplicateHandle函数复制句柄与继承句柄有何异同? 5. 内核对象继承在Android Binder机制中有哪些应用场景?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值