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
相关产品推荐
相关产品推荐

