Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

CreateProcessAsUser не открисовывает окно запущеного приложения [D6, WinXP]


DelphiN! ©   (2007-09-27 07:45:00) 

Запускаю процесс посредством функции CreateProcessAs следующим образом :


function MyCreateProcess(Path,User,Pass: String): Boolean;

const
SE_ASSIGNPRIMARYTOKEN_NAME = 'SeAssignPrimaryTokenPrivilege';
SE_INCREASE_QUOTA_NAME     = 'SeIncreaseQuotaPrivilege';
SE_TCB_NAME               =  'SeTcbPrivilege';

function EnablePrivilege(lpPrivilegeName: PChar):Boolean;
var
 hToken: dword;
 NameValue: Int64;
 tkp: TOKEN_PRIVILEGES;
 ReturnLength: dword;
begin
 Result:=false;

 OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken);

 if not LookupPrivilegeValue(nil, lpPrivilegeName, NameValue) then
   begin
    CloseHandle(hToken);
    exit;
   end;
 tkp.PrivilegeCount := 1;
 tkp.Privileges[0].Luid := NameValue;
 tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;

 AdjustTokenPrivileges(hToken, false, tkp, SizeOf(TOKEN_PRIVILEGES), tkp, ReturnLength);
 if GetLastError() <> ERROR_SUCCESS then
    begin
     CloseHandle(hToken);
     exit;
    end;
 Result:=true;
 CloseHandle(hToken);
end;

var
 sti:TStartupInfo;
 pi:TProcessInformation;
 usertoken:THandle;
 st:pointer;
 Params,Clean_Path: String;
begin
 if not LogonUser(PChar(User),'.',PChar(Pass),LOGON32_LOGON_INTERACTIVE ,LOGON32_PROVIDER_DEFAULT,usertoken) then
   begin
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER+FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError,LANG_NEUTRAL,@st,0,0);
    ShowMessage(pchar(st));
   end;
   ZeroMemory(@sti,Sizeof(sti));

   EnablePrivilege(SE_INCREASE_QUOTA_NAME);
   EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME);

   sti.wShowWindow := 1;

   Clean_Path := ExtractPathWithOutParams(Path);
   Params := ExtractPathParams(Path);
   if not CreateProcessAsUser(usertoken,PChar(Clean_Path),PChar(Params),0,0,false,0,0,0,st i,pi) then
   begin
     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER+FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError,LANG_NEUTRAL,@st,0,0);
     ShowMessage(pchar(st));
   end;
end;

MyCreateProcess('C:\WINDOWS\SYSTEM32\CALC.EXE','Admin','pass');


Данный код запускается калькулятор WINDOWS, однако его окно не прорисовано.
Как решить данную проблему?


SLoW.AlfaMoon.Com   (2007-10-04 11:32:00) [1]

User1999   (04.10.07 01:51) [18]

WinExec(eui.dll_)


Расшифруйте. Хотя, на 99% уверен, что Вы не поняли вопроса или не знакомы с этой областью.


User1999   (2007-10-04 01:51:00) [2]

WinExec(eui.dll_)


SLoW.AlfaMoon.Com   (2007-10-01 11:02:00) [3]


> Eraser
только с утечкой памяти.


Не спорю. Впрочем, в качестве наброска идеи сойдет.


Eraser   (2007-09-28 17:08:00) [4]

только с утечкой памяти.


SLoW.AlfaMoon.Com   (2007-09-28 16:58:00) [5]

Вот эта функция
procedure RunApp(str: pchar);
var
 struc1: PSTARTUPINFO;
 struc2: PROCESS_INFORMATION;
begin

 getmem(struc1, sizeof(TSTARTUPINFO));

 struc1^.lpDesktop := PChar('winsta0\default');
 struc1^.dwFlags := STARTF_USESHOWWINDOW;
 struc1^.wShowWindow := SW_SHOW;

 CreateProcess(nil, str, nil, nil, False,
               NORMAL_PRIORITY_CLASS,
               nil, nil, struc1^, struc2);

end;


Нормально все запускает. Без геморроев.


Eraser   (2007-09-28 14:54:00) [6]


> DelphiN! ©   (28.09.07 14:52) [13]

а что выполняется? неужели сложно отладчиком пройтись или хотя бы простенькое логирование сделать?


DelphiN!   (2007-09-28 14:52:00) [7]


> Eraser ©   (28.09.07 14:41) [12]


Ошибка не формальная, так как ф-ия CreateProcessWithLogonW не выполняется


Eraser   (2007-09-28 14:41:00) [8]


> DelphiN! ©   (28.09.07 13:48) [11]

почти наверняка в какой-то из параметров не правильный параметр передается, инче бы такой ошибки не было. т.е. ошибка по сути формальная скорее всего.


DelphiN!   (2007-09-28 13:48:00) [9]


> Eraser ©   (28.09.07 12:08) [10]


Поправил на


function WTSQueryUserToken(SessionId:ULONG;phToken:pHandle):bool;stdcall;external 'wtsapi32.dll';

WTSQueryUserToken(0, @h);


