Vista下服务与桌面互交
本来在Vista之前服务与桌面互交是一件很容易的事情,自从Vista把服务都挪到Session 0 中运行去而且不可以跨Session之后,问题就复杂了许多,有时候我就在想这些问题是否真的不得不解决而且似乎对于安全并未带来多大提升的更改总是让人头疼,Google了一些文档,抄袭了不少代码我是如下实现的
这个函数抄自winehq网站,顺便不得不说一下winehq的代码是很值得参考的
1
BOOL WINAPI EnablePrivilege(LPSTR lpPrivilegeName, BOOL bEnable)
2 {
3 TOKEN_PRIVILEGES Privileges;
4 HANDLE hToken;
5 BOOL bResult;
6 if ( ! OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, & hToken))
7 return FALSE;
8
9 Privileges.PrivilegeCount = 1 ;
10 Privileges.Privileges[ 0 ].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0 ;
11
12 if ( ! LookupPrivilegeValue(NULL, lpPrivilegeName,
13 & Privileges.Privileges[ 0 ].Luid))
14 {
15 CloseHandle(hToken);
16 return FALSE;
17 }
18
19 bResult = AdjustTokenPrivileges(hToken, FALSE, & Privileges, 0 , NULL, NULL);
20
21 CloseHandle(hToken);
22
23 return bResult;
24 }
2 {
3 TOKEN_PRIVILEGES Privileges;
4 HANDLE hToken;
5 BOOL bResult;
6 if ( ! OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, & hToken))
7 return FALSE;
8
9 Privileges.PrivilegeCount = 1 ;
10 Privileges.Privileges[ 0 ].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0 ;
11
12 if ( ! LookupPrivilegeValue(NULL, lpPrivilegeName,
13 & Privileges.Privileges[ 0 ].Luid))
14 {
15 CloseHandle(hToken);
16 return FALSE;
17 }
18
19 bResult = AdjustTokenPrivileges(hToken, FALSE, & Privileges, 0 , NULL, NULL);
20
21 CloseHandle(hToken);
22
23 return bResult;
24 }
EnablePrivilege用来提升本进程权限,因为我们的核心思路是用CreateProcessAsUser创建进程到需要互交的Session,
//
保证拥有权限
EnablePrivilege(SE_TCB_NAME, TRUE);
EnablePrivilege(SE_CHANGE_NOTIFY_NAME, TRUE);
EnablePrivilege(SE_INCREASE_QUOTA_NAME, TRUE);
EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME, TRUE);
// 获取当前进程的灵牌
HANDLE hTokenThis = NULL;
HANDLE hTokenDup = NULL;
HANDLE hThisProcess = GetCurrentProcess();
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, & hTokenThis);
// 复制令牌
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, & hTokenDup);
// 枚举所有Session,本来还有一个WTSGetActiveConsoleSessionId,不过这个函数在win2000下只有Server版本安装WTS才可以
PWTS_SESSION_INFO pSInfo;
DWORD pCInfo = 0 ;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0 , 1 , & pSInfo, & pCInfo);
DWORD dwSessionId = 0 ;
for ( int i = 0 ;i < pCInfo;i ++ )
{
if (pSInfo[i].State == WTSActive)
{
dwSessionId = pSInfo[i].SessionId;
break ;
}
}
// DWORD dwSessionId = WTSGetActiveConsoleSessionId();
// 替换令牌,关键地方,我们并不需要以Session用户创建进程,只需要替换令牌就可以了
SetTokenInformation(hTokenDup, TokenSessionId, & dwSessionId, sizeof (DWORD));
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof (si);
si.lpDesktop = " WinSta0//Default " ;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
char pPath[MAX_PATH * 2 ];
GetModuleFileName(NULL,pPath, sizeof (pPath));
strcat(pPath, " -work " );
LPVOID pEnv;
CreateEnvironmentBlock( & pEnv,hTokenDup,FALSE);
if ( ! CreateProcessAsUser(hTokenDup,NULL,pPath,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL, & si, & pi))
{
//
// int p = GetLastError();
// p = 0;
}
WaitForSingleObject(pi.hProcess,INFINITE);
CloseHandle(hTokenDup);
CloseHandle(hTokenThis);
EnablePrivilege(SE_TCB_NAME, TRUE);
EnablePrivilege(SE_CHANGE_NOTIFY_NAME, TRUE);
EnablePrivilege(SE_INCREASE_QUOTA_NAME, TRUE);
EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME, TRUE);
// 获取当前进程的灵牌
HANDLE hTokenThis = NULL;
HANDLE hTokenDup = NULL;
HANDLE hThisProcess = GetCurrentProcess();
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, & hTokenThis);
// 复制令牌
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, & hTokenDup);
// 枚举所有Session,本来还有一个WTSGetActiveConsoleSessionId,不过这个函数在win2000下只有Server版本安装WTS才可以
PWTS_SESSION_INFO pSInfo;
DWORD pCInfo = 0 ;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0 , 1 , & pSInfo, & pCInfo);
DWORD dwSessionId = 0 ;
for ( int i = 0 ;i < pCInfo;i ++ )
{
if (pSInfo[i].State == WTSActive)
{
dwSessionId = pSInfo[i].SessionId;
break ;
}
}
// DWORD dwSessionId = WTSGetActiveConsoleSessionId();
// 替换令牌,关键地方,我们并不需要以Session用户创建进程,只需要替换令牌就可以了
SetTokenInformation(hTokenDup, TokenSessionId, & dwSessionId, sizeof (DWORD));
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof (si);
si.lpDesktop = " WinSta0//Default " ;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
char pPath[MAX_PATH * 2 ];
GetModuleFileName(NULL,pPath, sizeof (pPath));
strcat(pPath, " -work " );
LPVOID pEnv;
CreateEnvironmentBlock( & pEnv,hTokenDup,FALSE);
if ( ! CreateProcessAsUser(hTokenDup,NULL,pPath,NULL,NULL,FALSE,dwCreationFlag,pEnv,NULL, & si, & pi))
{
//
// int p = GetLastError();
// p = 0;
}
WaitForSingleObject(pi.hProcess,INFINITE);
CloseHandle(hTokenDup);
CloseHandle(hTokenThis);
这样我们的程序就可以和桌面互交了,这只是核心,其余牵涉多用户切换这些还需要另外考虑