1. 程式人生 > >windows程式提權方法

windows程式提權方法

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);
        }
    }

可以看出AdjustTokenPrivileges提權是針對當前程序的控制代碼與對應系統許可權令牌的特權值的結構體LUID(也就是LARGE_INTEGER)的;

也就是說這種方式需要先使用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不相容的問題;所以如果第一種方式能滿足需求,儘量避免使用第二種方式,畢竟也多不了幾行程式碼;