- //提升权限
- 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()等函数一直没有效果,后又通过调用批处理文件来调用命令行参数都不行。
Apache服务调用的外部程序以system身份运行,自己双击运行的程序以用户身份运行。
// 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);