冲出UAC-解决Win UAC问题的编程经验

    感想关注 ,转载引用请注明 http://blog.csdn.net/leonwei/article/details/8905703 

 

   最近一直在搞页游版的端游移植,里面用到了很多进程启动进程的情况,这种情况在XP以前的系统上是很常见的编程形式,也从来不会出现问题,但是搬到Win7系统上就不行,在很多用户的Win7系统中,进程A去启动进程B(如果直接使用CreateProcess)会创建失败,后来发现这是因为受到了UAC的控制,将解决这类问题的经验总结于此。

1.什么是UAC

UAC全称User Access Control,是Win Vista系统开始引入的一种安全机制,它在操作系统中定义了多种用户访问的安全级别(可在用户账户中修改,默认为中),

不同的安全级别对于程序的行为是有不同限定的:

从不通知:这个跟XP一样,没有限定任何程序行为,是最低的

仅当程序尝试更改计算机时通知:当你的程序会触发对计算机的修改,更简单的说就是你发生了写磁盘操作,就会弹出通知询问用户(这是默认的)

始终通知:无论是自己还是程序修改计算机都会触发询问

 例如当我们在win7下打开某个程序时可能触发这样的画面

这个小盾牌我们经常看见,这就是触发了UAC的询问了

 

2.UAC会给编程带来哪些问题

UAC在vista上他是一个饱受诟病的东西,因为在它降低了用户使用程序软件的连贯性,经常的这种弹窗很烦,而且它能带来的安全保护又有些鸡肋,所以很多用户去控制面板里关了它,但是微软在Win7之后的版本仍然保留甚至加强了这个东西,甚至在Win8版本中用户想关它都要费点麻烦。

他对于我们的编程上更是带来一些问题,但是既然我们还在用Windows,而UAC就是Windows的一部分,我们就要Do the Microsoft Way 了。

在编程上通常有下列问题(在开启uac的情况下):

1.任何更改系统或者写磁盘的操作都会失败(例如fopen这些都会失败)

2.对其他进程的调用会失败(例如createprocess)

 

3.解决方案

 3.1 首先对于写磁盘失败这些问题,是因为你的程序启动默认都是采用低权限启动的,突破UAC你就要使用高权限启动程序,行话叫elevate(提升)。一个程序启动后是没有办法任何办法elavate的,一个程序是不是被elevate只有在启动的那一时刻决定,查阅了一下MSDN,上面有张图如下,就是UAC起作用与elevate的整个过程。记住elevate只有在启动时可以发生,一旦它已经运行了,没有任何办法提升他的权限。

所以对待这样的程序,在win7下我们要显示的声明他们需要elevate,而如何显示声明,就是把这个信息写入exe的清单文件(,manifest),在vs下面,清单文件一般我们让他默认生成,而如果是想让在win7下获得elevate,可以建立一个新的manifest文件,内容如下

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
<ms_asmv2:security>
<ms_asmv3:requestedPrivileges xmlns:ms_asmv3="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</ms_asmv3:requestedPrivileges>
</ms_asmv2:security>
</ms_asmv2:trustInfo>
</assembly>
其中的level="requireAdministrator就标志着这个程序的执行需要elevate,在vs里附加以上清单文件,再编译链接,就会发现新生成的exe文件带有一个盾牌,如图,这标志着这个程序的启动需要以管理员权限启动,它可能会修改系统。

当这个exe双击启动时,会触发UAC,而在得到用户的询问允许后,你的程序就自然获得了高权限,就可以写磁盘了。(相反,没有这个盾牌,启动后不触发UAC,自动进入较低权限,你程序的行为可能就会被限制)

 

3.2还有一种情况是对process的调用,如你在A程序中想创建一个进程B,如果进程A的权限较低,而B的权限较高(即A有盾牌,B没有盾牌),那么B是回创建失败的,怎么办,一种是像前面那样把A加个盾牌,另一种就是采用ShellExecuteEx启动进程。

ShellExecuteEx是唯一一个微软允许触发UAC的进程启动函数,如下面代码

SHELLEXECUTEINFO shExInfo = {0};
 shExInfo.cbSize = sizeof(shExInfo);
 shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
 shExInfo.hwnd = 0;
 shExInfo.lpVerb = _T("open");                // Operation to perform
 shExInfo.lpFile = enginePath;       // Application to start   
 shExInfo.lpParameters = szBuf;                  // Additional parameters
 shExInfo.lpDirectory = workingPath;
 shExInfo.nShow = SW_SHOW;
 shExInfo.hInstApp = 0; 

ShellExecuteEx(&shExInfo);
 

使用ShellExecuteEx启动中,lpVerb可以指定为Open、edit等等,这个函数不仅可以启动进程,还可以打开文件,这个函数会自动触发UAC的询问。

在Win7下使用Createprocess,如果发现权限不足,会直接失败,而ShellExecuteEx则是一个好的解决方法。

 

posted on 2013-05-09 15:46  leonwei  阅读(258)  评论(0编辑  收藏  举报