65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Internet Explorer 7 中运行进程而无需安全警告

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.46/5 (6投票s)

2008年11月5日

CPOL

3分钟阅读

viewsIcon

139763

如何在 Internet Explorer 中阻止安全警告,例如“已识别的程序想要访问您的计算机”或“网站想要使用此程序在您的计算机上打开网页内容”。

介绍 

由于 Internet Explorer 7 提供了针对恶意攻击的最佳保护,正如 MSDN 所说,我相信任何人都将遇到相同的情况 - 当 Internet Explorer 的扩展程序试图启动另一个进程时,Internet Explorer 将弹出一个提示,如下面两个示例屏幕截图所示

Security warning 1

特别是,上述“安全警告”对话框会发生在拥有特定权限的特殊程序进程中,这些权限是在清单 XML 文件中编写的。

Security warning 2

通常,如果程序进程没有在清单 XML 文件中编写的权限,则会弹出上述“UAC 控制”对话框。

正如您所猜测的,我将讨论 UAC、Internet Explorer 保护模式问题。实际上,我不想在这里进一步解释 Internet Explorer 保护模式
过去,Michael Dunn 在他的文章 开发人员的 IE 保护模式生存指南 中给出了更多描述。

如果您已经阅读了 MSDN 和 Mike 关于 Internet Explorer 保护模式的文章,您可能想尝试 从保护模式启动进程' by MSDN solution. 不幸的是,我尝试使用这种方法,然后尝试执行 CreateProcessShellExecute(Ex),但失败了。

幕后

为了解决上面提到的这个问题,您首先需要了解 ACL(访问控制列表) 知识。如果您不想接触这方面,您可以跳过下面的简要说明,然后直接享受下面的代码。

原理是创建一个新的高权限令牌,该令牌引用 Internet Explorer 令牌。新的高权限令牌将拥有所有访问权限,然后我们将高权限令牌作为参数传递给 CreateProcessAsUser。因此,此进程将在由高权限令牌表示的用户的安全上下文中运行。

您可以在下面我已封装为函数 - CreateSystemProcess 的完整代码中看到更多详细信息。参数 szProcessName 是要启动的新进程的可执行文件路径。

#include <Accctrl.h>
#include <Aclapi.h>

