`
coolsooner
  • 浏览: 1311121 次
文章分类
社区版块
存档分类
最新评论

UAC相关的几个问题/Manifest文件

 
阅读更多

Vista/Win7/Windows Server 2008,加入了UAC功能,这就给开发带来了很多问题,总结了一下碰到的问题和解决办法。
1)权限提升之前,即使是管理员权限帐号(built-in Administrator除外)登陆,也不能向根目录,C:/windows, C:/program files等目录下写文件。
还有也不能访问其他用户的私有文件夹,比如其他用户的Desktop文件夹等。

2)有时候执行一个安装程序,UAC的权限提升询问对话框(就是屏幕变暗那个)就会弹出来,Windows怎么知道这个程序需要权限提升才能执行呢?
a) 编译的时候加入manifest:<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
反过来,如果不希望提升,就指定为level="asInvoker"。下面会谈到,某些时候Windows也会误认为你的程序需要提升权限,本来是不需要。
但是这样有可能在WindowXP SP2造成程序崩溃的问题。
产生这个问题,目前已知的原因:手动编辑 manifest 文件导致的;使用 Visual Studio 2005 自动产生 manifest 文件导致的。
解决办法:http://support.microsoft.com/kb/921337/en-us
b) 程序名字或者文件说明里面包含了setup, install等单词,Windows就会把它当作一个安装程序,认为需要提升权限了。
很容易证明,随便找个EXE,把名字改成setup.exe,再去执行,看看会出现什么。这个时候,如果本来不需要提升,那就需要manifest了。

3)CreateProcessWithLogonW这个API,本来可以利用它来进行用户切换。
比如为了安装软件,通常需要管理员权限用户登录,
管理员可预先设定好管理权限用户密码,保存在安装包中,发给普通用户,
普通用户登陆执行安装包,通过这个API就可以切换到管理员权限,执行安装。这样就省事多了。
但是UAC下,任何调用 CreateProcess系列API来启动一个需要提升权限的程序(例如安装程序),这个API就会失败,返回ERROR_ELEVATION_REQUIRED(740)。
解决办法,写个壳程序,它不需要权限提升,CreateProcessWithLogonW切换用户并启动这个壳程序,
然后由这个壳程序调用ShellExecute来启动目标程序。
当然,调用ShellExecute提升权限的时候,还是会弹出UAC的权限提升询问对话框,否则就等于绕过UAC了。

4)RUN/RUNONCE注册表项
已知:(参考http://msdn2.microsoft.com/en-us/library/bb325654.aspx
a) UAC下,通过Startup菜单或者RUN注册表项启动的应用程序,如果此程序需要权限提升,将会被UAC阻止(Block)。
这个时候,右下角的任务栏上会出现个图标。
类似上面3)的办法,先启动个不需要权限提升的壳程序,这个壳程序再启动目标程序,可以解决这个问题。

b) UAC下,写在RUNONCE注册表的项目,如果用普通用户(非管理员用户)登陆,不会被执行。
好像没什么解决办法。

5)UAC使用UIPI(User Interface Privilage Intergrity)技术
来防止低权限(Lower Integrity)的进程通过向其他已提升权限的进程发送消息的方式来进行一些可能危害系统安全的操作。
但是如果我们需要这样做怎么办呢?
Vista之后提供了一个新的API, 提升过权限的进程调用它可以打开这个限制,允许接受从低安全等级的进程发送过来的消息。
API是ChangeWindowMessageFilter,有2个参数,消息代码和操作类型(接受还是拒绝)。
参考:http://msdn2.microsoft.com/en-us/library/ms632675(VS.85).aspx



使用Visual Studio进行开发的时候,默认是把Manifest文件嵌入到exe或者dll文件中的。
随Visual Studio提供一个工具mt.exe,可以用来把Manifest文件嵌入到exe或者dll文件中,或者反之,从文件中导出Manifest。
因此可以使用mt.exe来查看manifest。
exe文件:mt.exe -inputresource:<exe-file>;#1 -out:<manifest-file>
dll文件:mt.exe -outputresource:<dll-file>;#2 -out:<manifest-file>


和Manifest相关的一个技术是Side-by-Side Assembly(SxS),这是微软在Visual Studio 2005中引入的技术,用来解决Windows平台上的DLL Hell问题。
http://msdn.microsoft.com/en-us/library/aa376307%28VS.85%29.aspx
例如,使用VS2005生成exe中嵌入以下的manifest文件:


winsxs下有2个相关目录:
1)存放manifest文件
%WINDIR%/WinSxS/Manifests/x86_microsoft.vc80.crt_<版本>.manifest,该清单用来标识此程序集并列出其内容(属于此程序集的 DLL)
2)程序集
%WINDIR%/WinSxS/Manifests/x86_microsoft.vc80.crt_<版本>目录下。

这样程序启动时,需要到winsxs目录下去根据manifest中的版本信息加载相应的WinCRT。

并行程序集还可以使用发行者配置文件(也称为策略文件),以便在全局上重定向应用程序和程序集,使其从使用并行程序集的一个版本变为使用该程序集的另一版本。
Windows XP中该文件在%WINDIR%/WinSxS/Policies/下面。
Windows Vista以后在%WINDIR%/winsxs/Manifests/下面。
文件名是x86_policy.8.0.microsoft.vc80.crt_<版本>。
例如,在一台没有安装上面exe的manifest中记载版本(8.0.50608.0)的CRTWindowsVista系统上,也能正常运行此exe。
原因是在已经安装的CRT的策略文件中有如下记载:


以上策略指定,对于需要此程序集8.0.41204.256-8.0.50608.0版的任何应用程序或程序集,都应改用此程序集的8.0.50727.5592版,此版本是安装在系统上的当前版本。
所以程序会改为加载8.0.50727.5592的CRT,也就能够正常启动了。

也可以将 CRT 程序集作为私有并行程序集,安装在应用程序的本地文件夹中。如果操作系统未能找到 CRT 或作为共享程序集的任何其他程序集,它会开始将该程序集作为私有程序集来查找。它将按以下顺序搜索私有程序集:
1.在应用程序本地文件夹中查找名为 <assemblyName>.manifest 的清单文件。在此示例中,加载程序尝试在exe所在的文件夹中查找 Microsoft.VC80.CRT.manifest。如果找到该清单,加载程序将从应用程序文件夹中加载 CRT DLL。如果未找到 CRT DLL,加载将失败。

2.尝试在exe本地文件夹中打开文件夹 <assemblyName>,如果存在此文件夹,则从中加载清单文件 <assemblyName>.manifest。如果找到该清单,加载程序将从 <assemblyName> 文件夹中加载 CRT DLL。如果未找到 CRT DLL,加载将失败。

因此对于VS2005,可以到
<VS2005安装目录>/VC/redist/x86/Microsoft.VC80.CRT目录下,把以下4个文件拷贝出来,和exe一起发布。注意不能只是拷贝dll文件,必须也拷贝manifest文件。
Microsoft.VC80.CRT.manifest
msvcm80.dll
msvcp80.dll
msvcr80.dll

另外,VS2010中似乎已经取消了使用winsxs,至少默认是不用的。

可以参考http://blogs.msdn.com/b/vcblog/archive/2008/10/28/visual-studio-2010-ctp-released.aspx

New deployment model for Visual C++ Libraries (changed to not use Windows SxS configuration)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics