gpt4 book ai didi

windows - CreateProcessAsUser 来自服务和用户安全问题

转载 作者:行者123 更新时间:2023-12-05 06:46:30 26 4
gpt4 key购买 nike

我有一个启动我的应用程序的 Windows 服务。此服务是一个调度程序,用于执行最终用户定义的一些自定义操作。

它作为 LocalSystem 帐户运行,并将启动我的应用程序(有窗口)。

为此,我使用函数 LogongUser , LoadUserProfile , CreateProcessAsUser .这非常有效但前提是登录的用户是管理员组的成员。

我不能将用户保留为管理员,他需要成为默认用户(用户组的成员)。

作为管理员,它在服务中运行良好。但是当进程以默认用户身份启动时,它会异常终止:

ExitCode: 0xC0000142 STATUS_DLL_INIT_FAILED
Message: {DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is terminating abnormally.

如果我使用该用户(Users 组的成员)登录并手动启动应用程序,一切正常。

我还没有弄清楚导致问题的库是什么。我检查了系统事件日志,但没有日志。我已经尝试过 ImporsonateLoggedOnUser但没有成功。

这是代码:

type 
TProcessRec = record
Token: Cardinal;
ProfileInfo: TProfileInfo;
Job: Cardinal;
Environment: Pointer;
ProcessInfo: TProcessInformation;
WinStat: HWINSTA;
end;

TProcess = class
private
fProcess: TProcessRec;
public
constructor Create(aUser, aDomain, aPassword, aCommand, aWorkingDir: string; aUtil: TJJWServiceUtil);
destructor Destroy; override;

procedure Terminate(aExitCode: Cardinal);

function getExitCode: Cardinal;
end;

constructor TProcess.Create(aUser, aDomain, aPassword, aCommand, aWorkingDir: string; aUtil: TJJWServiceUtil);
type
TCreateProcessFuncType = (cpAsUser, cpWithLogon);
const
DES_CREATION_TYPE: array [TCreateProcessFuncType] of string =
('CreateProcessAsUser', 'CreateProcessWithLogon');
var
sa: TSecurityAttributes;
si: TStartupInfo;
limits : TJobObjectExtendedLimitInformation;
wUser, wDomain, wPassword, wCommand, wWorkingDir: WideString;
creationType: TCreateProcessFuncType;
begin

// se estiver rodando com a conta LocalSystem (em serviço de windows)
if
IsPrivilegeEnabled(SE_TCB_NAME) or IsPrivilegeEnabled(SE_INCREASE_QUOTA_NAME)
then
creationType := cpAsUser
else
creationType := cpWithLogon;

aUtil.debug('ENV: ' + AnsiReplaceStr(GetEnvironmentVariable('PATH'), '%', '%%'));
aUtil.debug('Criando novo processo em modo: ' + DES_CREATION_TYPE[creationType]);

FillChar(fProcess, SizeOf(fProcess), 0);

FillChar(sa, SizeOf(sa), 0);
sa.nLength := SizeOf(sa);

FillChar(si, SizeOf(si), 0);
si.cb := SizeOf(si);

case creationType of

cpAsUser:
begin
aUtil.debug('Efetuando o login do usuário %s', [aUser]);
// login
if not LogonUser(PChar(aUser), PChar(aDomain), PChar(aPassword), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, fProcess.Token) then
RaiseLastOSError;

try
aUtil.debug('Carrengado o profile do usuário %s', [aUser]);

// carrega o profile do usuário
fProcess.ProfileInfo.dwSize := SizeOf(fProcess.ProfileInfo);
fProcess.ProfileInfo.dwFlags := PI_NOUI;
fProcess.ProfileInfo.lpUserName := PChar(aUser);
if not LoadUserProfile(fProcess.Token, fProcess.ProfileInfo) then
RaiseLastOSError;

try
aUtil.debug('Criando o bloco de variáveis de ambiente do usuário %s', [aUser]);
// variaveis de ambiente
if not CreateEnvironmentBlock(fProcess.Environment, fProcess.Token, false) then
RaiseLastOSError;

aUtil.debug('Criando o JOB para associar o processo filho ao processo pai');
// job para associar
fProcess.Job := CreateJobObject(@sa, nil);
if fProcess.Job = 0 then
RaiseLastOSError;

try
// limita o job para matar o seu processo caso o processo pai termine antes
FillChar(Limits,SizeOf(Limits),0);
with Limits,BasicLimitInformation do
LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE or JOB_OBJECT_LIMIT_BREAKAWAY_OK;

if not SetInformationJobObject(fProcess.Job, JobObjectExtendedLimitInformation, @limits, SizeOf(limits)) then
RaiseLastOSError;

try
fProcess.WinStat := CreateWindowStation(SCHEDULER_WINSTAT, 0, 0, nil);
if fProcess.WinStat = 0 then
RaiseLastOSError;
si.lpDesktop := PChar(SCHEDULER_WINSTAT);

aUtil.debug('Criando o processo: %s', [aCommand]);

// processo!
if not CreateProcessAsUser(
fProcess.Token,
nil,
PChar(aCommand),
@sa,
nil,
false,
CREATE_SUSPENDED or CREATE_BREAKAWAY_FROM_JOB or NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP or CREATE_UNICODE_ENVIRONMENT,
fProcess.Environment,
PChar(aWorkingDir),
si,
fProcess.ProcessInfo)
then
RaiseLastOSError;

try
aUtil.debug('Associando o JOB ao processo filho');
// associa ao processo do plugin o JOB (gruda nele!)
if not AssignProcessToJobObject(fProcess.Job, fProcess.ProcessInfo.hProcess) then
RaiseLastOSError;

// VOA PROCESSO, VOA!
if ResumeThread(fProcess.ProcessInfo.hThread) = $FFFFFFFF then
RaiseLastOSError;

aUtil.debug('Processo disparado');
except
TerminateProcess(fProcess.ProcessInfo.hProcess, Cardinal(-1));

CloseHandle(fProcess.ProcessInfo.hThread);
CloseHandle(fProcess.ProcessInfo.hProcess);

FillChar(fProcess.ProcessInfo, SizeOf(fProcess.ProcessInfo), 0);

raise;
end;

except
DestroyEnvironmentBlock(fProcess.Environment);
fProcess.Environment := nil;
raise;
end;

except
CloseHandle(fProcess.Job);
fProcess.Job := 0;
raise;
end;

except
UnloadUserProfile(fProcess.Token, fProcess.ProfileInfo.hProfile);
FillChar(fProcess.ProfileInfo, SizeOf(fProcess.ProfileInfo), 0);
raise;
end;

except
CloseHandle(fProcess.Token);
fProcess.Token := 0;
raise;
end;
end;

//////////////////////////////////////////////////////////////////////////////

cpWithLogon:
begin
wUser := aUser;
wDomain := aDomain;
wPassword := aPassword;
wCommand := aCommand;
wWorkingDir := aWorkingDir;

aUtil.debug('Disparando o processo: %s', [aCommand]);

// o CreateProcessWithLogon já cria um JOB para evitar
// que o processo fique órfão no limbo
if not CreateProcessWithLogon(
PWideChar(wUser),
PWideChar(wDomain),
PWideChar(wPassword),
LOGON_WITH_PROFILE,
nil,
PWideChar(wCommand),
NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP,
nil,
PWideChar(wWorkingDir),
si,
fProcess.ProcessInfo
)
then
RaiseLastOSError;
end;

end;
end;

destructor TProcess.Destroy;
begin
if fProcess.ProcessInfo.hProcess > 0 then
begin
if getExitCode = STILL_ACTIVE then
TerminateProcess(fProcess.ProcessInfo.hProcess, Cardinal(-1));

CloseHandle(fProcess.ProcessInfo.hThread);
CloseHandle(fProcess.ProcessInfo.hProcess);
end;

if fProcess.Environment <> nil then
DestroyEnvironmentBlock(fProcess.Environment);

if fProcess.Job > 0 then
CloseHandle(fProcess.Job);

if fProcess.ProfileInfo.hProfile > 0 then
UnloadUserProfile(fProcess.Token, fProcess.ProfileInfo.hProfile);

if fProcess.Token > 0 then
CloseHandle(fProcess.Token);

if fProcess.WinStat > 0 then
CloseWindowStation(fProcess.WinStat);

FillChar(fProcess, SizeOf(fProcess), 0);

inherited;
end;

function TProcess.getExitCode: Cardinal;
begin
if not GetExitCodeProcess(fProcess.ProcessInfo.hProcess, Result) then
RaiseLastOSError;
end;

这很有用

Starting an Interactive Client Process in C++

最佳答案

根据这个:Starting an Interactive Client Process in C++

还有这个:CreateProcessAsUser() windowstations and desktops

我解决了创建新的 WindowStation 和 Deskyop 以启动进程的问题:

myWinStat := CreateWindowStation('myWinStat', 0, GENERIC_READ or GENERIC_WRITE, nil);
myDesk := CreateDesktop('myDesktop', nil, nil, 0, GENERIC_READ or GENERIC_WRITE, nil);
startupInfo.lpDesktop := 'myDesktop';
try
// createProcessAsUser...
// Wait for process termination...
finally
CloseDesktop(myDesk);
CloseWindowStation(myWinStat);
end;

关于windows - CreateProcessAsUser 来自服务和用户安全问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15158888/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com