【发布时间】:2021-12-28 18:17:11
【问题描述】:
使用 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 安全的来龙去脉,但我确信有办法做到这一点 - 我只是不知道上面的哪些部分需要调整以便使用正确的权限。或者,如果有更好的方法可以做到这一点,我愿意接受。有什么建议吗?
谢谢。
【问题讨论】:
标签: delphi service delphi-10.2-tokyo