面对IE保护模式的开发者生存之道
保护模式的另一个影响是,一个插件不能让一个单独的应用程序继承一个内核对象的句柄。举个例子来说,当保护模式被启用的时候,我们的插件不能创建一个文件映射对象,运行这个单独的应用程序(传递bInheritHandles的参数TRUE给CreateProcess()),并且让这个应用程序继承文件映射对象的句柄。
HANDLE hMapping;DemoApp然后将从/h交换读取句柄的值,并使用这个值来调用MapViewOfFile()来读取数据。这是让新的进程自动接受一个内核对象句柄的标准技术,但是当保护模式被启用的时候,新的进程实际上是由代理进程发起的。因为IE进程没有直接启动这个新的进程,句柄继承不再起作用。
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES) };
sa.bInheritHandle = TRUE;
hMapping = CreateFileMapping( INVALID_HANDLE_VALUE, &sa,
PAGE_READWRITE, 0, cbyData, NULL );
// Omitted: Put data in the shared memory block...
// Run the EXE and pass it the shared memory handle.
CString sCommandLine;
BOOL bSuccess;
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
sCommandLine.Format( _T("\"C:\\path\\to\\DemoApp.exe\" /h:%p"),
hMapping );
bSuccess = CreateProcess(
NULL, sCommandLine.GetBuffer(0), NULL, NULL,
TRUE, // TRUE => the new process should inherit handles
NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi );
为了解决这个限制,插件可以为一个IPC对象使用预先定义好的名称,那么这个单独的应用程序将能偶访问这个对象,因为这个对象具有低完整性级别。如果你不想使用一个预先定义好的名称,你可以在运行的时候产生一个名称(例如使用一个GUID作为名字),并将这个名称传递给这个单独的应用程序:
// Get a GUID that we'll use as the name of the shared memory object.使用这个方法,这个EXE程序在命令行中接受到这个IPC对象的名称。它然后能调用OpenFileMapping()来访问这个对象。但是,这个方法有些复杂,因为你需要对于对象生命周期管理非常谨慎。当使用句柄继承的时候,事件的顺序是:
GUID guid = {0};
WCHAR wszGuid[64] = {0};
HRESULT hr;
CoCreateGuid( &guid );
StringFromGUID2( guid, wszGuid, _countof(wszGuid) );
// Create the file mapping object, we don't need a SECURITY_ATTRIBUTES
// struct since the handle won't be inherited.
HANDLE hMapping;
hMapping = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, cbyData, CW2CT(wszGuid) );
// Omitted: Put data in the shared memory block...
// Run the EXE and pass it the name of the shared memory object.
// Note that the bInheritHandles param to CreateProcess() is FALSE.
CString sCommandLine;
BOOL bSuccess;
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
sCommandLine.Format( _T("\"C:\\path\\to\\DemoApp.exe\" /n:%ls"),
wszGuid );
bSuccess = CreateProcess(
NULL, sCommandLine.GetBuffer(0), NULL, NULL,
FALSE, // FALSE => the new process does not inherit handles
NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi );
1、插件创建IPC对象,并将其引用计数设为1。
2、插件起动继承了句柄的进程。这增加对象的引用计数到2。
3、插件现在可以立即关闭它的句柄,因为它不再需要这个对象了。引用计数降到0。
4、这个新的进程完成任何它需要与这个IPC对象的东西。因为它依然有一个开放的句柄,这个对象在这个新的进程关闭它的句柄之前一直存在。
0
相关文章