windows下一个用户登录进去,会产生一个会话,术语为session,可以用工具Process Explorer,查看进程的session id,如下所示,我们查看chrome进程的session id。
可以看出Session id是4.任务管理器中查看chrome的用户名是当前登录的用户名。
由于用户登录产生会话,故一直以为用户下所有进程必然是同一个session id,直到解决一个服务程序需要创建具有管理员权限的界面程序时,发现一个神奇的现象,任务管理器中的winlogon.exe进程的用户是SYSTEM,SYSTEM是服务程序用户,其下的程序的session一般是0,但是这个winlogon.exe是个例外,我们看下,如下图所示:
4是界面程序的session id,并且其权限信息显示其有管理员权限,所以利用这个winlogon.exe进程的token可以创建具有管理员权限的界面程序。
现在问题来了,SYSTEM用户(对应session为0)下是如何创建session为4的winlogon,经查,SetTokenInformation可以改变token所属的session,从而改变进程所属的session,下面是自己写的一个例子:
// TsService.cpp : Defines the entry point for the console application.
//
#include
#include
#include
#pragma comment(lib, "userenv.lib")
#define SLEEP_TIME 50000 //间隔时间
bool brun = false;
SERVICE_STATUS servicestatus;
SERVICE_STATUS_HANDLE hstatus;
void WINAPI ServiceMain(int argc, char** argv);
void WINAPI CtrlHandler(DWORD request);
int InitService();
void CreateNewProcess()
{
DWORD dwErr = 0;
HANDLE hTokenThis = NULL;
HANDLE hTokenDup = NULL;
HANDLE hThisProcess = GetCurrentProcess();
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
BOOL bRet = SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD));
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE);
bRet = CreateProcessAsUserA(
hTokenDup,
NULL,
"E:\\learn\\c++\\mfc\\DllKiller\\Release\\DllKiller.exe",
NULL,
NULL,
FALSE,
dwCreationFlag,
pEnv,
NULL,
&si,
&pi);
dwErr = ::GetLastError();
}
void WINAPI ServiceMain(int argc, char** argv)
{
servicestatus.dwServiceType = SERVICE_WIN32;
servicestatus.dwCurrentState = SERVICE_START_PENDING;
servicestatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP;//在本例中只接受系统关机和停止服务两种控制命令
servicestatus.dwWin32ExitCode = 0;
servicestatus.dwServiceSpecificExitCode = 0;
servicestatus.dwCheckPoint = 0;
servicestatus.dwWaitHint = 0;
hstatus = ::RegisterServiceCtrlHandler("testservice", CtrlHandler);
if (hstatus == 0)
{
return;
}
//向SCM 报告运行状态
servicestatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hstatus, &servicestatus);
//在此处添加你自己希望服务做的工作,在这里我做的工作是获得当前可用的物理和虚拟内存信息
brun = true;
MEMORYSTATUS memstatus;
char str[100];
memset(str, '\0', 100);
while (brun)
{
CreateNewProcess();
Sleep(SLEEP_TIME);
}
}
void WINAPI CtrlHandler(DWORD request)
{
switch (request)
{
case SERVICE_CONTROL_STOP:
brun = false;
servicestatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_SHUTDOWN:
brun = false;
servicestatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
SetServiceStatus(hstatus, &servicestatus);
}
void main()
{
SERVICE_TABLE_ENTRY entrytable[2];
entrytable[0].lpServiceName = "testservice";
entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
entrytable[1].lpServiceName = NULL;
entrytable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(entrytable);
}
工程名叫TsService.exe,用下面命令注册成服务:
sc create TsService binpath= E:\learn\c++\win32\Service\TsService\Release\TsService.exe
服务运行起来后,会创建进程DllKiller.exe,这个exe是自己写的一个程序,用户可以换成其他的exe文件。
结果是创建出的进程所属的用户名是SYSTEM,但是其session id却是4.