BOOL CreateSystemProcess( LPTSTR szProcessName)
{
	HANDLE hProcess;
	HANDLE hToken, hNewToken;
	DWORD dwPid;

	PACL pOldDAcl = NULL;
	PACL pNewDAcl = NULL;
	BOOL bDAcl;
	BOOL bDefDAcl;
	DWORD dwRet;

	PACL pSacl = NULL;
	PSID pSidOwner = NULL;
	PSID pSidPrimary = NULL;
	DWORD dwAclSize = 0;
	DWORD dwSaclSize = 0;
	DWORD dwSidOwnLen = 0;
	DWORD dwSidPrimLen = 0;

	DWORD dwSDLen;
	EXPLICIT_ACCESS ea;
	PSECURITY_DESCRIPTOR pOrigSd = NULL;
	PSECURITY_DESCRIPTOR pNewSd = NULL;

	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	CString strUserName;

	BOOL bError;

	// Get the current process - IEExplore.exe
	hProcess = GetCurrentProcess();

	// Open IE process token and specify the access types to IE token
	if ( !OpenProcessToken( hProcess, READ_CONTROL | WRITE_DAC, &hToken ) )
	{
		printf( "OpenProcessToken() = %d\n", GetLastError() );

		bError = TRUE;
		goto Cleanup;
	}

	// Create a new access control information that includes all access permissions.
	ZeroMemory( &ea, sizeof( EXPLICIT_ACCESS ) );
	BuildExplicitAccessWithName( &ea,
		"CURRENT_USER", // Note: if you specified other trustee name,
			       // it would fail at subsequent code
		TOKEN_ALL_ACCESS,
		GRANT_ACCESS,
		0 );

	if ( !GetKernelObjectSecurity( hToken,
		DACL_SECURITY_INFORMATION,
		pOrigSd,
		0,
		&dwSDLen ) )
	{
		// We first get the length of original
		// security descriptor to IE token
		if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
		{
			pOrigSd = ( PSECURITY_DESCRIPTOR )
				HeapAlloc( GetProcessHeap(),
				HEAP_ZERO_MEMORY,
				dwSDLen );
			if ( pOrigSd == NULL )
			{
				printf( "Allocate pSd memory to failed!\n" );


				bError = TRUE;
				goto Cleanup;
			}

			// Again, we now get the original
			// security descriptor to IE token
			if ( !GetKernelObjectSecurity( hToken,
				DACL_SECURITY_INFORMATION,
				pOrigSd,
				dwSDLen,
				&dwSDLen ) )
			{
				printf( "GetKernelObjectSecurity() = %d\n",
							GetLastError() );
				bError = TRUE;
				goto Cleanup;
			}
		}
		else
		{
			printf( "GetKernelObjectSecurity() = %d\n", GetLastError() );
			bError = TRUE;
			goto Cleanup;
		}
	}

	// Getting ACL of original security descriptor
	if ( !GetSecurityDescriptorDacl( pOrigSd, &bDAcl, &pOldDAcl, &bDefDAcl ) )
	{
		printf( "GetSecurityDescriptorDacl() = %d\n", GetLastError() );

		bError = TRUE;
		goto Cleanup;
	}

	// Using the created access control information - EXPLICIT_ACCESS,
	// and the original ACL to generate a new ACL
	dwRet = SetEntriesInAcl( 1, &ea, pOldDAcl, &pNewDAcl );
	if ( dwRet != ERROR_SUCCESS )
	{
		printf( "SetEntriesInAcl() = %d\n", GetLastError() );
		pNewDAcl = NULL;

		bError = TRUE;
		goto Cleanup;
	}

	// Create a new security descriptor that refers
	// to original security descriptor.
	if ( !MakeAbsoluteSD( pOrigSd,
		pNewSd,
		&dwSDLen,
		pOldDAcl,
		&dwAclSize,
		pSacl,
		&dwSaclSize,
		pSidOwner,
		&dwSidOwnLen,
		pSidPrimary,
		&dwSidPrimLen ) )
	{
		if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
		{
			pOldDAcl = ( PACL ) HeapAlloc( GetProcessHeap(),
				HEAP_ZERO_MEMORY,
				dwAclSize );
			pSacl = ( PACL ) HeapAlloc( GetProcessHeap(),
				HEAP_ZERO_MEMORY,
				dwSaclSize );
			pSidOwner = ( PSID ) HeapAlloc( GetProcessHeap(),
				HEAP_ZERO_MEMORY,
				dwSidOwnLen );
			pSidPrimary = ( PSID ) HeapAlloc( GetProcessHeap(),
				HEAP_ZERO_MEMORY,
				dwSidPrimLen );
			pNewSd = ( PSECURITY_DESCRIPTOR )
				HeapAlloc( GetProcessHeap(),
				HEAP_ZERO_MEMORY,
				dwSDLen );

			if ( pOldDAcl == NULL ||
				pSacl == NULL ||
				pSidOwner == NULL ||
				pSidPrimary == NULL ||
				pNewSd == NULL )
			{
				printf( "Allocate SID or ACL to failed!\n" );

				bError = TRUE;
				goto Cleanup;
			}

			if ( !MakeAbsoluteSD( pOrigSd,
				pNewSd,
				&dwSDLen,
				pOldDAcl,
				&dwAclSize,
				pSacl,
				&dwSaclSize,
				pSidOwner,
				&dwSidOwnLen,
				pSidPrimary,
				&dwSidPrimLen ) )
			{
				printf( "MakeAbsoluteSD() = %d\n", GetLastError() );

				bError = TRUE;
				goto Cleanup;
			}
		}
		else
		{
			printf( "MakeAbsoluteSD() = %d\n", GetLastError() );

			bError = TRUE;
			goto Cleanup;
		}
	}

	// Well, we have owned a new security descriptor & a new ACL,
	// all we have to do is fetch the new ACL into the new security descriptor!
	if ( !SetSecurityDescriptorDacl( pNewSd, bDAcl, pNewDAcl, bDefDAcl ) )
	{
		printf( "SetSecurityDescriptorDacl() = %d\n", GetLastError() );

		bError = TRUE;
		goto Cleanup;
	}

	//
	// Injects the new security descriptor into IE token
	//
	if ( !SetKernelObjectSecurity( hToken, DACL_SECURITY_INFORMATION, pNewSd ) )
	{
		printf( "SetKernelObjectSecurity() = %d\n", GetLastError() );

		bError = TRUE;
		goto Cleanup;
	}

	//
	// When we open IE process again, the hToken has all access permissions.
	//
	if ( !OpenProcessToken( hProcess, TOKEN_ALL_ACCESS, &hToken ) )
	{
		printf( "OpenProcessToken() = %d\n", GetLastError() );

		bError = TRUE;
		goto Cleanup;
	}

	//
	// Then, make a duplicate from IE token
	//
	if ( !DuplicateTokenEx( hToken,
		TOKEN_ALL_ACCESS,
		NULL,
		SecurityImpersonation,
		TokenPrimary,
		&hNewToken ) )
	{
		printf( "DuplicateTokenEx() = %d\n", GetLastError() );

		bError = TRUE;
		goto Cleanup;
	}


	ZeroMemory( &si, sizeof( STARTUPINFO ) );
	si.cb = sizeof( STARTUPINFO );

	// Now, we impersonate the security context of a
	// logged-on user using the token.
	// Note: if you didn't, the below CreateProcessAsUser
	// will report 1314 no permission error.
	ImpersonateLoggedOnUser( hNewToken );


	// Finally, we use the token to create new process.
	if ( !CreateProcessAsUser( hNewToken,
		NULL,
		szProcessName,
		NULL,
		NULL,
		FALSE,
		NULL, //NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
		NULL,
		NULL,
		&si,
		p ) )
	{
		strMsg.Format( "CreateProcessAsUser() = %d\n", GetLastError() );

		bError = TRUE;
		goto Cleanup;
	}

	bError = FALSE;

Cleanup:
	if ( pOrigSd )
	{
		HeapFree( GetProcessHeap(), 0, pOrigSd );
	}
	if ( pNewSd )
	{
		HeapFree( GetProcessHeap(), 0, pNewSd );
	}
	if ( pSidPrimary )
	{
		HeapFree( GetProcessHeap(), 0, pSidPrimary );
	}
	if ( pSidOwner )
	{
		HeapFree( GetProcessHeap(), 0, pSidOwner );
	}
	if ( pSacl )
	{
		HeapFree( GetProcessHeap(), 0, pSacl );
	}
	if ( pOldDAcl )
	{
		HeapFree( GetProcessHeap(), 0, pOldDAcl );
	}

	if (!bError)
	{
	    CloseHandle( pi.hProcess );
	    CloseHandle( pi.hThread );
	    CloseHandle( hToken );
	    CloseHandle( hNewToken );
	    CloseHandle( hProcess );
	}

	if ( bError )
	{
	    return FALSE;
	}

	return TRUE;
}

