我們有一個服務應用程序,它在控制檯會話中產生一個進程(WTSGetActiveConsoleSessionId),以允許桌面控制風格訪問機器。這在大多數情況下都能很好地工作,但是在CreateProcessAsUser的結果方面,有一些虛擬機似乎成功地創建了進程,但是該進程沒有被創建。CreateProcessAsUser成功,但沒有創建進程
該服務在LocalSystem帳戶下運行。正在啓動的進程尚未運行。沒有病毒保護程序正在運行。我們只在Windows Server 2008 R2上看到過這種行爲(但這並不是說它是獨佔的)。
我們使用的代碼如下:
function StartProcessInSession(strProcess: String; bLocalSystem: Boolean = True; iSessionID: Integer = -1): Boolean;
procedure SPISLog(strLog: String; bError: Boolean = False);
begin
Log(strLog);
if bError then Abort;
end;
var pi: PROCESS_INFORMATION;
si: STARTUPINFO;
winlogonPid, dwSessionId: DWord;
hUserToken, hUserTokenDup, hPToken, hProcess: THANDLE;
dwCreationFlags: DWORD;
tp: TOKEN_PRIVILEGES;
lpenv: Pointer;
bError: Boolean;
strClone: String;
begin
if GetProcessID(strProcess, iSessionID) > 0 then
begin
Result := True;
Exit;
end;
Result := False;
bError := False;
if not InitProcLibs then Exit;
if bLocalSystem then strClone := 'winlogon.exe' else strClone := 'explorer.exe';
winlogonPid := GetProcessID(strClone, iSessionID);
try
dwSessionId := WTSGetActiveConsoleSessionId();
dwCreationFlags := NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE;
ZeroMemory(@si, sizeof(STARTUPINFO));
si.cb := sizeof(STARTUPINFO);
si.lpDesktop := PChar('Winsta0\Default');
ZeroMemory(@pi, sizeof(pi));
hProcess := OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid);
if (not OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY or TOKEN_DUPLICATE or
TOKEN_ASSIGN_PRIMARY or TOKEN_ADJUST_SESSIONID or TOKEN_READ or TOKEN_WRITE, hPToken)) then
bError := True;
if bError then SPISLog('SPIS - OpenProcessToken failed (' + SysErrorMessage(GetLastError) + ').', True);
if (not LookupPrivilegeValue(nil, SE_DEBUG_NAME, tp.Privileges[0].Luid)) then bError := True;
if bError then SPISLog('SPIS - LookupPrivilegeValue failed (' + SysErrorMessage(GetLastError) + ').', True);
tp.PrivilegeCount := 1;
tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, nil, SecurityIdentification, TokenPrimary, hUserTokenDup);
SetTokenInformation(hUserTokenDup, TokenSessionId, Pointer(dwSessionId), SizeOf(DWORD));
if (not AdjustTokenPrivileges(hUserTokenDup, FALSE, @tp, SizeOf(TOKEN_PRIVILEGES), nil, nil)) then bError := True;
if bError then SPISLog('SPIS - AdjustTokenPrivileges failed (' + SysErrorMessage(GetLastError) + ').', True);
if (GetLastError() = ERROR_NOT_ALL_ASSIGNED) then bError := True;
if bError then SPISLog('SPIS - AdjustTokenPrivileges: ERROR_NOT_ALL_ASSIGNED (' + SysErrorMessage(GetLastError) + ').', True);
lpEnv := nil;
if (CreateEnvironmentBlock(lpEnv, hUserTokenDup, TRUE)) then
dwCreationFlags := dwCreationFlags or CREATE_UNICODE_ENVIRONMENT
else
lpEnv := nil;
if not Assigned(lpEnv) then SPISLog('SPIS - CreateEnvironmentBlock failed (' + SysErrorMessage(GetLastError) + ').', True);
try
UniqueString(strProcess);
if not CreateProcessAsUser(hUserTokenDup, nil, PChar(strProcess), nil, nil, FALSE,
dwCreationFlags, lpEnv, PChar(ExtractFilePath(strProcess)), si, pi) then bError := True;
if bError then
SPISLog('SPIS - CreateProcessAsUser failed (' + SysErrorMessage(GetLastError) + ').', True)
else
SPISLog('Started process in ' + IntToStr(dwSessionId) + ' using token from ' + IntToStr(winlogonPid) + '.');
try
try CloseHandle(hProcess); except {} end;
try CloseHandle(hUserToken); except {} end;
try CloseHandle(hUserTokenDup); except {} end;
try CloseHandle(hPToken); except {} end;
except
{}
end;
finally
DestroyEnvironmentBlock(lpEnv);
end;
except
on E: Exception do
begin
bError := True;
if not (E is EAbort) then
SPISLog('SPIS - ' + E.Message + ' (' + SysErrorMessage(GetLastError) + ').', True);
end;
end;
Result := not bError;
end;
function GetProcessID(strProcess: String; iSessionID: Integer = -1): DWORD;
var dwSessionId, winlogonSessId: DWord;
hsnap: THandle;
procEntry: TProcessEntry32;
myPID: Cardinal;
begin
Result := 0;
if not InitProcLibs then Exit;
{ check running processes and return ID of process in current session... }
if iSessionID = -1 then
dwSessionId := WTSGetActiveConsoleSessionId
else
dwSessionId := iSessionID;
hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap = INVALID_HANDLE_VALUE) then Exit;
strProcess := UpperCase(ExtractFileName(strProcess));
myPID:= GetCurrentProcessId;
procEntry.dwSize := sizeof(TProcessEntry32);
if (not Process32First(hSnap, procEntry)) then Exit;
repeat
if (procEntry.th32ProcessID <> myPID) and ((UpperCase(procEntry.szExeFile) = strProcess) or
(UpperCase(ExtractFileName(procEntry.szExeFile)) = strProcess)) then
begin
winlogonSessId := 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, winlogonSessId) and (winlogonSessId = dwSessionId)) then
begin
Result := procEntry.th32ProcessID;
break;
end;
end;
until (not Process32Next(hSnap, procEntry));
end;
有誰知道爲什麼它會失敗,或是否有工作了什麼與此調用API中發生的一種方式?
使用WTSEnumerateSessions並搜索第一個活動會話而不是WTSGetActiveConsoleSession。它不適用於RDP連接。 – FredS
「通過這個調用瞭解API中發生了什麼的一種方法?」 - 需要在暫停狀態下創建進程,將調試器附加到新創建的進程,並在此恢復之後 – RbMm
此代碼接近不可讀。錯誤處理是不可避免的。 –