服務器中以system權限啓動UI進程

轉自:http://www.dewen.org/q/2299

需要創建三個程序:1.Windows 服務程序 2.我們自己的應用程序 3.給服務發送信號的應用程序。

當然其中的 1和3 可以合併在一起,而且 2 我們可以做成多個應用程序。這樣只要是我們自己寫的都可以以SYSTEM的權限運行了,比管理員更實用。這裏需要注意的是第一次安裝服務的時候必須以管理員的權限運行。

好了,閒話少說,下面步入正題,我做了個簡單的Demo,是以服務的方式啓動系統自帶的管理記事本程序(windows 7下面的,用VS2008編輯)。

我們以函數CreateProcessAsUser 來開始講解,我們所要做的動作就是把這個函數的各個參數都填對 就OK,只需把其中的幾個關鍵參數填好,其他設置爲NULL 就OK ,

首先第一個參數HANDLE hToken ,Token 句柄,怎麼得到這個句柄,MSDN 給出了兩種辦法,一種通過調用 LogonUser函數 ,一種另外一種通過 調用DuplicateTokenEx 函數,在這裏我們選擇第二種方式創建一個模擬的Token,關鍵是這個模擬的Token那裏來,那我們就得追蹤DuplicateTokenEx裏面的各個參數,其中DuplicateTokenEx參數如下:

BOOL WINAPI DuplicateTokenEx(
__in HANDLE hExistingToken,
__in DWORD dwDesiredAccess,
__in_opt LPSECURITY_ATTRIBUTES lpTokenAttributes,
__in SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
__in TOKEN_TYPE TokenType,
__out PHANDLE phNewToken
);
這個函數的主要功能就是根據現有的Token 來創建一個新的Token,我們需要的就是這個新的Token,如何得到這個新的Token,看來我們還得往下追蹤哦,第二個參數是新建Token的權限,這個參數直接設置成MAXIMUM_ALLOWED就可以,第三個參數是 安全描述符的指針,這裏直接設置成NULL,分配成一個默認的安全描述符,第四個參數設置成SecurityIdentification 的OK,(安全描述符的級別) 第五個參數 Token類型 直接設置成TokenPrimary OK 因爲它就是用於CreateProcessAsUser的函數的。最後一個參數就是我們想要的參數了。我們主要就是得到他,要想得到這個參數 我們必須得到第一個參數。

第一個參數是一個已經存在的Token,數要想得到這個Token,必須找到以個進程,把這個進程的Token 拿過來爲我們所用,得到這個Token 要運行函數OpenPrcessToken通過這個函數得到Token的句柄,但是要得到這個Token的句柄,必須要通過函數OpenProcess得到進程的句柄,要得到進程的句柄 必須通過函數ProcessIdToSessionId得到進程的ID。因爲我們系統每次登入的時候都有一個winlogon.exe,我們就拿這個進程的ID 來得到CreateProcessAsUser函數的第一個參數。也就是把上面的一步步還原回去!

dwSessionId = WTSGetActiveConsoleSessionId(); //得到當前用戶的會話ID //////////////////////////////////////////
// Find the winlogon process
////////////////////////////////////////
PROCESSENTRY32 procEntry; //用來存放快照進程信息的一個結構體
//函數爲指定的進程、進程使用的堆[HEAP]、模塊[MODULE]、線程[THREAD])建立一個快照[snapshot]
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
{
return 1 ;
}
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &procEntry)) //獲得第一個進程的句柄.
{
return 1 ;
}
do
{
if (_wcsicmp(procEntry.szExeFile, _T("winlogon.exe")) == 0) //查找winlogon.exe
{
// We found a winlogon process...make sure it's running in the console session
DWORD winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId) && winlogonSessId == dwSessionId)//得到與進程ID對應的終端服務會話ID
{
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry)); //獲得下一個進程的句柄
////////////////////////////////////////////////////////////////////////
hProcess = OpenProcess(MAXIMUM_ALLOWED,FALSE,winlogonPid); //獲得進程句柄
if(!::OpenProcessToken(hProcess,TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
|TOKEN_READ|TOKEN_WRITE,&hPToken)) //獲得令牌句柄
{
int abcd = GetLastError();
printf("Process token open Error: %u\n",GetLastError());
}
DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);//創建模擬令牌
int dup = GetLastError();

通過上面的函數我們得到了這個DuplicateTokenEx函數的最後一個參數後,我們還不能直接用,根據MSDN 的說法要用SetTokenInformation來設置一下

BOOL WINAPI SetTokenInformation(
__in HANDLE TokenHandle,
__in TOKEN_INFORMATION_CLASS TokenInformationClass,
__in LPVOID TokenInformation,
__in DWORD TokenInformationLength
);
其中第一個參數就是我們得到Toke 的句柄,第二個參數會話ID ,也就是把會話ID 設置到備份令牌中,代碼如下:

SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)dwSessionId,sizeof(DWORD))

設置完成後 最好檢驗一下,當然不檢驗也沒有關係了,代碼如下:

if(!AdjustTokenPrivileges(hUserTokenDup,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,NULL)) //這個函數啓用或禁止指定訪問令牌的特權
{
int abc =GetLastError();
printf("Adjust Privilege value Error: %u\n",GetLastError());
}
if (GetLastError()== ERROR_NOT_ALL_ASSIGNED)
{
printf("Token does not have the provilege\n");
}

這樣的話CreateProcessAsUser第一個參數的工作算是正式完成,下面幾個參數就簡單了,

大家直接看代碼吧

bResult = CreateProcessAsUser(
hUserTokenDup, // 這個參數上面已經得到
_T("C:\Windows\System32\notepad.exe"), //執行文件的路徑
NULL, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);

最後大家別忘了把打開的句柄關閉。這樣看起來是不是就有點簡單了,其實也沒什麼,剩下的就是Winodws 服務的基本框架的一些東西,那些就簡單了。 以上都是自己根據MSDN理解得來的,如有什麼問題歡迎大家指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章