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 ...
随机推荐
- cocos2d-Js 各类碰撞检测
这里总结一下点.圆.矩形之间的简单碰撞检测算法(矩形不包括旋转状态) 点和圆的碰撞检测: 1.计算点和圆心的距离 2.判断点与圆心的距离是否小于圆的半径 isCollision: function(p ...
- logback日志颜色设置
resources下创建logback-spring.xml配置文件,名字必须要叫这个!!! <?xml version="1.0" encoding="UTF-8 ...
- nginx下的proxy_pass使用
之前的文章说到了,return,rewrite的使用,以及它们的使用场景,今天再来说一种代理的使用,proxy_pass,它属于nginx下的ngx_http_proxy_module模块,没有显示的 ...
- 手写滑动同步滚动进度条jq插件
因需要一种滑动显示内容,并且带可拖动的进度条,即下面这种效果 找了很多插件,总有地方不能满足需求.于是决定自己手写,下面为完整源码: swiper.js 1 $.swiperCalculator = ...
- [VMware]ESXI下硬盘的两种直通方式
文章来自:https://rmbz.net/archives/vmware-esxi-passthrough 最近再搞ESXI,把原来的"黑群晖"改成ESXI:因为群晖里有数据,为 ...
- 《An End-to-end Model for Entity-level Relation Extraction using Multi-instance Learning》阅读笔记
代码 原文地址 预备知识: 1.什么是MIL? 多示例学习(MIL)是一种机器学习的方法,它的特点是每个训练数据不是一个单独的实例,而是一个包含多个实例的集合(称为包).每个包有一个标签,但是 ...
- Supershell防溯源反制配置
简介 项目地址:https://github.com/tdragon6/Supershell Supershell是一个集成了reverse_ssh服务的WEB管理平台,使用docker一键部署(快速 ...
- Linux集群存储配置
RH436_EX集群 介绍Linux环境下集群架构,Linux开源集群软件的安装及配置使用,软件与软件之间的组合.实现高可用集群,负载均衡集群;负载均衡.高可用集群与存储集群间的多集群混合架构使用. ...
- Ubuntu 终端如何分割多个窗口
sudo apt-get install terminator 查看 ~/.config(隐藏文件夹 ctrl + h 即可看见) 下是否有 terminator 文件夹 如果没有手动创建一个 然后在 ...
- puppeteer的简单使用
引言 对于编写应用程序,尤其是要部署上线投入生产使用的应用,QA是其中重要的一环,在过去的工作经历中,我参与的项目开发,大多是由测试同学主要来把控质量的,我很少编写前端方面的测试代码,对于测试工具的使 ...