WIN32 动态 UAC 提权
UAC(User Account Control) 是 Windows 平台的用户权限控制。它可以让程序使用管理员权限执行某些操作。
静态 UAC 提权
静态 UAC 提权让程序一直运行在管理员权限下,只要在项目设置里把 "UAC Execution Level" 设置为 "requireAdministrator"。这样生成的 exe 文件图标会自动加上一个小盾牌的角标 Overlay。执行 exe 文件会自动弹出 UAC 对话框。

静态 UAC 提权对程序员来说是一种偷懒的办法,只需要修改一个配置就行。但对用户来说非常麻烦,每次打开程序都需要确认 UAC 对话框。比如“小黑盒加速器”,每次打开它都会弹 UAC 对话框。更奇葩的是“小黑盒加速器” 可以设置开机自启,每次开机都会弹一个 UAC 对话框要你确认。
动态 UAC 提权
动态 UAC 提权让程序一直运行在普通用户权限下,并且只有需要管理员权限操作时才会弹出 UAC 对话框。这种做法比静态 UAC 提权更加细致。一个普通的应用程序 99% 的功能都不需要管理员权限,只在极少数情况下才需要。比如“QQ音乐”,它只是一个音乐播放软件。用户大部分的时间都仅使用音乐播放功能。而需要管理员权限的“将QQ音乐设为默认应用”功能很少会被使用。所以动态 UAC 提权很有必要。
按照微软官方文档 Developing Applications that Require Administrator Privilege,有四种方法可以实现动态 UAC 提权:
- Elevated Task Model
- Operating System Service Model
- Administrator Broker Model
- Administrator COM Object Model
可以根据具体需要实现的功能选择合适的方法。比如:“添加防火墙规则”这个功能需要使用 INetFwPolicy2。这是一个 COM 接口,可以直接用第 4 种方法“Administrator COM Object Model”实现。使用这种方法有个前提,就是这个 COM 接口必须在注册表里是配置为可以提权的。比如 INetFwPolicy2 接口,先找到 NetFwPolicy2 的 GUID 为 E2B3C97F-6AE1-41AC-817A-F6F92166D7DD,再打开 regedit,输入 HKLM\Software\Classes\CLSID\{E2B3C97F-6AE1-41AC-817A-F6F92166D7DD}\Elevation。Enabled 值为 1 就可以用。对于这种方法,The COM Elevation Moniker 介绍得比较详细,所以直接贴出完整代码:
#include <Windows.h>
#include <netfw.h>
#include <comdef.h>
#include <spdlog/spdlog.h>
#include <memory>
#include <filesystem>
#include <wil/resource.h>
#include <wil/com.h>
#include <iostream>
int add_firewall_rule();
int main()
{
add_firewall_rule();
}
int add_firewall_rule()
{
auto couninitialize_call = wil::CoInitializeEx();
auto pNetFwPolicy2 = wil::CoCreateInstance<INetFwPolicy2>(__uuidof(NetFwPolicy2));
wil::unique_cotaskmem_string clsid;
RETURN_IF_FAILED(StringFromCLSID(__uuidof(NetFwPolicy2), &clsid));
// https://learn.microsoft.com/en-us/windows/win32/secauthz/developing-applications-that-require-administrator-privilege
// https://learn.microsoft.com/en-us/windows/win32/com/the-com-elevation-moniker
BIND_OPTS3 bo{};
bo.cbStruct = sizeof(bo);
bo.hwnd = GetConsoleWindow();
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
auto moniker = fmt::format(L"Elevation:Administrator!new:{}", clsid.get());
spdlog::info(L"moniker: {}", moniker);
auto hr = (CoGetObject(moniker.c_str(), &bo, IID_PPV_ARGS(&pNetFwPolicy2)));
wil::com_ptr<INetFwRules> pNetFwRules;
RETURN_IF_FAILED(pNetFwPolicy2->get_Rules(&pNetFwRules));
long count{};
RETURN_IF_FAILED(pNetFwRules->get_Count(&count));
spdlog::info("rule count: {}", count);
wil::com_ptr<IUnknown> pEnumerator;
pNetFwRules->get__NewEnum(&pEnumerator);
auto pVariant = pEnumerator.query<IEnumVARIANT>();
std::vector<wchar_t> buf(1024);
GetModuleFileNameW(nullptr, buf.data(), (DWORD)buf.size());
std::filesystem::path exe_path(buf.data());
// https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ics/c-enumerating-firewall-rules
while (true) {
wil::unique_variant var;
ULONG cFecthed = 0;
if (pVariant->Next(1, &var, &cFecthed) != S_OK) {
break;
}
wil::com_ptr<INetFwRule> pNetFwRule;
var.pdispVal->QueryInterface(__uuidof(INetFwRule), (void**)&pNetFwRule);
_bstr_t app_name;
pNetFwRule->get_ApplicationName(app_name.GetAddress());
std::error_code ec{};
if (!app_name || !std::filesystem::equivalent(exe_path, (wchar_t*)app_name, ec)) {
continue;
}
pNetFwRule->put_Name(app_name);
pNetFwRules->Remove(app_name);
spdlog::info(L"remove firewall rule: {}", (wchar_t*)app_name);
}
auto pNetFwRule = wil::CoCreateInstance<INetFwRule3>(__uuidof(NetFwRule));
pNetFwRule->put_Enabled(VARIANT_TRUE);
pNetFwRule->put_Action(NET_FW_ACTION_ALLOW);
pNetFwRule->put_ApplicationName(_bstr_t(exe_path.c_str()));
pNetFwRule->put_Profiles(NET_FW_PROFILE2_ALL);
pNetFwRule->put_Name(_bstr_t(L"firewall-test.exe(TCP-In)"));
pNetFwRule->put_Protocol(NET_FW_IP_PROTOCOL_TCP);
RETURN_IF_FAILED(pNetFwRules->Add(pNetFwRule.get()));
pNetFwRule->put_Name(_bstr_t(L"firewall-test.exe(UDP-In)"));
pNetFwRule->put_Protocol(NET_FW_IP_PROTOCOL_UDP);
RETURN_IF_FAILED(pNetFwRules->Add(pNetFwRule.get()));
spdlog::info("success");
return S_OK;
}
关于动态 UAC 提权的代码只有第 30-36 行。需要注意的点有:
- 第 32 行的
bo.hwnd设置 UAC 对话框的 owner。如果代码是控制台程序,应该设置为GetConsoleWindow(),如果是 GUI 程序可以直接填nullptr。 - 第 33 行的
bo.dwClassContext应填CLSCTX_LOCAL_SERVER,而不是CLSCTX_INPROC_SERVER。否则提权失败,CoGetObject仍然返回S_OK。 - UAC 对话框出现在
CoGetObject调用时,而不是执行需要管理员权限的操作(如pNetFwRules->Add)时。 - 每次执行
add_firewall_rule()都会弹出 UAC 对话框。
很多动态 UAC 提权的程序都会在需要管理员权限的操作按钮上显示一个小盾牌图标
,表示点击它会请求管理员权限,比如:

