目录

运行前

方法一:使用清单文件

运行时

方法一:运行时请求管理员权限

方法二:使用 PowerShell 提升权限

方法三:使用批处理文件

方法四:升级为调试权限

总结

1. 使用清单文件

2. 运行时请求管理员权限

3. 使用 PowerShell 提升权限

4. 使用批处理文件

5. 升级为调试权限

总结


运行前

方法一:使用清单文件

创建或修改清单文件

  • 在你的Visual Studio项目中,可以添加一个新的清单文件。右击项目 -> 添加 -> 新建项 -> 选择“应用程序清单文件”。
  • 在清单文件中,你需要指定程序需要的权限级别。为此,将 requestedExecutionLevel 节点的 level 属性设置为 requireAdministrator,如下所示:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

编译并运行程序

  • 编译你的程序后,当你尝试运行生成的可执行文件时,系统会自动提示你是否以管理员身份运行程序。

运行时

方法一:运行时请求管理员权限

        如果你不想通过修改清单文件来永久要求管理员权限,你可以在程序运行时根据需要请求权限。这通常涉及到在程序中启动一个新的进程实例,并请求以管理员身份运行。

        以下是一个示例代码,展示如何使用 ShellExecuteEx 函数来以管理员权限启动自身:

#include <windows.h>
#include <shellapi.h>

int main()
{
    // 检查当前是否已经是管理员权限
    BOOL isElevated = FALSE;
    HANDLE hToken = NULL;
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
        TOKEN_ELEVATION elevation;
        DWORD dwSize;
        if (GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) {
            isElevated = elevation.TokenIsElevated;
        }
    }
    if (hToken) {
        CloseHandle(hToken);
    }

    if (!isElevated) {
        // 如果不是管理员,以管理员权限重新启动自己
        SHELLEXECUTEINFO sei = { sizeof(sei) };
        sei.lpVerb = TEXT("runas");
        sei.lpFile = TEXT("你的程序路径"); // 比如: "C:\\Program Files\\MyApp\\MyApp.exe"
        sei.hwnd = NULL;
        sei.nShow = SW_NORMAL;

        if (!ShellExecuteEx(&sei)) {
            DWORD dwError = GetLastError();
            if (dwError == ERROR_CANCELLED)
                MessageBox(NULL, "The user refused to allow privileges elevation.", "Elevation Canceled", MB_OK);
        }
        return 0; // 退出原程序
    }

    // 在这里放置需要管理员权限才能执行的代码
    MessageBox(NULL, "Running as Administrator", "Elevated", MB_OK);
    return 0;
}

        在实际使用时,你需要确保正确处理各种可能的错误情况,并对 ShellExecuteEx 函数调用结果进行检查。以上代码提供了一个基础框架,可根据具体需求进行调整和完善。

方法二:使用 PowerShell 提升权限

        可以编程方式通过PowerShell脚本来请求提升权限。你可以从你的C++应用程序中启动一个PowerShell窗口,该窗口运行一个需要管理员权限的命令。示例如下:

#include <windows.h>

int main() {
    ShellExecute(NULL, "runas", "powershell.exe", "Start-Process PowerShell -Verb RunAs", NULL, SW_SHOWNORMAL);
    return 0;
}

        这行代码会启动一个新的PowerShell进程,该进程请求管理员权限。用户会看到UAC提示,请求确认。

方法三:使用批处理文件

        可以创建一个批处理文件(.bat),在其中加入需要管理员权限的命令,并从你的应用程序中调用这个批处理文件,同样使用“runas”动词。

        例如,你可以创建一个名为runasadmin.bat的文件,包含以下内容:

@echo off
:: 执行需要管理员权限的命令
echo Running tasks that require admin privileges...
pause

        然后在你的C++程序中调用这个批处理文件:

#include <windows.h>

int main() {
    ShellExecute(NULL, "runas", "cmd.exe", "/c path\\to\\runasadmin.bat", NULL, SW_HIDE);
    return 0;
}

 

        所有这些方法都会向用户显示UAC对话框,除非用户已经将UAC设置为永远不提示。这是Windows的一个安全特性,目的是防止未经授权的权限提升,因此开发者应当尊重这一设计,确保应用程序的透明性和安全性。

方法四:升级为调试权限

        代码展示了如何通过调整访问令牌的特权来提升当前进程的权限。它主要用于启用特定的系统权限,使得当前进程可以执行需要高级权限的操作。下面详细解析这段代码如何进行提权操作:

