进程权限 - 降低子进程权限(windows)

在 Windows 系统中,管理员权限和非管理员权限运行的程序之间不能使用 Windows 提供的通信机制进行通信。对于部分文件夹(ProgramData),管理员权限创建的文件是不能以非管理员权限修改和删除的。

然而,一个进程运行之后启动的子进程,会继承当前进程的 UAC 权限;于是有时我们会有降权运行的需要。本文将介绍 Windows 系统上降权运行的几种方法。

 

问题描述:

A进程(安装包进程)通过UAC弹窗提权为Administrators​​,A进程要启动B进程(界面进程),B进程却无法读取到网络驱动器。但是手动启动B进程,则可以读取到网络驱动器。(且前者中,B进程调用GetFileAttributes等函数查看网络驱动器文件路径,报错路径不正确,后者则没问题)

 

原因:

初步认为是权限不同导致的。使用accesschk工具查看A启动的B进程,与手动启动B进程的权限差别。发现第一种情况下,B进程是BUILTIN\Administrators用户组,表示本地管理员组,而第二种情况下,则是DELL用户组。由此可以进一步尝试探索是否是权限问题导致。(如下图)


解决方案:

在A进程启动B进程时,采取一定方式,降低B进程权限。

方法1:用 explorer.exe 代理运行程序(不能携带参数)

请特别注意,使用 explorer.exe 代理运行程序的时候,是不能带参数的,否则 explorer.exe 将不会启动你的程序。

因为绝大多数用户启动系统的时候,explorer.exe 进程都是处于运行状态,而如果启动一个新的 explorer.exe,都会自动激活当前正在运行的进程而不会启动新的。

于是我们可以委托默认以普通权限运行的 explorer.exe 来代理启动我们需要启动的子进程,这时启动的子进程便是与 explorer.exe 相同权限的。如果用户计算机上的 UAC 是打开的,那么 explorer.exe 默认就会以标准用户权限运行。

BOOL CLauncherApp::StartProcessWithExplorer(const std::wstring& appPath)
{std::wstring command = appPath;    WriteInfo(_T("command = %s"), command.c_str());// 使用 ShellExecute 启动 explorer.exeHINSTANCE result = ShellExecuteW(NULL,                  L"open",              L"explorer.exe",         command.c_str(),       // 进程完整路径NULL,                  SW_SHOWNORMAL          // 不显示窗口);if ((int)result <= 32){WriteError(_T("ShellExecuteW failed with error code: %d(HINSTANCE)"), (int)result);return FALSE;}return TRUE;
}

方法2:使用cmd的runas 命令来运行程序(需要输入密码)
使用 runas 命令来运行,可以指定一个权限级别,或者指定用户。这里指定为当前用户,即可获得当前用户权限。
但请注意:可以手动先试一下cmd中的runas命令,结果发现指定用户时是需要输入密码的(且不支持空密码),因此这里改为代码,无法使用,除非密码已知。

// 使用 runas 命令启动一个进程
bool RunAsUser(const std::wstring& appPath, const std::wstring& username)
{
    // 构造 runas 命令
    std::wstring command = L"runas /user:" + username + L" \"" + appPath + L"\"";    // runas /user:WIN-26554\DELL "要启动程序的完整路径"
                                                                                     // (WIN-26554\DELL是要指定用户的DOMAIN\USER名称)    // 使用 ShellExecuteW 启动 runas 命令
    HINSTANCE result = ShellExecuteW(
        NULL,                  // 父窗口句柄
        L"open",               // 操作类型
        L"cmd.exe",            // 命令提示符
        command.c_str(),       // runas 命令
        NULL,                  // 当前目录
        SW_HIDE                // 不显示窗口
    );    if ((int)result <= 32)
    {
        std::cerr << "ShellExecuteW failed with error code: " << (int)result << std::endl;
        return false;
    }    return true;
}

方法3;使用 CreateProcessAsUser 启动低权限进程(仅限父进程必须在 LocalSystem 帐户 的上下文中运行,并具有 SE_TCB_NAME 特权)
可以通过 WTSQueryUserToken 获取当前会话的用户令牌,然后使用 CreateProcessAsUser 启动一个低权限的子进程

