//提升權限
bool EnableSpecificPrivilege(LPCTSTR lpPrivilegeName)
{
HANDLE hToken = NULL;
TOKEN_PRIVILEGES Token_Privilege;
BOOL bRet = TRUE;
do
{
if (0 == OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
OutputDebugView(_T("OpenProcessToken Error"));
bRet = FALSE;
break;
}
if (0 == LookupPrivilegeValue(NULL, lpPrivilegeName, &Token_Privilege.Privileges[0].Luid))
{
OutputDebugView(_T("LookupPrivilegeValue Error"));
bRet = FALSE;
break;
}
Token_Privilege.PrivilegeCount = 1;
Token_Privilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
//Token_Privilege.Privileges[0].Luid.LowPart=17;//SE_BACKUP_PRIVILEGE
//Token_Privilege.Privileges[0].Luid.HighPart=0;
if (0 == AdjustTokenPrivileges(hToken, FALSE, &Token_Privilege, sizeof(Token_Privilege), NULL,NULL))
{
OutputDebugView(_T("AdjustTokenPrivileges Error"));
bRet = FALSE;
break;
}
} while (false);
if (NULL != hToken)
{
CloseHandle(hToken);
}
return bRet;
}
lpPrivilegeName 取值:
#define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege")#define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege")#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege")#define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege")#define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege")#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege")#define SE_TCB_NAME TEXT("SeTcbPrivilege")#define SE_SECURITY_NAME TEXT("SeSecurityPrivilege")#define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege")#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege")#define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege")#define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege")#define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege")#define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege")#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege")#define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege")#define SE_BACKUP_NAME TEXT("SeBackupPrivilege")#define SE_RESTORE_NAME TEXT("SeRestorePrivilege")#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")#define SE_DEBUG_NAME TEXT("SeDebugPrivilege")#define SE_AUDIT_NAME TEXT("SeAuditPrivilege")#define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege")#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege")#define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege")#define SE_UNDOCK_NAME TEXT("SeUndockPrivilege")#define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege")#define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege")#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege")#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege")#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege")#define SE_TRUSTED_CREDMAN_ACCESS_NAME TEXT("SeTrustedCredManAccessPrivilege")#define SE_RELABEL_NAME TEXT("SeRelabelPrivilege")#define SE_INC_WORKING_SET_NAME TEXT("SeIncreaseWorkingSetPrivilege")#define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")#define SE_CREATE_SYMBOLIC_LINK_NAME TEXT("SeCreateSymbolicLinkPrivilege")
提權函數之 RtlAdjustPrivilege()
RtlAdjustPrivilege() 這玩意是在 NTDLL.DLL 裏的一個不爲人知的函數,MS沒有公開,原因就是這玩意實在是太NB了,以至於不需要任何其他函數的幫助,僅憑這一個函數就可以獲得進程ACL的任意權限!下面是函數定義:NTSTATUS RtlAdjustPrivilege( ULONG Privilege, BOOLEANEnable, BOOLEANCurrentThread, PBOOLEANEnabled)參數的含義:Privilege [In] Privilege index to change. // 所需要的權限名稱,可以到 MSDN 查找關於 Process Token & Privilege 內容可以查到Enable [In] If TRUE, then enable the privilege otherwise disable. // 如果爲True 就是打開相應權限,如果爲False 則是關閉相應權限CurrentThread [In] If TRUE, then enable in calling thread, otherwise process. // 如果爲True 則僅提升當前線程權限,否則提升整個進程的權限Enabled [Out] Whether privilege was previously enabled or disabled.// 輸出原來相應權限的狀態(打開 | 關閉), 注意:該參數賦予空指針會出錯,我測試過。eg:RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE,1,0,NULL);比用 AdjustTokenPrivileges 來提升進程權限方便很多,所以自己整理下備忘這個函數封裝在NtDll.dll中(在所有DLL加載之前加載),被微軟嚴格保密,就是說你在MSDN上查不到關於他的任何信息。
常用:常量 SE_BACKUP_PRIVILEGE = 0x11h常量 SE_RESTORE_PRIVILEGE = 0x12h常量 SE_SHUTDOWN_PRIVILEGE = 0x13h常量 SE_DEBUG_PRIVILEGE = 0x14h
全部:
//// These must be converted to LUIDs before use.//#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L)#define SE_CREATE_TOKEN_PRIVILEGE (2L)#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L)#define SE_LOCK_MEMORY_PRIVILEGE (4L)#define SE_INCREASE_QUOTA_PRIVILEGE (5L)#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L)#define SE_TCB_PRIVILEGE (7L)#define SE_SECURITY_PRIVILEGE (8L)#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L)#define SE_LOAD_DRIVER_PRIVILEGE (10L)#define SE_SYSTEM_PROFILE_PRIVILEGE (11L)#define SE_SYSTEMTIME_PRIVILEGE (12L)#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L)#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L)#define SE_CREATE_PAGEFILE_PRIVILEGE (15L)#define SE_CREATE_PERMANENT_PRIVILEGE (16L)#define SE_BACKUP_PRIVILEGE (17L)#define SE_RESTORE_PRIVILEGE (18L)#define SE_SHUTDOWN_PRIVILEGE (19L)#define SE_DEBUG_PRIVILEGE (20L)#define SE_AUDIT_PRIVILEGE (21L)#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L)#define SE_CHANGE_NOTIFY_PRIVILEGE (23L)#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L)#define SE_UNDOCK_PRIVILEGE (25L)#define SE_SYNC_AGENT_PRIVILEGE (26L)#define SE_ENABLE_DELEGATION_PRIVILEGE (27L)#define SE_MANAGE_VOLUME_PRIVILEGE (28L)#define SE_IMPERSONATE_PRIVILEGE (29L)#define SE_CREATE_GLOBAL_PRIVILEGE (30L)#define SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L)#define SE_RELABEL_PRIVILEGE (32L)#define SE_INC_WORKING_SET_PRIVILEGE (33L)#define SE_TIME_ZONE_PRIVILEGE (34L)#define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L)#define SE_MAX_WELL_KNOWN_PRIVILEGE (SE_CREATE_SYMBOLIC_LINK_PRIVILEGE)
關機代碼
#include <windows.h>const unsigned int SE_SHUTDOWN_PRIVILEGE = 0x13;int main(){HMODULE hDll = ::LoadLibrary("ntdll.dll");typedef int (* type_RtlAdjustPrivilege)(int, bool, bool, int*);typedef int (* type_ZwShutdownSystem)(int);type_RtlAdjustPrivilege RtlAdjustPrivilege = (type_RtlAdjustPrivilege)GetProcAddress(hDll, "RtlAdjustPrivilege");type_ZwShutdownSystem ZwShutdownSystem = (type_ZwShutdownSystem)GetProcAddress(hDll, "ZwShutdownSystem");int nEn = 0;int nResult = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, true, true, &nEn);if(nResult == 0x0c000007c){nResult = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, true, false, &nEn);}nResult = ZwShutdownSystem(2);FreeLibrary(hDll);return 0;}
==============================================
以不同用戶身份運行程序
一直想方便的處理CCProxy代理的帳號管理,所以夢想做一個比較好的管理工具。但一個最麻煩的問題就是帳號的更新,CCProxy有一個網頁管理功能,可以加帳號,但加的帳號就是不可以立即更新。中午上網的時候發現CCProxy有一功能就是支持命令行的操作,如:
CCProxy -reboot 重啓軟件
CCProxy -reset 更新配置
CCProxy -update 更新帳號
試着改了AccInfo.ini中帳號信息,在DOS中運行CCProxy -update的確更新了賬號,所以開始用PHP做管理工具,做到調用CCProxy -update時,用了PHP中的exec(),system()等函數一直沒有效果,後又通過調用批處理文件來調用命令行參數都不行。 處理得正沒耐心的時候,一氣之下狂刷新PHP網頁,電腦卡死,用進程管理器查看時發現打開了多個CCProxy進程,認真一看,除了一個CCProxy是用戶進程外其它CCProxy全是system進程。認真一想有可能是運行用戶身份不同所產生的結果。
Apache服務調用的外部程序以system身份運行,自己雙擊運行的程序以用戶身份運行。 如果CCProxy -update以用戶身份運行是不是就可以了呢?本人在網絡上找到了runas這個命令,的確可以指定以哪個用戶運行,但是每次都要輸密碼,沒有密碼的帳號就要加上密碼纔可以用,“/savecred”這個參數可以用,只要輸入一次密碼就可以了,但在PHP中發現要以system的身份輸入一次纔行,根本沒有機會輸入。打算用C程序來處理這個問題。可是發現用WinExec(),ShellExecute(),CreateProcess()都不好處理這個問題,好在發現了CreateProcessAsUser()這個函數。把網絡上的程序改了幾處,編譯後一試問題終於解決。
以下爲相關代碼:
// Update.cpp : 定義控制檯應用程序的入口點。
#include "stdafx.h" #include <windows.h> #include <tlhelp32.h> BOOL GetTokenByName(HANDLE &hToken,LPSTR lpName) { if(!lpName) return FALSE; HANDLE hProcessSnap = NULL; BOOL bRet = FALSE; PROCESSENTRY32 pe32 = {0}; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) return (FALSE); pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hProcessSnap, &pe32)) { do { if(!strcmp(_strupr(pe32.szExeFile),_strupr(lpName))) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,pe32.th32ProcessID); bRet = OpenProcessToken(hProcess,TOKEN_ALL_ACCESS,&hToken); CloseHandle (hProcessSnap); return (bRet); } } while (Process32Next(hProcessSnap, &pe32)); bRet = TRUE; } else bRet = FALSE; CloseHandle (hProcessSnap); return (bRet); } BOOL RunProcess(LPCSTR lpImage,LPSTR lpCommandLine) { if(!lpImage) return FALSE; HANDLE hToken; if(!GetTokenByName(hToken,"EXPLORER.EXE")) return FALSE; STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb= sizeof(STARTUPINFO); si.lpDesktop = TEXT("winsta0\\default"); BOOL bResult = CreateProcessAsUser(hToken,lpImage, lpCommandLine,NULL,NULL, FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi); CloseHandle(hToken); if(bResult) { OutputDebugString("CreateProcessAsUser ok!\r\n"); printf("CreateProcessAsUser ok!\r\n"); } else { OutputDebugString("CreateProcessAsUse* **lse!\r\n"); printf("CreateProcessAsUse* **lse!\r\n"); } return bResult; } int _tmain(int argc, _TCHAR* argv[]) { RunProcess("CCProxy.exe"," -update"); return 0; }
=====================================================================
用CreateProcessAsUser 創建最低權限進程
我從msdn上找到的資料,你看看
高 管理權限(進程可以將文件安裝到“Program Files”文件夾,並寫入敏感註冊表區域,如 HKEY_LOCAL_MACHINE。)
中 用戶權限(進程可在用戶的“文檔”文件夾創建和修改文件,並寫入用戶指定的註冊表區域,如 HKEY_CURRENT_USER。)
低 不受信任權限(進程只能寫入低完整性位置,例如 Temporary Internet Files\Low 文件夾或 HKEY_CURRENT_USER\Software\LowRegistry key)
啓動低完整性進程
1.重複中等完整性進程的處理。
2.使用 SetTokenInformation 將進程處理降低爲低完整性。
3.使用 CreateProcessAsUser 創建使用低完整性處理的新進程。
uses
windows;
function ConvertStringSidToSidA(StringSid: LPCTSTR; Sid:TSIDIdentifierAuthority): BOOL; stdcall; external 'Advapi32.dll' name 'ConvertStringSidToSidA';
const
SE_GROUP_INTEGRITY = 1;
#include "winnt.h"
BOOL b;
HANDLE hToken;
HANDLE hNewToken;
PWSTR szProcessName = "LowClient"; // 例如
PWSTR szIntegritySid = "S-1-16-4096"; // 低完整性 SID
PSID pIntegritySid = NULL;
TOKEN_MANDATORY_LABEL TIL = {0};
PROCESS_INFORMATION ProcInfo = {0};
STARTUPINFO StartupInfo = {0};
ULONG ExitCode = 0;
b = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED,
&hToken);
b = DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,
SecurityImpersonation, TokenPrimary, &hNewToken);
b = ConvertStringSidToSid(szIntegritySid, &pIntegritySid);
TIL.Label.Attributes = SE_GROUP_INTEGRITY;
TIL.Label.Sid = pIntegritySid;
// 設置進程完整性級別
b = SetTokenInformation(hNewToken, TokenIntegrityLevel, &TIL,
sizeof(TOKEN_MANDATORY_LABEL) + RtlLengthSid(pIntegritySid));
// 設置進程的 UI 權限級別
b = SetTokenInformation(hNewToken, TokenIntegrityLevelDesktop,
&TIL, sizeof(TOKEN_MANDATORY_LABEL) + RtlLengthSid(pIntegritySid));
// 以低完整性創建新進程
b = CreateProcessAsUser(hNewToken, NULL, szProcessName, NULL, NULL,
FALSE, 0, NULL, NULL, &StartupInfo, &ProcInfo);
實際中遇到的問題描:SKype在一個本地登錄帳戶裏只能運行一個實例,我需要運行多個實例,那麼就需要以其他帳戶的身份運行skype
有個方法:
調用runas.exe程序。。
只需要以runas /user:anotheruser "password" whatisgoingtorun
運行一個新進程就解決了
而windows默認的runas.exe是交互式輸入密碼, 看雪上有人將它改爲了參數式輸入密碼(即上面的形式)
詳見看雪論壇
以下是該帖子網址:
http://www.pediy.com/bbshtml/bbs8/pediy8-45.htm
============================================================
微軟從XP/2003開始爲我們提供了一套Windows
Terminal Service 的相關API,這些API都以WTS開頭(請安裝MSDN2005以查閱相關說明),要獲得活動Session也不止一個途徑,最簡單的就是直接使用
DWORD WTSGetActiveConsoleSessionId(void);
來獲得活動Session Id 。要在程序中使用這些API需要最新的Platform SDK(如果你正在使用Visual Studio 2005那麼它已經具備了相關頭文件和庫文件可以直接使用了),如果你在使用VC++ 6.0 你也沒有或者不打算安裝最新的SDK那麼你可以直接使用LoadLibrary() 裝載wtsapi32.dll然後使用GetProcAddress()獲得相關函數的地址以調用它們。我們獲得了活動SessionId後就可以使用
BOOL WTSQueryUserToken(
ULONG SessionId,
PHANDLE phToken
);
來獲取當前活動Session中的用戶令牌(Token),有了這個Token我們的就可以在活動Session中創建新進程了,
BOOL CreateProcessAsUser(
HANDLE hToken,
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
將我們獲得的Token作爲此API的第一個參數即可,你可以先嚐試一下運行一個notepad.exe看看,怎麼樣?你可以在控制檯桌面上看到新進程了。再查看一下進程列表,該進程的用戶名是當前控制檯登錄的用戶。可是這裏我們又遇到一個問題,我們需要收集當前交本機互式登錄用戶的一些信息,而有些操作需要很高的權限才能完成,而Vista下即使是Administraotrs用戶組成員默認也是以Users權限啓動進程的,所以我們創建的新進程只有Users權限,無法完成一些操作,當然我們可以使用Vista所提供的UI來詢問用戶以提升至管理員權限,可有些操作甚至是管理員Token也無法完成的,而且需要用戶確認實在在易用性上大打折扣,所以我決定在活動Session中以SYSTEM權限啓動我們的用戶交互程序。顯然
WTSQueryUserToken() 是不好用了。
之前,我們提到過進程所屬的Session是由進程Token中的TokenSessionId來決定的,那麼我們是不是可以複製服務進程的Token然後修改其中的TokenSessionId,從而在用戶桌面上創建一個具有SYSTEM權限的新進程呢?答案是肯定的。一下是實現這個操作的代碼,爲了縮小篇幅我刪除了異常處理代碼
HANDLEhTokenThis = NULL;
HANDLEhTokenDup = NULL;
HANDLEhThisProcess = GetCurrentProcess();
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORDdwSessionId = WTSGetActiveConsoleSessionId();
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD));
STARTUPINFOsi;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0//Default";
LPVOIDpEnv = NULL;
DWORDdwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE);
CreateProcessAsUser(
hTokenDup,
NULL,
(char *)"notepad",
NULL,
NULL,
FALSE,
dwCreationFlag,
pEnv,
NULL,
&si,
&pi);