实际上,上面给出的整个代码都来自互联网的某个地方。我只是为了这个目的修改了其中的一部分。但是,如果您想创建一个高权限令牌,它仍然很有用。这意味着您可以将创建的高权限令牌传递给任何具有类似 hToken 参数的 API 函数。

注意使用代码

您不需要将清单 XML 文件嵌入到您的 EXE 文件中。如果您这样做了,至少,您应该删除如下所示的类似部分

<v3:trustInfo xmlns:v3="urn:schemas-microsoft-com:asm.v3">
  <v3:security>
    <v3:requestedPrivileges>
      <v3:requestedExecutionLevel level="requireAdministrator" />
    </v3:requestedPrivileges>
  </v3:security>
</v3:trustInfo>
</assembly>

我认为原因是 Vista 始终认为该进程以清单信息指定的权限模式运行。所以即使我们为 CreateProcessAsUser 创建了一个高权限令牌,它在 Internet Explorer 7 中也永远无法正常工作。
另一方面,我不确定即将推出的 Internet Explorer 8 是否接受这种技巧函数。希望 Internet Explorer 8 永远不要采用这种风格。:)

反馈

我尝试了封装函数 - CreateSystemProcess,它在我的 Vista Ultimate 版本上运行良好,并且适用于管理员和普通用户模式。
如果代码在您的 Vista 上不起作用,请通过 chenxinyi1978@hotmail.com 与我联系,我很乐意尽快解决新问题。

历史

  • 2008年11月5日:文章创建
© . All rights reserved.