//进程提权
VOID
DebugPriv(
	VOID
)
{
	HANDLE Token;
	UCHAR Buf[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
	PTOKEN_PRIVILEGES Privs;

	if (OpenProcessToken(GetCurrentProcess(),
		MAXIMUM_ALLOWED,
		&Token)) {
		Privs = (PTOKEN_PRIVILEGES)Buf;

		Privs->PrivilegeCount = 1;
		Privs->Privileges[0].Luid.LowPart = 20L;
		Privs->Privileges[0].Luid.HighPart = 0;
		Privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

		AdjustTokenPrivileges(Token,
			FALSE,
			Privs,
			0,
			NULL,
			NULL);

		CloseHandle(Token);
	}
}
  • 该函数名为 DebugPriv,没有参数且返回类型为 VOID(即无返回值)。
  • 它的作用是启用当前进程的调试特权 SeDebugPrivilege

设置特权信息:

Privs = (PTOKEN_PRIVILEGES)Buf;

Privs->PrivilegeCount = 1;
Privs->Privileges[0].Luid.LowPart = 20L;
Privs->Privileges[0].Luid.HighPart = 0;
Privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  • Privs = (PTOKEN_PRIVILEGES)Buf:将 Buf 缓冲区转换为 PTOKEN_PRIVILEGES 类型的指针。
  • PrivilegeCount:特权数量设为1。
  • Luid:唯一标识符(LUID)标识该特权。
    • LowPart = 20L:20L代表调试特权 SeDebugPrivilege,允许进程查看和修改其他进程的内存。
    • HighPart = 0:没有高位值。
  • Attributes = SE_PRIVILEGE_ENABLED:启用此特权。

调整令牌的特权:

        AdjustTokenPrivileges(Token, FALSE, Privs, 0, NULL, NULL);

  • AdjustTokenPrivileges:修改访问令牌的特权。
    • Token:需要调整特权的令牌句柄。
    • FALSE:指示是否禁用令牌的所有特权;这里选择 FALSE 以只修改指定的特权。
    • Privs:指向需要启用的特权。
    • 最后两个参数为 0NULL,因为我们不需要接收原始的特权信息。

        这段代码通过获取当前进程的访问令牌,并使用 AdjustTokenPrivileges 函数来启用 SeDebugPrivilege 特权,实现了提升当前进程权限的功能。它有效地利用了Windows的令牌系统,使得当前进程可以获取更多的操作权限(如调试其他进程)。这种方法为开发者提供了一种安全且受控的权限提升机制,以便执行一些需要特殊权限的任务。需要注意的是,这种权限调整通常需要管理员权限,否则将导致失败。由于特权的使用可能影响系统的安全和稳定性,因此在启用特权时务必谨慎。

总结

1. 使用清单文件

关联和区别:通过修改应用程序的清单文件,可以使程序在启动时默认要求管理员权限。与运行时动态获取权限的方法不同,清单文件的方法是固定和全局的。 优点

  • 简单直接,不需要额外代码。
  • 一次配置后,程序始终要求管理员权限。 缺点
  • 如果不需要所有操作都以管理员身份执行,此方法可能过于强制。 使用场景:适合于所有操作都需要管理员权限的程序,例如系统工具或安装程序。

2. 运行时请求管理员权限

关联和区别:通过代码逻辑检查当前权限并重新启动自己,类似于清单文件方式,但运行时方法可以灵活控制请求权限的时机。 优点

  • 动态请求权限,按需提权,灵活性更高。 缺点
  • 需要编写额外的代码逻辑处理重启过程,用户体验可能受到影响。 使用场景:适合某些特定操作需要管理员权限的工具,例如当用户执行某项特定操作时重新启动以管理员身份运行。

3. 使用 PowerShell 提升权限

关联和区别:调用 PowerShell 脚本来间接启动具有管理员权限的进程。 优点

  • 简单直接,只需一行代码调用 PowerShell。
  • 可以执行更复杂的 PowerShell 脚本。 缺点
  • 依赖 PowerShell 环境,增加系统依赖。
  • 需要确保 PowerShell 本身具有足够的权限。 使用场景:适合在多种操作系统版本上统一实现管理员权限请求,或者需要执行复杂的 PowerShell 命令。

4. 使用批处理文件

关联和区别:通过批处理文件中内置的 runas 命令来实现提权。 优点

  • 适合自动化或批处理操作,批处理文件可共享。
  • 简化部分代码逻辑。 缺点
  • 执行方式相对固定,调试与维护复杂。 使用场景:适合自动化部署或大批量执行某些需要管理员权限的操作。

5. 升级为调试权限

关联和区别:直接修改访问令牌的权限来获取更高的权限,通常用于调试权限(SeDebugPrivilege)。 优点

  • 可精细化控制权限,仅启用所需的特定权限。
  • 无需启动新的进程,执行效率高。 缺点
  • 需要管理员权限来调整特权。
  • 对系统稳定性和安全性有潜在影响。 使用场景:适合开发者或系统管理员需要调试其他进程的特定场景。

总结

        这些方法从全局到局部、从简单到复杂提供了不同的获取管理员权限的方案。选择具体的方案需要综合考虑程序的实际需求、安全性、用户体验以及系统依赖等因素,确保能够有效且安全地完成提权操作。

05-12 07:56