Windows下应用程序如果需要做一些系统管理或进程管理之类的工作,经常需要将本进程提权(获取权限令牌);
而通常windows下提权方法有两种,主要的方法是:
1)win32API——AdjustTokenPrivileges;
2)ntdll.dll——RtlAdjustPrivilege;
前者是已公开的win32系统API,后者是非公开的导出函数(藏在ntdll.dll里);
两者的用法也有些差别;
先看第一种方式:
1)win32API——AdjustTokenPrivileges
//Win32Api:
void AdjustPrivilege()
{
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))
{
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
}
CloseHandle(hToken);
}
}
也就是说这种方式需要先使用LookupPrivilegeValue方法查询令牌(比如SE_DEBUG_NAME)对应的特权值;
2)ntdll.dll——RtlAdjustPrivilege
//ntdll.dll
const unsigned long SE_DEBUG_PRIVILEGE = 0x14;
typedef int (__stdcall *fRtlAdjustPrivilege)(ULONG, BOOLEAN, BOOLEAN, PBOOLEAN);
void NtAdjustPrivilege()
{
HMODULE hNtDll = LoadLibrary(_T("ntdll.dll"));
if (!hNtDll)
return;
fRtlAdjustPrivilege funcAdjustPrivilege =
(fRtlAdjustPrivilege)GetProcAddress(hNtDll, "RtlAdjustPrivilege");
if (funcAdjustPrivilege)
{
BOOLEAN oldStatus;
funcAdjustPrivilege(SE_DEBUG_PRIVILEGE, true, false, &oldStatus);
}
FreeLibrary(hNtDll);
}
这种导出RtlAdjustPrivilege的方式没有依赖其它方法,但是需要自己定义权限值SE_DEBUG_PRIVILEGE为0x14,显然这样写死的方式总是一种不太好的方式;
我们应该让windows自己定义这些值,我们通过变量名使用这些值,这样的设计更好;
当然,在特定的windows平台下,只要windows对ntdll.dll导出的函数改动不大,这样使用也可以。
总结一下,第一种方式使用的公开API,有官方文档,名正言顺,不用担心API的改动问题,但是需要用到不止一个方法(LookupPrivilegeValue与AdjustTokenPrivileges)组合使用,才能达到效果,稍显繁琐;第二种方式虽然不依赖其它方法就能达到效果,简洁强大,但是使用的非公开的导出方法RtlAdjustPrivilege,名不正言不顺,说不定以后windows在以后的版本中对ntdll.dll的修改可能会引起API不兼容的问题;所以如果第一种方式能满足需求,尽量避免使用第二种方式,毕竟也多不了几行代码;