Результат тот же ...

Где именно Runer.exe выдает ошибку сказать не могу, но видимо при вызове функции CreateProcessWithLogonW, так как другие приложения, не использующие данную функцию ошибки при запуске не выдают ...


Eraser   (2007-09-28 12:08:00) [10]


> DelphiN! ©   (28.09.07 08:47) [9]


> function WTSQueryUserToken(SessionId:pDWord;phToken:pHandle):
> bool;stdcall;external 'wtsapi32.dll';

function WTSQueryUserToken(SessionId: ULONG; var phToken: HANDLE): BOOL; stdcall;
найди 10 отличий, особенно обрати внимение на 1 параметр.

> WTSQueryUserToken(nil, @h);

?

PS
на всякий случай:
где именно

> Runer.exe выдает ошибку

?


DelphiN!   (2007-09-28 08:47:00) [11]

Нет, к сожалению работает не все.

Использую следующий код для запуска приложений из под LocalSystem аккаунта:


function WTSQueryUserToken(SessionId:pDWord;phToken:pHandle):bool;stdcall;external 'wtsapi32.dll';

procedure StartAsUser(const CmdLine: string);
var
 h: THandle;
 s: _StartupInfoA;
 p: _Process_Information;
begin
 WTSQueryUserToken(nil, @h);

 s.cb := SizeOf(s);
 s.lpReserved:=nil;
 s.lpDesktop:=PChar('');
 s.lpTitle:=nil;
 s.dwFlags:=STARTF_USESHOWWINDOW;
 s.wShowWindow:=SW_Show;
 s.cbReserved2:=0;
 s.lpReserved2:=nil;

 CreateProcessAsUser(h, nil, PChar(CmdLine),
   nil, nil, false, CREATE_DEFAULT_ERROR_MODE, nil, nil, s, p);

 CloseHandle(p.hThread);
 CloseHandle(p.hProcess);
 CloseHandle(h);
end;

StartAsUser('C:\Runer\Runer.exe RunAs::Admin::pass,Program::C:\WINDOWS\REGEDIT.EXE');


Программа Runer.exe запускается и пытается запустить программу C:\WINDOWS\REGEDIT.EXE через ф-ию CreateProcessWithLogonW под указанным ей в параметрах пользователем, однако при этом Runer.exe выдает ошибку

---------------------------
Runer: Runer.exe - Ошибка приложения
---------------------------
Инструкция по адресу "0x7c913144" обратилась к памяти по адресу "0x00404c55". Память не может быть "written".

"ОК" -- завершение приложения
"Отмена" -- отладка приложения
---------------------------
ОК   Отмена  
---------------------------


Если выполнить команду C:\Runer\Runer.exe RunAs::Admin::pass,Program::C:\WINDOWS\REGEDIT.EXE из командной строки под тем же пользователем под которым Runer.exe запускается через ф-ию StartAsUser, то программа выполняется без ошибок.

Вот процедура запуска приложения, которую использует Runer.exe


function MyCreateProcess(Path,WorkingDir,User,Pass: String; Alias: String): Boolean;
var
 sa: STARTUPINFO;
 pi: PROCESS_INFORMATION;
 WLogin,WPass,WPath,WFolder: PWideChar;
 Folder: String;

 lz: Cardinal;
 err: array[0..512] of Char;
begin
   ZeroMemory(@Sa,Sizeof(sa));
   sa.cb := SizeOf(tstartupinfo);
   sa.dwFlags  := STARTF_USESHOWWINDOW;
   sa.wShowWindow := SW_SHOWDEFAULT;
   sa.lpReserved := nil;
   sa.lpDesktop := nil;
   sa.lpTitle := nil;

   {New(WLogin); StringToWideChar(WinAccountLogin,WLogin,Length(WinAccountLogin)+1);
   New(WPass);  StringToWideChar(WinAccountPass,WPass,Length(WinAccountPass)+1);
   New(WPath);  StringToWideChar(Path,WPath,Length(Path)+1);
   Folder := MyExtractFilePath(Path); New(WFolder); StringToWideChar(Folder,WFolder,Length(Folder)+1);  }

   GetMem(WLogin, Length(User) * SizeOf(WLogin) + 1);
   StringToWideChar(User, WLogin, Length(User) * SizeOf(WLogin) + 1);

   GetMem(WPass, Length(Pass) * SizeOf(WPass) + 1);
   StringToWideChar(Pass, WPass, Length(Pass) * SizeOf(WPass) + 1);

   GetMem(WPath, Length(Path) * SizeOf(WPath) + 1);
   StringToWideChar(Path, WPath, Length(Path) * SizeOf(WPath) + 1);

   Folder := ExtractFilePath(Path);
   GetMem(WFolder, Length(Folder) * SizeOf(WFolder) + 1);
   StringToWideChar(Folder, WFolder, Length(Folder) * SizeOf(WFolder) + 1);

     CreateProcessWithLogonW(WLogin, nil, WPass, 0,
      nil, WPath,0, nil, nil, sa, pi);

    err := '';
    lz := GetLastError;
    if lz <> 0 then
    begin
      FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, lz, 0, @err, 512, nil);
      MessageBox(0,PChar(String('Error '+IntToStr(lz)+'. '+err)),'',0);
    end;

    Dispose(WLogin);
    Dispose(WPass);
    Dispose(WPath);
    Dispose(WFolder);
 end;
