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不兼容的问题;所以如果第一种方式能满足需求,尽量避免使用第二种方式,毕竟也多不了几行代码;