void CreateProcessWithLowerPrivileges(LPCWSTR szAppPath)
{DWORD sessionId = WTSGetActiveConsoleSessionId();    // 获取当前活动窗口的会话IDHANDLE hToken, hNewToken;STARTUPINFO si = { sizeof(STARTUPINFO) };PROCESS_INFORMATION pi;if (!WTSQueryUserToken(sessionId, &hToken))    // 查询对应的Token{std::cerr << "WTSQueryUserToken failed: " << GetLastError() << std::endl;return;}// 复制Tokenif (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)){std::cerr << "DuplicateTokenEx failed: " << GetLastError() << std::endl;CloseHandle(hToken);return;}// 使用当前会话Token创建子进程if (!CreateProcessAsUser(hNewToken,NULL,(TCHAR*)szAppPath,NULL,NULL,FALSE,CREATE_UNICODE_ENVIRONMENT,NULL,NULL,&si,&pi)){std::cerr << "CreateProcessAsUser failed: " << GetLastError() << std::endl;CloseHandle(hNewToken);CloseHandle(hToken);return;}CloseHandle(pi.hProcess);CloseHandle(pi.hThread);CloseHandle(hNewToken);CloseHandle(hToken);
}

方法4:调用AdjustTokenPrivileges调整权限(不推荐,除非知道要调整什么权限)
可以在程序中调整访问令牌的权限,禁用一些高权限相关的权限,从而降低进程的权限。

BOOL DisablePrivilege(LPCWSTR lpPrivilegeName)
{HANDLE hToken;LUID luid;TOKEN_PRIVILEGES tp;if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)){std::cerr << "OpenProcessToken failed: " << GetLastError() << std::endl;return FALSE;}if (!LookupPrivilegeValue(NULL, lpPrivilegeName, &luid)){std::cerr << "LookupPrivilegeValue failed: " << GetLastError() << std::endl;CloseHandle(hToken);return FALSE;}tp.PrivilegeCount = 1;tp.Privileges[0].Luid = luid;tp.Privileges[0].Attributes = 0; // 禁用权限(在这里指定要禁用什么权限)if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)){std::cerr << "AdjustTokenPrivileges failed: " << GetLastError() << std::endl;CloseHandle(hToken);return FALSE;}CloseHandle(hToken);return TRUE;
}

还有就是可以通过修改访问令牌的完整性级别,再启动子进程,不过这样只能修改完整性级别,修改不了别的权限

