如何在windows开启UAC(用户账号控制)的情况下优雅的管理程序的权限申请方案(一)

问题起源:

       简单的说就是在windows vista之前的windows系统,只要是管理员(比如Administrator)账户登录系统以后,该账户下的任何程序的启动权限都具有管理员权限;这个权限是很高的(仅仅比System权限低),具有这个权限的程序几乎可以“为所欲为”,试想如果一个病毒程序拥有了这个权限,那它可以做很多的“破坏”活动,这将给系统的安全造成了极大的安全隐患。

UAC技术摘要:

windows vista版本开始windows引入了UAC机制,用户帐户控制User Account Control,简写作UAC)是微软公司在其Windows Vista及更高版本操作系统中采用的一种控制机制。其原理是通知用户是否对应用程序使用硬盘驱动器和系统文件授权,以达到帮助阻止恶意程序(有时也称为“恶意软件”)损坏系统的效果。

至于windows下如何关闭和打开UAC,可以参照:https://jingyan.baidu.com/article/fc07f9897fd90712fee51976.html,这里不做过多赘述。

打开和关闭UAC比较:

  • 在打开UAC功能的时候:

如果一个程序希望强制拥有足够的权限来运行自己,那么在编译程序的时候可以通过VS的工程属性:配置属性--->链接器--->清单文件--->UAC执行级别,并将值设置为:requireAdministrator (/level='requireAdministrator')。这个时候编译出来的程序的图标右下角通常会有一个小盾牌:

有这个小盾牌的程序表示程序必须在管理员权限下才能运行(相当于必须程序右键菜单--->管理员权限运行),在程序运行前就会弹出一个让用户确认提权的对话框:

注意:这个弹出窗口其实是在windows的另一个桌面上(windows多桌面技术)的,程序是无法绕开用户来帮用户完成相应的点击动作的,也就是这个程序提权必须交给用户来选择的,这就避免了恶意程序绕开用户偷偷提权运行的风险。只要当用户同意了程序的提权申请这个程序才会被系统执行,否则程序是无法被系统执行的。

如果一个程序被强制设置为必须具有管理员权限才能运行的话,假如这个程序放在非管理员账户的User账户下会怎么样呢,当然这个程序还是需要提权的,而且是需要提升为管理权限,这个时候就会弹出一个管理员账户的登录窗来让管理员用户进行登录,只有成功登录管理员账户后这个程序才能正常的获权执行。

所以结论就是:

  1. 既然windows提供了这么个程序权限管理机制,那么一个用户体验良好和尊重用户的程序应该在除非一定要提权的情况下,能不强求用户提权就不应该让用户提权,因为每次提权的弹窗其实对用户来说都是一种打扰,除非在必要的时刻才进行相应的提权操作。比如windows在某些对话框的某些按钮才有盾牌图标,只有点击到这个按钮才会弹出UAC提权窗口:

  2. 回想我们的学生时代,很多机房的电脑其实开设的账户并不是管理员账户,而是普通的用户账户,如果一个程序必须提权为管理员权限才能运行的话,那么这类程序就无法运行了。这样的例子可能在部分网吧或者在国外欠发达的地区比较常见。

小结:一个体验良好的程序一般不会强求用户以管理员权限运行自己的程序。

  • 在系统彻底关闭UAC的时候:

在系统彻底关闭UAC的状况下,就有点类似XP系统了,双击任意一个程序,程序会默认自动获取管理权限运行。这其实是很危险的。所以建议用户在vista以上版本的系统最好打开UAC功能来保护系统免受侵害。

 

如何判断当前程序是否需要进行提权

  • 通常能够触发UAC规则的常用操作包括以下内容。

运行应用程序

增加或者删除用户账户

安装或者卸载程序

安装设备驱动程序

修改注册表文件

复制文件到windows目录

安装activex控件

权限低的程序注入DLL到权限高的程序

而笔者遇到的一个场景就是自己的Client.exe进程需要注入DLL到游戏的game.exe进程。显然如果自己的Client.exe非管理员权限运行的情况下如果要注入到以管理员权限运行的目标game.exe游戏进程因为权限不足是会失败的,也就是这种状况下Client.exe是必须进行提权操作后才能成功注入DLL到目标游戏进程的。而如果目标game.exe进程是非管理员权限运行,那么哪怕自己的Client.exe是非管理员权限运行也是能正常注入的。

上图显示,只有Client.exe进程没有管理员权限而目标game.exe管理员权限运行的情况下才会出现注入DLL失败的情况,考虑到目标game.exe进程是非特定的,可能是任意一个游戏进程。所以说只有一种失败情况的前提下如果强制进程必须以管理员权限运行其实是不好。合理的做法应该是:判断当前进程没有管理员权限并且目标进程拥有管理员权限的情况下才进行相应的提权操作。

那么如何判断一个程序是否有管理员权限呢,相应的代码如下:

BOOL IsElevated(DWORD dwPid)
{
	HANDLE	hProcess = NULL;
	if (0 == dwPid)
		hProcess = GetCurrentProcess();
	else
	{
		hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION/*PROCESS_QUERY_INFORMATION*/, FALSE, dwPid);
		if (nullptr == hProcess && GetLastError() == 5)  //比如服务程序    自己没有权限打开    直接会打开失败的
			return TRUE;
	}

	BOOL fRet = FALSE;
	HANDLE hToken = NULL;
	if (hProcess && OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
		TOKEN_ELEVATION Elevation;
		DWORD cbSize = sizeof TOKEN_ELEVATION;
		if (GetTokenInformation(hToken,
			TokenElevation,
			&Elevation,
			sizeof(Elevation),
			&cbSize))
			fRet = Elevation.TokenIsElevated;
	}

	if (hToken) CloseHandle(hToken);

	return fRet;
}

上面函数只要传入本进程的PID或者目标进程PID,就可以返回该进程是否拥有了管理员权限。

那么如果遇到自身程序权限不足而目标进程权限比较高的情况下,那就必须做提权操作了,也就是说程序还是无法绕开UAC,这个提权的操作还是会弹出来让用户选择的。

那既然提权的弹窗无法绕开,那是不是每次遇到注入DLL时需要提权的情况就以管理员权限重启自己来让用户提权呢。请看下文:

如何在windows开启UAC(用户账号控制)的情况下优雅的管理程序的权限申请方案(二)

发布了7 篇原创文章 · 获赞 1 · 访问量 6904

猜你喜欢

转载自blog.csdn.net/liaozhilong88/article/details/104037226