使用 Delphi 10.2.3,我正在實作一個服務,除其他外,需要在資料庫恢復之前關閉用戶應用程式,然后在之后重新啟動應用程式。關閉應用程式沒有問題,但出于明顯的 session-0 原因,啟動應用程式備份是有問題的。我在網上找到了以下代碼來做到這一點,它作業正常,只有一個例外。
function CreateEnvironmentBlock(var lpEnvironment: Pointer; hToken: THandle; bInherit: BOOL): BOOL; stdcall; external 'userenv.dll';
function DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall; external 'userenv.dll';
function SvcLaunchAppInCurrUserSession(const AppToLaunch: String;
const Params: String = '';
WaitForIt: Boolean = False;
HideIt: Boolean = False): Cardinal;
var
PI: PROCESS_INFORMATION;
SI: STARTUPINFO;
bResult: Boolean;
dwSessionId: DWORD;
hUserTokenDup, hPToken: THANDLE;
dwCreationFlags: DWORD;
CommandLine: string;
Directory: string;
tp: TOKEN_PRIVILEGES;
pEnv: Pointer;
begin
Result := S_OK;
try
try
pEnv := nil;
dwCreationFlags := NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE;
CommandLine := Trim('"' Trim(AppToLaunch) '" ' Params);
Directory := ExtractFileDir(AppToLaunch);
// get the current active session and the token
dwSessionId := WtsGetActiveConsoleSessionID;
// initialize startup info
ZeroMemory(@SI, SizeOf(SI));
SI.cb := SizeOf(STARTUPINFO);
SI.lpDesktop := nil; //PChar('winsta0\Default');
SI.dwFlags := STARTF_USESHOWWINDOW;
if HideIt then
SI.wShowWindow := SW_HIDE
else
SI.wShowWindow := SW_SHOWNORMAL;
if OpenProcessToken(GetCurrentProcess, 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 begin
tp.PrivilegeCount := 1;
tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
if LookupPrivilegeValue(nil, 'SeDebugPrivilege', tp.Privileges[0].Luid) then begin
DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, nil, SecurityIdentification, TokenPrimary, hUserTokenDup);
SetTokenInformation(hUserTokenDup, TokenSessionId, @dwSessionId, SizeOf(DWORD));
if CreateEnvironmentBlock(pEnv, hUserTokenDup, True) then
dwCreationFlags := dwCreationFlags or CREATE_UNICODE_ENVIRONMENT
else
pEnv := nil;
// Launch the process in the client's logon session.
bResult := CreateProcessAsUser(hUserTokenDup, // client's access token
nil, // file to execute
PChar(CommandLine), // command line
nil, // pointer to process SECURITY_ATTRIBUTES
nil, // pointer to thread SECURITY_ATTRIBUTES
False, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
PChar(Directory), // name of current directory
si, // pointer to STARTUPINFO structure
pi); // receives information about new process
if not bResult then begin
Result := GetLastError;
Exit;
end;
end
else begin
Result := GetLastError;
Exit;
end;
end
else begin
Result := GetLastError;
Exit;
end;
if WaitForIt then begin
WaitForSingleObject(PI.hProcess, INFINITE);
GetExitCodeProcess(PI.hProcess, Result);
end;
finally
// close all handles
if Assigned(pEnv) then
DestroyEnvironmentBlock(pEnv);
CloseHandle(hUserTokenDup);
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
CloseHandle(hPToken);
end;
except
on E:Exception do begin
DbgLogFmt('SvcLaunchApp %s: %s', [E.ClassName, E.Message]);
raise;
end;
end;
end;
這樣做的問題是它使用服務的權限 (SYSTEM) 啟動應用程式,這是一個巨大的安全漏洞。我希望它以當前用戶的權限(用戶或管理員)啟動應用程式,而不是系統。我對 Windows 安全性的來龍去脈了如指掌,但我確信有一種方法可以做到這一點 - 我只是不知道需要調整上述哪些部分才能使用正確的權限。或者,如果有更好的方法來做到這一點,我愿意接受。建議?
謝謝。
uj5u.com熱心網友回復:
您正在使用您的服務作為 (SYSTEM) 運行的用戶令牌。使用WTSQueryUserToken()得到令牌的目標會話,而不是用戶。
uj5u.com熱心網友回復:
您必須首先模擬用戶,然后運行應用程式。 我寫了一篇使用模擬的博客文章,可能會對您有所幫助。為此,您需要用戶憑據。
模擬將使您的程式(此處為服務)充當另一個用戶。該博客文章中使用該功能從當前用戶隱藏資料。在您的情況下,您的服務將首先模擬為目標用戶,然后啟動應用程式,該應用程式將在模擬用戶的背景關系中運行。
我在 github 上發布了源代碼。此代碼是StackOverflow 討論的結果。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/400669.html
標籤:德尔福 服务 delphi-10.2-东京
