微软从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);