可以直接调用 SHGetStockIconInfo 方法直接得到它的 HICON 句柄。
SHSTOCKICONINFO sii{};
sii.cbSize = sizeof(sii);
HRESULT hr = SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &sii);
m_buttonRepairFirewall.SetIcon(sii.hIcon);
DestroyIcon(sii.hIcon);
WIN32 动态 UAC 提权的更多相关文章
- metaspolit下UAC提权以及日志清除
在获得webshell时但权限不够大,这时候为了完全获得受害者机器的权限,使用msf进行后渗透. 一.获取Meterpreter会话 Meterpreter 是msf的一个payload,目标执行之后 ...
- windows UAC 提权实验(CVE-2019-1388)
--------------------------------------------------------------------------------- 声明:本文仅做学习,实验主机为虚拟机 ...
- C++ UAC 提权 以一个管理员身份运行程序
这里是我编译的和一个测试Demo:http://pan.baidu.com/s/1qWNgC6C 大家如果看我下边的不是很清楚,可以下载这个具体工程: 群:103197177 C++进阶讨论:欢迎喜欢 ...
- CVE-2019-1388 Windows UAC提权
漏洞简述 该漏洞位于Windows的UAC(User Account Control,用户账户控制)机制中.默认情况下,Windows会在一个单独的桌面上显示所有的UAC提示——Secure Desk ...
- CVE-2019-1388 UAC提权复现
0x01 前言 该漏洞位于Windows的UAC(User Account Control,用户帐户控制)机制中.默认情况下,Windows会在一个单独的桌面上显示所有的UAC提示--Secure D ...
- 【动态UAC权限】无盾程序(win32&cmd)
可以看到两种不同的提权方式,注意是动态,用代码提权,而不是用清单文件提前处理. 函数都写好了,这里不多做解释. win32程序: 首先需要这俩头文件,第二个我忘了啥函数要用了,总之出问题加上就对了:( ...
- CVE-2014-4113本地提权测试
CVE-2014-4113本地提权漏洞分析 By Netfairy 前言 2014年10月14日, Crowdstrike和FireEye发表了一篇文章, 描述了一个新的针对Windows的提权漏洞. ...
- windows提权操作以及系统开机关机重启代码(用到了LookupPrivilegeValue和AdjustTokenPrivileges调整进程的Token权限)
对于UAC提权操作,一般在编译期间,如果程序有需求要提权,会在编译器里设置,vs2010比较简单,在工程属性里可以直接设置,vs2005稍微有点儿麻烦,参考这篇文章: http://www.seany ...
- Cobalt Strike系列教程第七章:提权与横向移动
Cobalt Strike系列教程分享如约而至,新关注的小伙伴可以先回顾一下前面的内容: Cobalt Strike系列教程第一章:简介与安装 Cobalt Strike系列教程第二章:Beacon详 ...
- 内网渗透 day5-msf本地提权(windows)
msf本地提权 目录 1. 利用uac提权 1 2. 绕过uac认证 2 3. 利用windows本地提权漏洞进行提权 4 1. 利用uac提权 前提与目标机建立会话连接 seach local/as ...
随机推荐
- 12 HTTP的实体数据
目录 数据类型和编码 HTTP协议为什么要关心 body MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型 HTTP 常用数据类型 MIM ...
- vue-admin-template快速开发框架,菜单栏不显示层级结构
问题现象 路由 页面效果 解决办法 路由添加中配置 alwaysShow: true, // 树形层级显示 页面效果
- C++ Qt开发:自定义Dialog对话框组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍自定义Dial ...
- .NET周刊【12月第2期 2023-12-13】
国内文章 用最清爽的方式开发dotNet https://www.cnblogs.com/ncellit/p/17881779.html 本文介绍了如何以清爽的方式开发dotNet应用,特别是简单的A ...
- flask应用程序配置
flask中配置app的配置有几种方式,不同的场景适合用不同的方式. 配置定义方式如下:(注意:这几种方式都时可以混用的) 直接调用app.config来设置. app.config["SE ...
- 部署堡垒机5——安装Core
部署jumpserver服务核心组件Core 一.前期准备 一个后台程序,基本上都是需要依赖于数据库才能运行,后台程序在启动的时候,代码就回去连接数据库,保证数据库,正确启动,且可以正确连接,否则后台 ...
- 编译安装python 3.11
先处理下opensll的版本,以免编python译环境异常:安装 openssl-1.1.1 yum remove openssl cd /opt wget https://www.openssl.o ...
- springboot-jpa获取session
springboot获取hibernate的session进行更精细的SQL操作,默认的jpa并不能满足一些复杂需求(可能是我把需求设计复杂了) 通过查看JpaRepository的底层实现,发现是通 ...
- 2023-05-14:你的赛车可以从位置 0 开始,并且速度为 +1 ,在一条无限长的数轴上行驶, 赛车也可以向负方向行驶, 赛车可以按照由加速指令 ‘A‘ 和倒车指令 ‘R‘ 组成的指令序列自动行驶
2023-05-14:你的赛车可以从位置 0 开始,并且速度为 +1 ,在一条无限长的数轴上行驶, 赛车也可以向负方向行驶, 赛车可以按照由加速指令 'A' 和倒车指令 'R' 组成的指令序列自动行驶 ...
- C#判断字符串是否是有效的XML格式数据
说明 在try-catch语句块中,创建XmlDocument对象,并使用LoadXml方法加载xml字符串.如果没有异常,则说明xml字符串是有效的,返回true,反之为false. 代码实现 // ...