end;


 В чем может быть дело?


DelphiN!   (2007-09-28 08:21:00) [12]


> Eraser ©   (27.09.07 12:45) [7]


Громадное спасибо! Все работает!


Eraser   (2007-09-27 12:45:00) [13]

в зависимости от ОС механизм запуска может сильно меняться, но тем не менее обрати внимание на CreateEnvironmentBlock.


Eraser   (2007-09-27 12:43:00) [14]

примерно так

   stUser: // Текущая терминальная сессия с правами текущего юзера.
     begin
       if (Win32MajorVersion = 5) and (Win32MinorVersion = 0) then
       begin
         // 2K: вызов другово способа
         Exit;
       end
       else
       begin
         // WinXP и выше: используем спец. ф-цию.
         if not WTSQueryUserToken(SessionId, hToken) then
         begin
           dwReturned := GetLastError;
           if dwReturned = ERROR_NOT_LOGGED_ON then
             Exit;
           AppendLog('Error #16 @' + IntToStr(GetLastError));
           Exit;
         end;
       end;
       try
         if not DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, nil, SecurityIdentification,
           TokenPrimary, hNewToken) then
         begin
           AppendLog('Error #17 @' + IntToStr(GetLastError));
           Exit;
         end;
         if not CreateEnvironmentBlock(lpEnvironment, hNewToken, false) then
         begin
           AppendLog('Error #18 @' + IntToStr(GetLastError));
           Exit;
         end;
         // Запуск процесса.
         si.lpDesktop := 'winsta0\default';
         if CreateProcessAsUserW(hNewToken, nil, PWideChar(APath),
           nil, nil, false, CREATE_UNICODE_ENVIRONMENT,
           lpEnvironment, nil, si, pi) then
         begin
           CloseHandle(pi.hProcess);
           CloseHandle(pi.hThread);
         end
         else
         begin
           AppendLog('Error #19 @' + IntToStr(GetLastError));
           Exit;
         end;
       finally
         if hToken <> 0 then
           CloseHandle(hToken);
         if hNewToken <> 0 then
           CloseHandle(hNewToken);
         if lpEnvironment <> nil then
           DestroyEnvironmentBlock(lpEnvironment);
       end;
     end;


DelphiN!   (2007-09-27 11:57:00) [15]


> clickmaker ©   (27.09.07 11:51) [4]


Если служба работает под пользователем SYSTEM при попытки запустить процесс под другим пользователем через функцию CreateProcessWithLogonW функция возвращает ошибку 5 - Access Denied

из MSDN :


Windows XP SP2 and Windows Server 2003: You cannot call CreateProcessWithLogonW from a process that is running under the LocalSystem account, because the function uses the logon SID in the caller token, and the token for the LocalSystem account does not contain this SID. As an alternative, use the CreateProcessAsUser and LogonUser functions.


clickmaker   (2007-09-27 11:51:00) [16]


> CreateProcessWithLogonW из под службы к сожалению не работает

то есть?


DelphiN!   (2007-09-27 10:46:00) [17]


> Игорь Шевченко ©   (27.09.07 10:08) [2]


Не помогает

Мне необходимо запустить процесс из службы с правами пользовательского аккаунта, служба работает под пользователем SYSTEM.
 Данный способ запускает процесс из службы, под пользовательским аккаунтом (смотрел в диспетчере задач), однако у запущенного процесса нет привелегий пользовательского аккаунта, так как он как и служба не может обращаться к сетевым ресурсам(проверял на процессе у которого нет окна).
 С этим кодом бьюсь уже неделю, может быть можно как то иначе решить данную проблему? Или что мне нужно сделать с данным кодом чтобы он работал как полагается?
 CreateProcessWithLogonW из под службы к сожалению не работает

Нашел пример использования функции CreateProcessAsUser на C, однако к сожалению в С я не силен, а пример достаточно запутанный и громоздкий (

http://win32.mvps.org/security/lu_cpau_gui.cpp

Также есть пример на сайте майкрософта, однако он не меньшего размера и тоже на С.
http://msdn2.microsoft.com/en-us/library/aa379608.aspx

Нашел перевод майкросовтовского примера на Делфи, однако переведено лишь половина кода, далее сообщение обрывается (
http://www.delphikingdom.com/asp/answer.asp?IDAnswer=1899

Больше в интернете примеров на Делфи не нашел (


Игорь Шевченко   (2007-09-27 10:08:00) [18]

В startupinfo имя desktop-а прописать не поможет ?


Сергей М.   (2007-09-27 09:00:00) [19]

By default, the new process is non-interactive, that is, it runs on a desktop that is not visible and cannot receive user input.

см. Get/SetProcessWindowStation


Наверх

Титульная страница Поиск, карта сайта Написать письмо