技术开发 频道

面对IE保护模式的开发者生存之道


   保护模式的另一个影响是,一个插件不能让一个单独的应用程序继承一个内核对象的句柄。举个例子来说,当保护模式被启用的时候,我们的插件不能创建一个文件映射对象,运行这个单独的应用程序(传递bInheritHandles的参数TRUE给CreateProcess()),并且让这个应用程序继承文件映射对象的句柄。

HANDLE hMapping; 
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 );
   DemoApp然后将从/h交换读取句柄的值,并使用这个值来调用MapViewOfFile()来读取数据。这是让新的进程自动接受一个内核对象句柄的标准技术,但是当保护模式被启用的时候,新的进程实际上是由代理进程发起的。因为IE进程没有直接启动这个新的进程,句柄继承不再起作用。

   为了解决这个限制,插件可以为一个IPC对象使用预先定义好的名称,那么这个单独的应用程序将能偶访问这个对象,因为这个对象具有低完整性级别。如果你不想使用一个预先定义好的名称,你可以在运行的时候产生一个名称(例如使用一个GUID作为名字),并将这个名称传递给这个单独的应用程序:

// Get a GUID that we'll use as the name of the shared memory object. 
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 );
   使用这个方法,这个EXE程序在命令行中接受到这个IPC对象的名称。它然后能调用OpenFileMapping()来访问这个对象。但是,这个方法有些复杂,因为你需要对于对象生命周期管理非常谨慎。当使用句柄继承的时候,事件的顺序是:

  1、插件创建IPC对象,并将其引用计数设为1。
  2、插件起动继承了句柄的进程。这增加对象的引用计数到2。
  3、插件现在可以立即关闭它的句柄,因为它不再需要这个对象了。引用计数降到0。
  4、这个新的进程完成任何它需要与这个IPC对象的东西。因为它依然有一个开放的句柄,这个对象在这个新的进程关闭它的句柄之前一直存在。

0
相关文章