You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RtlAdjustPrivilege调整权限失败 代码是否存在问题?

故障描述

Windows应用开发过程中调用RtlAdjustPrivilege函数无法成功配置程序所需权限,已对照SystemInformer开源项目ntrtl.h头文件中的公开定义核对,程序内函数声明与该文件定义完全一致,无法定位问题原因,原始实现代码如下:

#include <Windows.h>

#define SE_SHUTDOWN_PRIVILEGE 19
#define SE_DEBUG_PRIVILEGE 20
#define SE_SYSTEMTIME_PRIVILEGE 12

typedef NTSTATUS(NTAPI* pdef_RtlAdjustPrivilege)(IN ULONG Privilege, IN BOOLEAN Enable, IN BOOLEAN CurrentThread, OUT PBOOLEAN WasEnabled);
pdef_RtlAdjustPrivilege RtlAdjustPrivilege;

BOOL EnablePrivilege(ULONG priv)
{
    HINSTANCE ntdll = LoadLibraryW(L"ntdll.dll");
    if (ntdll != NULL) {
        RtlAdjustPrivilege = (pdef_RtlAdjustPrivilege)GetProcAddress(ntdll, "RtlAdjustPrivilege");
        if (!RtlAdjustPrivilege) {
            FreeLibrary(ntdll);
            return FALSE;
        }
        RtlAdjustPrivilege(priv, TRUE, FALSE, NULL);
    }
    else {
        return FALSE;
    }
    FreeLibrary(ntdll);
    return TRUE;
}

int main()
{
    EnablePrivilege(SE_SHUTDOWN_PRIVILEGE);
    //do something
}
故障原因

代码存在5处直接导致权限配置失败的逻辑错误:

  • 输出参数传无效空指针:RtlAdjustPrivilege最后一个参数是用于返回权限原启用状态的输出参数,必须传入指向有效BOOLEAN类型变量的指针,传入NULL会触发内存访问违规,函数直接执行失败。
  • 未校验函数返回值:RtlAdjustPrivilege返回NTSTATUS类型状态码标识调用结果,代码完全不判断返回值,直接默认调用成功,实际即使调用失败也会返回TRUE误导上层逻辑。
  • 权限常量硬编码风险:手动定义的权限索引值未和系统WDK头文件中的标准定义做对齐校验,不同Windows版本的部分权限索引存在差异,硬编码值可能和当前系统不匹配。
  • 逻辑认知错误:RtlAdjustPrivilege仅能启用当前进程/线程令牌中已经存在的权限,无法为进程凭空添加令牌中未授予的权限;如果程序不是以对应令牌上下文启动(比如需要管理员权限的场景下以普通用户运行),即使函数调用参数正确也无法开启目标权限。
  • 冗余的ntdll加载/释放逻辑:ntdll是Windows进程启动时就会默认加载的核心系统库,不需要重复调用LoadLibraryW/FreeLibrary,重复加载释放反而可能在复杂场景下出现地址失效问题。
修复后代码
#include <Windows.h>
#include <ntstatus.h>

// 优先使用系统头文件定义的权限常量,无WDK环境时再使用兼容定义
#ifndef SE_SHUTDOWN_PRIVILEGE
#define SE_SHUTDOWN_PRIVILEGE 19
#endif
#ifndef SE_DEBUG_PRIVILEGE
#define SE_DEBUG_PRIVILEGE 20
#endif
#ifndef SE_SYSTEMTIME_PRIVILEGE
#define SE_SYSTEMTIME_PRIVILEGE 12
#endif

typedef NTSTATUS(NTAPI* pfnRtlAdjustPrivilege)(
    ULONG Privilege,
    BOOLEAN Enable,
    BOOLEAN CurrentThread,
    PBOOLEAN WasEnabled
);

BOOL EnablePrivilege(ULONG privId)
{
    static pfnRtlAdjustPrivilege RtlAdjustPrivilege = NULL;
    BOOLEAN prevState = FALSE;
    NTSTATUS status;

    // 仅第一次调用时获取函数地址,后续直接复用
    if (!RtlAdjustPrivilege)
    {
        RtlAdjustPrivilege = (pfnRtlAdjustPrivilege)GetProcAddress(
            GetModuleHandleW(L"ntdll.dll"),
            "RtlAdjustPrivilege"
        );
        if (!RtlAdjustPrivilege)
        {
            return FALSE;
        }
    }

    status = RtlAdjustPrivilege(privId, TRUE, FALSE, &prevState);
    // 校验返回状态,只有返回STATUS_SUCCESS才代表权限启用成功
    return NT_SUCCESS(status);
}

int main()
{
    if (!EnablePrivilege(SE_SHUTDOWN_PRIVILEGE))
    {
        // 可在此处打印NTSTATUS对应的错误信息排查问题
        return 1;
    }
    // 执行业务逻辑
    return 0;
}
补充说明

涉及系统级高权限操作(比如开启SeDebugPrivilege、SeLoadDriverPrivilege)时,必须确保程序以管理员身份运行,且程序 manifest 中配置了requireAdministrator的 requestedExecutionLevel,否则进程令牌默认不持有对应权限,无法通过RtlAdjustPrivilege开启。

内容的提问来源于stack exchange,提问作者LC0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 08:00:36