从会话 0(服务)启动提升的用户进程 [重复]
Posted
技术标签:
【中文标题】从会话 0(服务)启动提升的用户进程 [重复]【英文标题】:Launch Elevated User Process from Session 0 (service) [duplicate] 【发布时间】:2013-12-02 09:03:54 【问题描述】:大家早安,
这个问题似乎已被问过几次,但我找不到它是否真的可能。我已在 here
发帖没有回复 - 让我们尝试在这里询问其他人。
我的目标是从当前用户上下文中的服务启动一个提升的进程(作为管理员)(仅当他们在本地管理员组中时)。
我可以毫无问题地获得当前用户令牌,但我无法获得该帐户的辅助/管理员令牌!
我已经阅读了很多论坛,但无法让它工作(开始认为它不可行)。
我目前的方法:
WTSGetActiveConsoleSessionId
- 获取活动会话 ID
WTSQueryUserToken
- 获取会话 ID 的用户令牌
检查令牌是否为管理员 - 不是。
OpenProcess
- 登录用户 explorer.exe 的进程句柄
OpenProcessToken
- 获取访问令牌的句柄
LookupPrivilegeValue
- SE_DEBUG 确认我们可以调整代币权限
DuplicateTokenEx
- 用户令牌
SetTokenInformation
AdjustTokenPrivileges
CreateEnvironmentBlock
- 运行新进程
CreateProcessAsUser
- 希望在提升的用户上下文中生成进程(不会发生 - 标准用户上下文)
请参阅下面的代码 - 很抱歉它的混乱,需要整理并关闭所有句柄。目前这只是实验代码。
public static bool CreateProcessInConsoleSession(String CommandLine, bool bElevate)
PROCESS_INFORMATION pi;
bool isadmin = IsUserAnAdmin();
bool bResult = false;
uint dwSessionId, winlogonPid = 0;
IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero,
hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
Debug.Print("CreateProcessInConsoleSession");
// Log the client on to the local computer.
dwSessionId = WTSGetActiveConsoleSessionId();
// Find the winlogon process
var procEntry = new PROCESSENTRY32();
uint hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
return false;
procEntry.dwSize = (uint)Marshal.SizeOf(procEntry); //sizeof(PROCESSENTRY32);
if (Process32First(hSnap, ref procEntry) == 0)
return false;
String strCmp = "explorer.exe";
do
if (strCmp.IndexOf(procEntry.szExeFile) == 0)
// We found a winlogon process...make sure it's running in the console session
uint winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, ref winlogonSessId) &&
winlogonSessId == dwSessionId)
winlogonPid = procEntry.th32ProcessID;
break;
while (Process32Next(hSnap, ref procEntry) != 0);
//Get the user token used by DuplicateTokenEx
WTSQueryUserToken(dwSessionId, ref hUserToken);
//Check if the user token is admin
isadmin = CheckIfAdminToken(hUserToken);
var si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";
var tp = new TOKEN_PRIVILEGES();
var luid = new LUID();
hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
TOKEN_INFORMATION_CLASS tokenInfo = new TOKEN_INFORMATION_CLASS();
uint TokenInfLength = 0 ;
if (
!OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY
| TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ref hPToken))
Debug.Print(String.Format("CreateProcessInConsoleSession OpenProcessToken error: 0",
Marshal.GetLastWin32Error()));
if (!LookupPrivilegeValue(IntPtr.Zero, SE_DEBUG_NAME, ref luid))
Debug.Print(String.Format("CreateProcessInConsoleSession LookupPrivilegeValue error: 0",
Marshal.GetLastWin32Error()));
bool Result;
#region TestToElevate
//http://www.microsoft-questions.com/microsoft/Platform-SDK-Security/35984508/how-to-run-a-process-with-elevated-privileges-run-as-administrat.aspx
// first call gets lenght of TokenInformation
Result = GetTokenInformation(hPToken, TOKEN_INFORMATION_CLASS.TokenUser, IntPtr.Zero , TokenInfLength , out TokenInfLength );
IntPtr TokenInformation = Marshal.AllocHGlobal((int)TokenInfLength);
Result = GetTokenInformation(hPToken, TOKEN_INFORMATION_CLASS.TokenElevation, TokenInformation, TokenInfLength, out TokenInfLength);
if (Result == false)
Result = GetTokenInformation(hPToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, TokenInformation, TokenInfLength, out TokenInfLength);
isadmin = CheckIfAdminToken(hPToken);
#endregion
var sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary,
ref hUserTokenDup))
Debug.Print(
String.Format(
"CreateProcessInConsoleSession DuplicateTokenEx error: 0 Token does not have the privilege.",
Marshal.GetLastWin32Error()));
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hPToken);
return false;
if (bElevate)
tp.PrivilegeCount = 1;
tp.Privileges = new int[3];
tp.Privileges[2] = SE_PRIVILEGE_ENABLED;
tp.Privileges[1] = luid.HighPart;
tp.Privileges[0] = luid.LowPart;
//Adjust Token privilege
if (!SetTokenInformation(hUserTokenDup, TOKEN_INFORMATION_CLASS.TokenSessionId, ref dwSessionId, (uint)IntPtr.Size))
Debug.Print(
String.Format(
"CreateProcessInConsoleSession SetTokenInformation error: 0 Token does not have the privilege.",
Marshal.GetLastWin32Error()));
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hPToken);
CloseHandle(hUserTokenDup);
return false;
if (!AdjustTokenPrivileges(hUserTokenDup, false, ref tp, Marshal.SizeOf(tp), /*(PTOKEN_PRIVILEGES)*/ IntPtr.Zero, IntPtr.Zero))
int nErr = Marshal.GetLastWin32Error();
if (nErr == ERROR_NOT_ALL_ASSIGNED)
Debug.Print(String.Format(
"CreateProcessInConsoleSession AdjustTokenPrivileges error: 0 Token does not have the privilege.", nErr));
else
Debug.Print(String.Format("CreateProcessInConsoleSession AdjustTokenPrivileges error: 0", nErr));
isadmin = CheckIfAdminToken(hUserTokenDup);
//Create Environment
uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
IntPtr pEnv = IntPtr.Zero;
if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
else
pEnv = IntPtr.Zero;
// Launch the process in the client's logon session.
bResult = CreateProcessAsUser(
hUserTokenDup, // client's access token
null, // file to execute
CommandLine, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
(int)dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
null, // name of current directory
ref si, // pointer to STARTUPINFO structure
out pi // receives information about new process
);
// End impersonation of client.
//GetLastError should be 0
int iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
//Close handles task
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hUserTokenDup);
CloseHandle(hPToken);
return (iResultOfCreateProcessAsUser == 0) ? true : false;
【问题讨论】:
不确定您的具体问题是什么,但您可以在此处找到工作代码的完整来源:sourceforge.net/p/jedi-apilib/code/HEAD/tree/jwscl/trunk/source/… 查看函数:JwCreateProcessAsAdminUser 【参考方案1】:你不能。服务被隔离并在与用户会话(会话 1、2、3 等)隔离的不同会话(会话 0)上运行。
【讨论】:
这是可能的。我在Delphi 中写了一些代码来做这件事,但也有很多 C# 示例:codeproject.com/articles/35773/…以上是关于从会话 0(服务)启动提升的用户进程 [重复]的主要内容,如果未能解决你的问题,请参考以下文章