BOOL CLauncherApp::CreateProcessWithMediumIL(LPCWSTR lpCommandLine)
{HANDLE hToken = NULL;HANDLE hDupToken = NULL;STARTUPINFO si = { sizeof(STARTUPINFO) };PROCESS_INFORMATION pi = { 0 };BOOL bResult = FALSE;// 获取当前进程的访问令牌if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) {WriteError(_T("OpenProcessToken failed with error = %d"), GetLastError());return FALSE;}// 复制访问令牌if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hDupToken)) {WriteError(_T("DuplicateTokenEx failed with error = %d"), GetLastError());CloseHandle(hToken);return FALSE;}// 设置复制的访问令牌的完整性级别为中等if (!SetTokenIntegrityLevel(hDupToken, SECURITY_MANDATORY_MEDIUM_RID)) {WriteError(_T("SetTokenIntegrityLevel failed"));CloseHandle(hToken);CloseHandle(hDupToken);return FALSE;}// 使用复制的访问令牌创建新的进程bResult = CreateProcessAsUser(hDupToken, NULL, (LPWSTR)lpCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);if (!bResult) {WriteError(_T("CreateProcessAsUser failed with error = %d"), GetLastError());} else {CloseHandle(pi.hProcess);CloseHandle(pi.hThread);}// 关闭句柄CloseHandle(hToken);CloseHandle(hDupToken);return bResult;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/881978.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java安全中的类加载

java安全中的类加载本文所涉及的内容仅供参考与教育目的,旨在普及网络安全相关知识。其内容不代表任何机构、组织或个人的权威建议,亦不构成具体的操作指南或法律依据。作者及发布平台对因使用本文信息直接或间接引发的任何风险、损失或法律纠纷不承担责任。对应的代码我发在…

cvat nuclio serverless pip install安装失败

cvat nuclio serverless 安装自动标注插件失败./serverless/deploy_cpu.sh serverless/onnx/WongKinYiu/yolov7主要pip安装失败的原因是部分依赖包不能够在大陆下载 只需要将function.yaml内的脚本添加依赖加速即可-i https://pypi.tuna.tsinghua.edu.cn/simple

Qt写Word文档-Windows

电脑没有安装微软的office,安装的是wps,用的是 QAxObject,所以只支持Windows系统一、pro文件添加 axcontainer 二、实现代码#include <QAxObject> #include <QDebug> // 创建Word应用程序对象 QAxObject* word = new QAxObject("kwps.Application");…

绝了,一招解决DeepSeek 提示“服务器繁忙,请稍后再试” 卡顿问题!(保姆级教程)

大家好,我是狂师。 现在 AI 圈里讨论最多的话题就是:"国产之光DeepSeek了"。 但用过的人也知道,是真的卡。动不动就提示:“服务器繁忙,请稍后再试”用官方App或网页版,估计10条回复中至少有8条会卡爆。对于重度使用的我来讲,经常会被官网的卡顿搞得差点吐血。…

揭秘 Sdcb Chats 如何解析 DeepSeek-R1 思维链

在上一篇文章中,我介绍了 Sdcb Chats 如何集成 DeepSeek-R1 模型,并利用其思维链(Chain of Thought, CoT)功能增强 AI 推理的透明度。DeepSeek-R1 强大的思维链能力给用户留下了深刻印象。本文将深入剖析 Sdcb Chats 实现这一功能的技术细节,重点介绍如何基于 OpenAI .NET…

全网最全的DeepSeek的使用指导资源,拿去用来操作其他的大模型也一样有用,你去找付费培训不如打赏我一毛

最近全网都在为火热的DeepSeek疯狂,不少商家培训都是出了付费培训,不少人都上当受骗。我就搜刮全网最全的使用,供大家使用,有使用文档,有提示词培训,有视频,应有尽有,现在我们就开始吧! 一、如何使用提示词 DeepSeek官网提供了很全面的提示词规则手册,包含了13个方向…

0帧起手将腾讯混元大模型集成到Spring AI的全过程解析

在前面,我们已经为大家铺垫了大量的知识点,并深入解析了Spring AI项目的相关内容。今天,我们将正式进入实战环节,从零开始,小雨将带领大家一步步完成将第三方大模型集成到Spring AI中的全过程。为了方便讲解,本次实战的示范将以腾讯的混元大模型为主,我们将逐步向你展示…

【5大误区】选择跨网文件安全交换系统的注意事项

网络隔离后,企业采用跨网文件安全交换系统可以显著提升工作效率、保障信息安全、满足合规要求、支持灵活工作模式以及增强市场竞争力。这些优势使得跨网文件交换系统成为现代企业不可或缺的工具。 一、选择跨网文件安全交换系统的常见误区 选择跨网文件安全交换系统时,企业和…

C# 深度学习:对抗生成网络(GAN)训练头像生成模型

通过生成对抗网络(GAN)训练和生成头像 目录通过生成对抗网络(GAN)训练和生成头像说明简介什么是 GAN什么是 DCGAN参数说明数据集处理权重初始化生成器判别器损失函数和优化器训练 说明 https://torch.whuanle.cn 电子书仓库:https://github.com/whuanle/cs_pytorch Maomi.Torc…

开源的 DeepSeek-R1「GitHub 热点速览」

春节假期回来,一睁眼全是王炸级的开源模型 DeepSeek-R1!GitHub 地址→github.com/deepseek-ai/DeepSeek-R1DeepSeek-R1 开源还不到一个月,Star 数就飙升至冲破天际的 70k。虽然目前仅开源了模型权重,但同时发布的技术论文详细地介绍了 DeepSeek-R1 所采用的训练技术,如模型…

C#/.NET/.NET Core优秀项目和框架2025年1月简报

前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的详细介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附…

Palo Alto Cortex XSOAR 6.13 for Linux - 安全编排、自动化和响应 (SOAR) 平台

Palo Alto Cortex XSOAR 6.13 for Linux - 安全编排、自动化和响应 (SOAR) 平台Palo Alto Cortex XSOAR 6.13 for Linux - 安全编排、自动化和响应 (SOAR) 平台 Security Orchestration, Automation and Response (SOAR) platform 请访问原文链接:https://sysin.org/blog/cort…