Вобщем, попробовал я заюзать CreateProcessAsUser(), без извратов, как я заметил, это сделать не получится... Поискал по локальным базам, нашёл с Delphi Kingdom некоторую инфу об этом, но там код почему-то не весь дан. Говорят, что это пример C-кода, кторый можно найти на
http://msdn.microsoft.com/. Я в сишке не особо шарю, посему решил поискать в Гугле — наёшл код, но он не работает под ХР, и у меня не получилось заставить его работать . В смысле, он компилится, CreateProcessAsUser происходит, но процесс не запускается... Вот код:
const
DESKTOP_ALL = DESKTOP_READOBJECTS or DESKTOP_CREATEWINDOW or DESKTOP_CREATEMENU or DESKTOP_HOOKCONTROL or
DESKTOP_JOURNALRECORD or DESKTOP_JOURNALPLAYBACK or DESKTOP_ENUMERATE or DESKTOP_WRITEOBJECTS or
DESKTOP_SWITCHDESKTOP or STANDARD_RIGHTS_REQUIRED;
WINSTA_ALL = WINSTA_ENUMDESKTOPS or WINSTA_READATTRIBUTES or WINSTA_ACCESSCLIPBOARD or WINSTA_CREATEDESKTOP or
WINSTA_WRITEATTRIBUTES or WINSTA_ACCESSGLOBALATOMS or WINSTA_EXITWINDOWS or WINSTA_ENUMERATE or
WINSTA_READSCREEN or STANDARD_RIGHTS_REQUIRED;
GENERIC_ACCESS = GENERIC_READ or GENERIC_WRITE or GENERIC_EXECUTE or GENERIC_ALL;
HEAP_ZERO_MEMORY = 8;
ACL_REVISION = 2;
ACCESS_ALLOWED_ACE_TYPE = 0;
CONTAINER_INHERIT_ACE = 2;
INHERIT_ONLY_ACE = 8;
OBJECT_INHERIT_ACE = 1;
NO_PROPAGATE_INHERIT_ACE = 4;
SE_GROUP_LOGON_ID = $C0000000;
type
ACL_SIZE_INFORMATION = record
AceCount: DWORD;
AclBytesInUse: DWORD;
AclBytesFree: DWORD;
end;
ACE_HEADER = record
AceType: BYTE;
AceFlags: BYTE;
AceSize: WORD;
end;
PACE_HEADER = ^ACE_HEADER;
ACCESS_ALLOWED_ACE = record
Header: ACE_HEADER;
Mask: ACCESS_MASK;
SidStart: DWORD;
end;
function AddAceToWindowStation(hwinsta: HWINSTA; psid: PSID): Boolean;
var
si: SECURITY_INFORMATION;
psd, psdNew: PSECURITY_DESCRIPTOR;
dwSidSize, dwSdSizeNeeded, dwNewAclSize: DWORD;
bDaclPresent, bDaclExist: LongBool;
pdacl, pNewAcl: PACL;
aclSizeInfo: ACL_SIZE_INFORMATION;
i: integer;
pTempAce: PACE_HEADER;
pace: ^ACCESS_ALLOWED_ACE;
begin
Result := False;
si := DACL_SECURITY_INFORMATION;
pace := nil;
psd := nil;
dwSidSize := 0;
pNewAcl := nil;
psdNew := nil;
// Obtain the DACL for the window station.
try
if not GetUserObjectSecurity(hwinsta, si, psd, dwSidSize, dwSdSizeNeeded) then begin
if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin
psd := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded);
if psd = nil then
Exit;
psdNew := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded);
if psdNew = nil then
Exit;
dwSidSize := dwSdSizeNeeded;
if not GetUserObjectSecurity(hwinsta, si, psd, dwSidSize, dwSdSizeNeeded) then
Exit;
end
else begin
Exit;
end;
end;
// Create a new DACL.
if not InitializeSecurityDescriptor(psdNew, SECURITY_DESCRIPTOR_REVISION) then
Exit;
// Get the DACL from the security descriptor.
if not GetSecurityDescriptorDacl(psd, bDaclPresent, pdacl, bDaclExist) then
Exit;
// Initialize the ACL.
ZeroMemory(@aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION));
aclSizeInfo.AclBytesInUse := SizeOf(ACL);
// Call only if the DACL is not NULL.
if pdacl <> nil then begin
// get the file ACL size info
if not GetAclInformation(pdacl^, @aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION), AclSizeInformation) then
Exit;
end;
// Compute the size of the new ACL.
dwNewAclSize := aclSizeInfo.AclBytesInUse + (2 * SizeOf(ACCESS_ALLOWED_ACE)) + (2 * GetLengthSid(psid)) - (2 * SizeOf(DWORD));
// Allocate memory for the new ACL.
pNewAcl := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwNewAclSize);
if pNewAcl = nil then
Exit;
// Initialize the new DACL.
if not InitializeAcl(pNewAcl^, dwNewAclSize, ACL_REVISION) then
Exit;
// If DACL is present, copy it to a new DACL.
if bDaclPresent then begin
// Copy the ACEs to the new ACL.
if aclSizeInfo.AceCount > 0 then begin
for i := 0 to aclSizeInfo.AceCount - 1 do begin
// Get an ACE.
if not GetAce(pdacl^, i, Pointer(pTempAce)) then
Exit;
// Add the ACE to the new ACL.
if not AddAce(pNewAcl^, ACL_REVISION, MAXDWORD, pTempAce, pTempAce.AceSize) then
Exit;
end;
end;
end;
// Add the first ACE to the window station.
pace := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, SizeOf(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - SizeOf(DWORD));
if pace = nil then
Exit;
pace.Header.AceType := ACCESS_ALLOWED_ACE_TYPE;
pace.Header.AceFlags := CONTAINER_INHERIT_ACE or INHERIT_ONLY_ACE or OBJECT_INHERIT_ACE;
pace.Header.AceSize := SizeOf(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - SizeOf(DWORD);
pace.Mask := GENERIC_ACCESS;
if not CopySid(GetLengthSid(psid), @pace.SidStart, psid) then
Exit;
if not AddAce(pNewAcl^, ACL_REVISION, MAXDWORD, pace, pace.Header.AceSize) then
Exit;
// Add the second ACE to the window station.
pace.Header.AceFlags := NO_PROPAGATE_INHERIT_ACE;
pace.Mask := WINSTA_ALL;
if not AddAce(pNewAcl^, ACL_REVISION, MAXDWORD, pace, pace.Header.AceSize) then
Exit;
// Set a new DACL for the security descriptor.
if not SetSecurityDescriptorDacl(psdNew, True, pNewAcl, False) then
Exit;
// Set the new security descriptor for the window station.
if not SetUserObjectSecurity(hwinsta, si, psdNew) then
Exit;
// Indicate success.
Result := True;
finally
// Free the allocated buffers.
if pace <> nil then
HeapFree(GetProcessHeap, 0, pace);
if pNewAcl <> nil then
HeapFree(GetProcessHeap, 0, pNewAcl);
if psd <> nil then
HeapFree(GetProcessHeap, 0, psd);
if psdNew <> nil then
HeapFree(GetProcessHeap, 0, psdNew);
end;
end;
function GetLogonSID(hToken: THandle; var ppsid: PSID): Boolean;
var
dwLength: DWORD;
ptg: ^TOKEN_GROUPS;
i: integer;
begin
Result := False;
dwLength := 0;
ptg := nil;
try
// Verify the parameter passed in is not NULL.
// if ppsid = nil then
// Exit;
// Get required buffer size and allocate the TOKEN_GROUPS buffer.
if not GetTokenInformation(hToken, TokenGroups, ptg, 0, dwLength) then begin
if GetLastError <> ERROR_INSUFFICIENT_BUFFER then
Exit;
ptg := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwLength);
if ptg = nil then
Exit;
// Get the token group information from the access token.
if not GetTokenInformation(hToken, TokenGroups, ptg, dwLength, dwLength) then
Exit;
// Loop through the groups to find the logon SID.
for i := 0 to ptg.GroupCount - 1 do begin
if ptg.Groups[i].Attributes and SE_GROUP_LOGON_ID = SE_GROUP_LOGON_ID then begin
// Found the logon SID; make a copy of it.
dwLength := GetLengthSid(ptg.Groups[i].Sid);
ppsid := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwLength);
if ppsid = nil then
Exit;
if not CopySid(dwLength, ppsid, ptg.Groups[i].Sid) then begin
HeapFree(GetProcessHeap, 0, ppsid);
Exit;
end;
Break;
end;
end;
Result := True;
end;
finally
// Free the buffer for the token groups.
if ptg <> nil then
HeapFree(GetProcessHeap, 0, ptg);
end;
end;
function AddAceToDesktop(hdesktop: HDESK; ps: PSID): Boolean;
var
aclSizeInfo: ACL_SIZE_INFORMATION;
bDaclExist, bDaclPresent: LongBool;
dwNewAclSize, dwSidSize, dwSdSizeNeeded: DWORD;
pdacl, pNewAcl: PACL;
psd, psdNew: PSECURITY_DESCRIPTOR;
pTempAce: PACE_HEADER;
si: SECURITY_INFORMATION;
i: integer;
begin
Result := False;
psd := nil;
psdNew := nil;
pNewAcl := nil;
si := DACL_SECURITY_INFORMATION;
dwSidSize := 0;
try
// Obtain the security descriptor for the desktop object.
if not GetUserObjectSecurity(hdesktop, si, psd, dwSidSize, dwSdSizeNeeded) then begin
if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin
psd := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded);
if psd = nil then
Exit;
psdNew := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded);
if psdNew = nil then
Exit;
dwSidSize := dwSdSizeNeeded;
if not GetUserObjectSecurity(hdesktop, si, psd, dwSidSize, dwSdSizeNeeded) then
Exit;
end
else begin
Exit;
end;
end;
// Create a new security descriptor.
if not InitializeSecurityDescriptor(psdNew, SECURITY_DESCRIPTOR_REVISION) then
Exit;
// Obtain the DACL from the security descriptor.
if not GetSecurityDescriptorDacl(psd, bDaclPresent, pdacl, bDaclExist) then
Exit;
// Initialize.
ZeroMemory(@aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION));
aclSizeInfo.AclBytesInUse := SizeOf(ACL);
// Call only if NULL DACL.
if pdacl <> nil then begin
// Determine the size of the ACL information.
if not GetAclInformation(pdacl^, @aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION), AclSizeInformation) then
Exit;
end;
// Compute the size of the new ACL.
dwNewAclSize := aclSizeInfo.AclBytesInUse + SizeOf(ACCESS_ALLOWED_ACE) + GetLengthSid(ps) - SizeOf(DWORD);
// Allocate buffer for the new ACL.
pNewAcl := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwNewAclSize);
if pNewAcl = nil then
Exit;
// Initialize the new ACL.
if not InitializeAcl(pNewAcl^, dwNewAclSize, ACL_REVISION) then
Exit;
// If DACL is present, copy it to a new DACL.
if bDaclPresent then begin
// Copy the ACEs to the new ACL.
if aclSizeInfo.AceCount > 0 then begin
for i := 0 to aclSizeInfo.AceCount - 1 do begin
// Get an ACE.
if not GetAce(pdacl^, i, Pointer(pTempAce)) then
Exit;
// Add the ACE to the new ACL.
if not AddAce(pNewAcl^, ACL_REVISION, MAXDWORD, pTempAce, pTempAce.AceSize) then
Exit;
end;
end;
end;
// Add ACE to the DACL.
if not AddAccessAllowedAce(pNewAcl^, ACL_REVISION, DESKTOP_ALL, ps) then
Exit;
// Set new DACL to the new security descriptor.
if not SetSecurityDescriptorDacl(psdNew, True, pNewAcl, False) then
Exit;
// Set the new security descriptor for the desktop object.
if not SetUserObjectSecurity(hdesktop, si, psdNew) then
Exit;
// Indicate success.
Result := True;
finally
// Free buffers.
if pNewAcl <> nil then
HeapFree(GetProcessHeap, 0, pNewAcl);
if psd <> nil then
HeapFree(GetProcessHeap(), 0, psd);
if psdNew <> nil then
HeapFree(GetProcessHeap(), 0, psdNew);
end;
end;
function StartInteractiveClientProcess(lpszUsername, lpszDomain, lpszPassword, lpCommandLine: PChar): Boolean;
var
hToken: THandle;
hdesktop: HDESK;
hwinst, hwinstSave: HWINSTA;
pi: PROCESS_INFORMATION;
pS: PSID;
si: STARTUPINFO;
begin
Result := False;
hdesktop := 0;
hwinst := 0;
hwinstSave := 0;
pS := nil;
try
// Log the client on to the local computer.
if not LogonUser(lpszUsername, lpszDomain, lpszPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken) then
Exit;
// Save a handle to the caller's current window station.
hwinstSave := GetProcessWindowStation;
if hwinstSave = 0 then
Exit;
// Get a handle to the interactive window station.
hwinst := OpenWindowStation('winsta0', False, READ_CONTROL or WRITE_DAC);
if hwinst = 0 then
Exit;
// To get the correct default desktop, set the caller's
// window station to the interactive window station.
if not SetProcessWindowStation(hwinst) then
Exit;
// Get a handle to the interactive desktop.
hdesktop := OpenDesktop('default', 0, False, READ_CONTROL or WRITE_DAC or DESKTOP_WRITEOBJECTS or DESKTOP_READOBJECTS);
// Restore the caller's window station.
if not SetProcessWindowStation(hwinstSave) then
Exit;
if hdesktop = 0 then
Exit;
// Get the SID for the client's logon session.
if not GetLogonSID(hToken, pS) then
Exit;
// Allow logon SID full access to interactive window station.
if not AddAceToWindowStation(hwinst, pS) then
Exit;
// Allow logon SID full access to interactive desktop.
if not AddAceToDesktop(hdesktop, pS) then
Exit;
// Impersonate client to ensure access to executable file.
if not ImpersonateLoggedOnUser(hToken) then
Exit;
// Initialize the STARTUPINFO structure.
// Specify that the process runs in the interactive desktop.
ZeroMemory(@si, SizeOf(STARTUPINFO));
si.cb := SizeOf(STARTUPINFO);
si.lpDesktop := PChar('winsta0\\\\\\\\default');
// Launch the process in the client's logon session.
Result := CreateProcessAsUser(hToken, nil, lpCommandLine, nil, nil, False, // handles are not inheritable
NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE, nil, nil, si, pi);
// End impersonation of client.
RevertToSelf();
if Result and (pi.hProcess <> INVALID_HANDLE_VALUE) then begin
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
end;
if pi.hThread <> INVALID_HANDLE_VALUE then
CloseHandle(pi.hThread);
Result := True;
finally
if hwinstSave <> 0 then
SetProcessWindowStation(hwinstSave);
// Free the buffer for the logon SID.
if pS <> nil then
HeapFree(GetProcessHeap, 0, pS);
// Close the handles to the interactive window station and desktop.
if hwinst <> 0 then
CloseWindowStation(hwinst);
if hdesktop <> 0 then
CloseDesktop(hdesktop);
// Close the handle to the client's access token.
if hToken <> INVALID_HANDLE_VALUE then
CloseHandle(hToken);
end;
end;
Вот процедурка, из которой должна запускаться прога /консоль/ (имя домена пробовал поставить не '.', а nil — тот же результат):
var
ERR: DWORD;
begin
{
StartInteractiveClientProcess(
lpszUsername,
lpszDomain,
lpszPassword,
lpCommandLine: PChar): Boolean;
}
if not StartInteractiveClientProcess('tst', '.', '1', 'C:\WINDOWS\system32\cmd.exe') then
begin
ERR := GetLastError;
Application.MessageBox(PChar(IntToStr(ERR) + ': ' + SysErrorMessage(ERR)), 'Error', MB_ICONWARNING or MB_OK);
end;
end;
P.S. Приношу извинения за столь длинный код, просто не нашёл ссылку на ресурс, откуда я его достал, а аттач из-под Януса не делается...
RSDN@Home v.1.1.4
ORIGIN: Для чиво нужин Арфагрофический Славарь?