Hallo zusammen,
ich bin in der Windows API mit Delphi 5 (unter Win 2000) hängengeblieben.
Mit folgendem Quellcode versuche ich einen Consolenprozess zu starten, der aber die Rechte eines localen Admins haben muss
(der aufruf von cmd.exe ist nur ein Beispiel):
'
'
function TForm1.GetConsoleOutput(const Command: String; var Output, Errors: TStringList): Boolean;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
SecurityAttr: TSecurityAttributes;
gsaSecAttr : TSecurityAttributes;
gsaSecDescr: TSecurityDescriptor;
PipeOutputRead: THandle;
PipeOutputWrite: THandle;
PipeErrorsRead: THandle;
PipeErrorsWrite: THandle;
hAccessToken : Cardinal;
NewPrimToken : Cardinal;
Succeed: Boolean;
Buffer: array [0..255] of Char;
NumberOfBytesRead: DWORD;
Stream: TMemoryStream;
SecurityImpersonation : TSecurityImpersonationLevel;
begin
if LogonUser(PAnsiChar('Administrator'), // UserName
PAnsiChar(''), // Domäne oder lokaler Rechner
PAnsiChar('MyPasswort'), // Password
LOGON32_LOGON_NETWORK or LOGON32_LOGON_BATCH ,
LOGON32_PROVIDER_DEFAULT,
hAccessToken)
then
begin
if ImpersonateLoggedOnUser(hAccessToken) then
begin
SecurityImpersonation := SecurityIdentification;
if not DuplicateTokenEx(hAccessToken, TOKEN_DUPLICATE or TOKEN_QUERY , nil , SecurityImpersonation, TokenPrimary, NewPrimToken)
then showmessage('DuplicateTokenEx: ' + SysErrorMessage(GetLastError));
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.bInheritHandle := true;
SecurityAttr.lpSecurityDescriptor := nil;
//Pipes erzeugen
CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);
CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0);
//Initialisierung StartupInfo
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
StartupInfo.cb:=SizeOf(StartupInfo);
StartupInfo.hStdInput := 0;
StartupInfo.hStdOutput := PipeOutputWrite;
StartupInfo.hStdError := PipeErrorsWrite;
StartupInfo.wShowWindow := sw_Show;
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
if CreateProcessAsUser(NewPrimToken,nil, PChar('c:\winnt\system32\cmd.exe'), nil, nil, true, CREATE_NEW_PROCESS_GROUP or
CREATE_DEFAULT_ERROR_MODE or NORMAL_PRIORITY_CLASS, nil, nil,
StartupInfo, ProcessInfo) then
begin
result:=true;
//Write-Pipes schließen
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsWrite);
//Ausgabe Read-Pipe auslesen
Stream := TMemoryStream.Create;
try
while true do begin
succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
if not succeed then break;
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Output.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeOutputRead);
//Fehler Read-Pipe auslesen
Stream := TMemoryStream.Create;
try
while true do begin
succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);
if not succeed then break;
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Errors.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeErrorsRead);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
CloseHandle(ProcessInfo.hProcess);
end
else //CreateProcess failed
begin
showmessage('Ende: ' + syserrormessage(getlasterror));
result:=false;
CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsRead);
CloseHandle(PipeErrorsWrite);
CloseHandle(hAccessToken);
CloseHandle(NewPrimToken);
end;
RevertToSelf; // zurückschalten zum angemeldeten Benutzer
end;
end;
end;
'
'
Wenn ich die Sache aufrufe tut sich eigentlich gar nichts. Erst der Aufruf des GetLastError zum Schluss sagt dann "Zugriff verweigert" - die Meldung müsste aus dem Aufruf von "CreateProcessAsUser" resultieren.
Ich tippe mal darauf, daß ich im Umgang mit "DuplicateTokenEx" oder "CreateProcessAsUser" mindestens einen Fehler gemacht habe - nur wo?
Kann mir bitte jemand helfen?
Danke im voraus.
Knut
'
PS: Kann mir mal jemand zeigen, wie man hier Leerzeilen in den Text einfügt, mehrfach ENTER wird offensichtlich ignoriert.
ich bin in der Windows API mit Delphi 5 (unter Win 2000) hängengeblieben.
Mit folgendem Quellcode versuche ich einen Consolenprozess zu starten, der aber die Rechte eines localen Admins haben muss
(der aufruf von cmd.exe ist nur ein Beispiel):
'
'
function TForm1.GetConsoleOutput(const Command: String; var Output, Errors: TStringList): Boolean;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
SecurityAttr: TSecurityAttributes;
gsaSecAttr : TSecurityAttributes;
gsaSecDescr: TSecurityDescriptor;
PipeOutputRead: THandle;
PipeOutputWrite: THandle;
PipeErrorsRead: THandle;
PipeErrorsWrite: THandle;
hAccessToken : Cardinal;
NewPrimToken : Cardinal;
Succeed: Boolean;
Buffer: array [0..255] of Char;
NumberOfBytesRead: DWORD;
Stream: TMemoryStream;
SecurityImpersonation : TSecurityImpersonationLevel;
begin
if LogonUser(PAnsiChar('Administrator'), // UserName
PAnsiChar(''), // Domäne oder lokaler Rechner
PAnsiChar('MyPasswort'), // Password
LOGON32_LOGON_NETWORK or LOGON32_LOGON_BATCH ,
LOGON32_PROVIDER_DEFAULT,
hAccessToken)
then
begin
if ImpersonateLoggedOnUser(hAccessToken) then
begin
SecurityImpersonation := SecurityIdentification;
if not DuplicateTokenEx(hAccessToken, TOKEN_DUPLICATE or TOKEN_QUERY , nil , SecurityImpersonation, TokenPrimary, NewPrimToken)
then showmessage('DuplicateTokenEx: ' + SysErrorMessage(GetLastError));
FillChar(ProcessInfo, SizeOf(TProcessInformation), 0);
FillChar(SecurityAttr, SizeOf(TSecurityAttributes), 0);
SecurityAttr.nLength := SizeOf(SecurityAttr);
SecurityAttr.bInheritHandle := true;
SecurityAttr.lpSecurityDescriptor := nil;
//Pipes erzeugen
CreatePipe(PipeOutputRead, PipeOutputWrite, @SecurityAttr, 0);
CreatePipe(PipeErrorsRead, PipeErrorsWrite, @SecurityAttr, 0);
//Initialisierung StartupInfo
FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
StartupInfo.cb:=SizeOf(StartupInfo);
StartupInfo.hStdInput := 0;
StartupInfo.hStdOutput := PipeOutputWrite;
StartupInfo.hStdError := PipeErrorsWrite;
StartupInfo.wShowWindow := sw_Show;
StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
if CreateProcessAsUser(NewPrimToken,nil, PChar('c:\winnt\system32\cmd.exe'), nil, nil, true, CREATE_NEW_PROCESS_GROUP or
CREATE_DEFAULT_ERROR_MODE or NORMAL_PRIORITY_CLASS, nil, nil,
StartupInfo, ProcessInfo) then
begin
result:=true;
//Write-Pipes schließen
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsWrite);
//Ausgabe Read-Pipe auslesen
Stream := TMemoryStream.Create;
try
while true do begin
succeed := ReadFile(PipeOutputRead, Buffer, 255, NumberOfBytesRead, nil);
if not succeed then break;
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Output.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeOutputRead);
//Fehler Read-Pipe auslesen
Stream := TMemoryStream.Create;
try
while true do begin
succeed := ReadFile(PipeErrorsRead, Buffer, 255, NumberOfBytesRead, nil);
if not succeed then break;
Stream.Write(Buffer, NumberOfBytesRead);
end;
Stream.Position := 0;
Errors.LoadFromStream(Stream);
finally
Stream.Free;
end;
CloseHandle(PipeErrorsRead);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
CloseHandle(ProcessInfo.hProcess);
end
else //CreateProcess failed
begin
showmessage('Ende: ' + syserrormessage(getlasterror));
result:=false;
CloseHandle(PipeOutputRead);
CloseHandle(PipeOutputWrite);
CloseHandle(PipeErrorsRead);
CloseHandle(PipeErrorsWrite);
CloseHandle(hAccessToken);
CloseHandle(NewPrimToken);
end;
RevertToSelf; // zurückschalten zum angemeldeten Benutzer
end;
end;
end;
'
'
Wenn ich die Sache aufrufe tut sich eigentlich gar nichts. Erst der Aufruf des GetLastError zum Schluss sagt dann "Zugriff verweigert" - die Meldung müsste aus dem Aufruf von "CreateProcessAsUser" resultieren.
Ich tippe mal darauf, daß ich im Umgang mit "DuplicateTokenEx" oder "CreateProcessAsUser" mindestens einen Fehler gemacht habe - nur wo?
Kann mir bitte jemand helfen?
Danke im voraus.
Knut
'
PS: Kann mir mal jemand zeigen, wie man hier Leerzeilen in den Text einfügt, mehrfach ENTER wird offensichtlich ignoriert.