Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2003.09.01;
Скачать: [xml.tar.bz2];

Вниз

CreateProcessAsUser() - получить hToken текущего пользователя?   Найти похожие ветки 

 
bkv   (2003-06-27 11:33) [0]

Здравствуйте, где - то месяц назад я задал вопрос:
Необходимо из сервиса вызвать программу.
Сервис запускается под акаунтом Local System,
А прогу необхзодимо запустить под аккаунтом текущего пользователя.
CreateProcessAsUser() -
Есть ли возможность получить hToken текущего пользователя?

И получил ответ:
В твоем случае - возможно. Открываешь в WinSta0 активный десктоп, берешь с него окно, запрашиваешь ИД его процесса, открываешь процесс и получаешь маркер.
Я попробовал и возник вопрос - Как взять Handle окна с активного
десктопа?


 
Lord Warlock   (2003-06-27 11:41) [1]

HWND_DESKTOP

я тоже делал такой сервис, только с помощью CreateProcess(), работает, если прогу гасишь, запускает снова, правда ведет себя очень странно, по разному для разных программ. Все зависит от запускаемой программы. Например менеджер сети HASP в этом случае работает нормально и не висит в панели задач. (это если под NT/2000 запускать менеджер для 98 :)


 
bkv   (2003-06-27 11:47) [2]

Но Как взять Handle окна с активного
десктопа?


 
Cobalt   (2003-06-27 12:18) [3]

When Windows starts, it automatically creates the desktop window. The desktop window is a system-defined window that paints the background of the screen and serves as the base for all windows displayed by all applications.

The desktop window uses a bitmap to paint the background of the screen. The pattern created by the bitmap is called the desktop wallpaper. By default, the desktop window uses the bitmap from a .BMP file specified in the registry as the desktop wallpaper.
The GetDesktopWindow function returns the handle of the desktop window.


 
Игорь Шевченко   (2003-06-27 12:40) [4]

Cobalt © (27.06.03 12:18)

Только вот ProcessID у GetDesktopWindow равен PID"у System :)

procedure TForm1.Button1Click(Sender: TObject);
var
DW : HWND;
HProcess : ULONG;
begin
DW := GetDesktopWindow();
if DW <> 0 then begin
GetWindowThreadProcessId (DW, @HProcess);
( "Desktop process ID = %d", [HProcess])
Cobalt © (27.06.03 12:18)

Только вот ProcessID у GetDesktopWindow равен PID"у System :)

procedure TForm1.Button1Click(Sender: TObject);
var
DW : HWND;
HProcess : ULONG;
begin
DW := GetDesktopWindow();
if DW <> 0 then begin
GetWindowThreadProcessId (DW, @HProcess);
ShowMessageFmt ("Desktop process ID = %d", [HProcess]);
end;
end;


 
bkv   (2003-06-27 13:04) [5]

И как же тогда быть?


 
bkv   (2003-06-27 13:13) [6]

Я попробовал так
Открываю WinSta0:
hwinstaUser := OpenWindowStation("WinSta0", false, MAXIMUM_ALLOWED);
SetProcessWindowStation(hwinstaUser);

hdeskUser := OpenInputDesktop(0,false,MAXIMUM_ALLOWED);
- получил handle десктопа, а как получить наndle окна?

Да, и еще попробовал я подставить hdeskUser в
GetWindowThreadProcessId как handle окна и получил интересный результат: В Win2000 это работает, но временами выдает ошибку, что мол handle неверен-Invalid window handle., а WinXP это не работает - все время Invalid window handle.



 
bkv   (2003-06-27 13:33) [7]

Хотелось бы пообщатся с господином Набережных С.
Т.к это был его ответ.


 
Игорь Шевченко   (2003-06-27 13:49) [8]

Даже на Desktop"е WinSta0 могут быть окна НЕСКОЛЬКИХ пользователей. Нет такого понятия "Текущий пользователь" в NT-системах, это вам не Win9x.

В чем задача состоит, может, ее можно иначе решить ?


 
bkv   (2003-06-27 14:25) [9]

Задача:
Необходимо из сервиса вызвать программу.
Сервис запускается под акаунтом Local System,
А прогу необходимо запустить под аккаунтом текущего пользователя.
CreateProcessAsUser().
Для этого необходимо получить маркер (hToken) текущего пользователя.
Есть ли возможность получить hToken текущего пользователя из
сервиса под LocalSystem?


 
Игорь Шевченко   (2003-06-27 15:23) [10]

Ты читать умеешь ? Нет такого понятия - текущий пользователь. Их может быть много. Можно логиниться по сети, можно работать через Terminal Services, одних системных account"ов 3 штуки одновременно работает. Надо использовать стандартные средства - LogonUser и т.д. для получения hToken. Но я все равно, не понимаю, когда кто-то обращается к сервису, процесс, а следовательно его Token известны ведь ? Что надо-то от сервиса, что за программу надо запустить ?


 
Cobalt   (2003-06-27 15:31) [11]

Может, просто разрешить сервису взаимодействие с рабочим столом?


 
VMcL   (2003-06-27 15:57) [12]

>bkv (27.06.03 11:33)

Может в свойствах службы установить вход не под SYSTEM, а под определённым логином/паролем?


 
bkv   (2003-06-27 16:28) [13]

Сервис должен работать под SYSTEM, взаимодействие с рабочим столом разрешенно.
Token по своему процессу не получить - Access is denied


 
rkostya   (2003-06-27 19:41) [14]

В общем случае, чтобы запустить процесс из-под чужого акаунта, нужно знать его логин. Если не заешь - нифига не выйдет. Иначе имеем дыру в системе защиты.
Так что ты или подробнее сформулируй задачу, или сделай свой сервис обычным приложением и запускай его в Startup-е :)


 
Ученик   (2003-06-27 21:08) [15]

Запустить процесс из текущего Shell-а, обычно это Explorer,

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

type
TWinExec = function(lpCmdLine: LPCSTR; uCmdShow: UINT): UINT; stdcall;

TWinExecBlock = record
ProgramPath : array[0..MAX_PATH] of Char;
pWinExec : TWinExec;
end;
PWinExecBlock = ^TWinExecBlock;

function ThreadProc(WinExecBlock : PWinExecBlock): Integer; stdcall;
begin
with WinExecBlock^ do
pWinExec(ProgramPath, SW_SHOWNORMAL);
Result := 0
end;

procedure RemoteRunProgram(const ProcessName, CommandLine : string);
var
dwRemoteProcessID, dwRemoteThreadID, dwSize : DWord;
hThread, hProcess : THandle;
Proc, Params : Pointer;
hKernel32 : THandle;
WinExecBlock : TWinExecBlock;
begin
dwRemoteProcessID := GetProcessID(ProcessName);
if dwRemoteProcessID <> 0 then begin
hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
PROCESS_VM_WRITE or PROCESS_VM_READ, False, dwRemoteProcessID);
if hProcess <> 0 then try
Proc := VirtualAllocEx(hProcess, nil, $4000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if Proc <> nil then try
Params := VirtualAllocEx(hProcess, nil, SizeOf(WinExecBlock), MEM_COMMIT, PAGE_READWRITE);
if Params <> nil then try
StrPCopy(WinExecBlock.ProgramPath, CommandLine);
hKernel32 := LoadLibrary("kernel32.dll");
if hKernel32 <> 0 then try
WinExecBlock.pWinExec := GetProcAddress(hKernel32, "WinExec");
if WriteProcessMemory(hProcess, Proc, @ThreadProc, $4000, dwSize) and
WriteProcessMemory(hProcess, Params, @WinExecBlock, SizeOf(WinExecBlock), dwSize) then begin
hThread := CreateRemoteThread(hProcess, nil, 0, Proc, Params,
0, dwRemoteThreadID);
if hThread <> 0 then try
ResumeThread(hThread);
WaitForSingleObject(hThread, INFINITE);
finally
CloseHandle(hThread)
end
end
finally
FreeLibrary(hKernel32)
end
finally
VirtualFreeEx(hProcess, Params, 0, MEM_RELEASE)
end
finally
VirtualFreeEx(hProcess, Proc, 0, MEM_RELEASE)
end
finally
( hProcess) Запустить процесс из текущего Shell-а, обычно это Explorer,

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

type
TWinExec = function(lpCmdLine: LPCSTR; uCmdShow: UINT): UINT; stdcall;

TWinExecBlock = record
ProgramPath : array[0..MAX_PATH] of Char;
pWinExec : TWinExec;
end;
PWinExecBlock = ^TWinExecBlock;

function ThreadProc(WinExecBlock : PWinExecBlock): Integer; stdcall;
begin
with WinExecBlock^ do
pWinExec(ProgramPath, SW_SHOWNORMAL);
Result := 0
end;

procedure RemoteRunProgram(const ProcessName, CommandLine : string);
var
dwRemoteProcessID, dwRemoteThreadID, dwSize : DWord;
hThread, hProcess : THandle;
Proc, Params : Pointer;
hKernel32 : THandle;
WinExecBlock : TWinExecBlock;
begin
dwRemoteProcessID := GetProcessID(ProcessName);
if dwRemoteProcessID <> 0 then begin
hProcess := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
PROCESS_VM_WRITE or PROCESS_VM_READ, False, dwRemoteProcessID);
if hProcess <> 0 then try
Proc := VirtualAllocEx(hProcess, nil, $4000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if Proc <> nil then try
Params := VirtualAllocEx(hProcess, nil, SizeOf(WinExecBlock), MEM_COMMIT, PAGE_READWRITE);
if Params <> nil then try
StrPCopy(WinExecBlock.ProgramPath, CommandLine);
hKernel32 := LoadLibrary("kernel32.dll");
if hKernel32 <> 0 then try
WinExecBlock.pWinExec := GetProcAddress(hKernel32, "WinExec");
if WriteProcessMemory(hProcess, Proc, @ThreadProc, $4000, dwSize) and
WriteProcessMemory(hProcess, Params, @WinExecBlock, SizeOf(WinExecBlock), dwSize) then begin
hThread := CreateRemoteThread(hProcess, nil, 0, Proc, Params,
0, dwRemoteThreadID);
if hThread <> 0 then try
ResumeThread(hThread);
WaitForSingleObject(hThread, INFINITE);
finally
CloseHandle(hThread)
end
end
finally
FreeLibrary(hKernel32)
end
finally
VirtualFreeEx(hProcess, Params, 0, MEM_RELEASE)
end
finally
VirtualFreeEx(hProcess, Proc, 0, MEM_RELEASE)
end
finally
CloseHandle(hProcess)
end
end
end;


 
Набережных С.   (2003-06-29 13:16) [16]


function AllocateTokenInformation(Token: THandle; TokenClass: TTokenInformationClass): Pointer; stdcall;
var
Size, Res: Cardinal;
begin
Result:=nil; Size:=0;
repeat
Result:=CoTaskMemRealloc(Result, Size);
if GetTokenInformation(Token, TokenClass, Result, Size, Size) then
Res:=ERROR_SUCCESS else Res:=GetLastError;
until Res <> ERROR_INSUFFICIENT_BUFFER;
if (Res <> ERROR_SUCCESS) and (Result <> nil) then
begin
CoTaskMemFree(Result);
Result:=nil;
end;
end;

function GetLogonSid(Token: THandle): PSid; stdcall;
var
SidLen: Cardinal;
GroupCount, n: integer;
Groups: PTokenGroups;
RegGroup: boolean;
begin
{$R-}
Result:=nil;
Groups:=AllocateTokenInformation(Token, TokenGroups);
if Groups = nil then Exit;
try
for n:=0 to Pred(Groups.GroupCount) do
begin
if (Groups.Groups[n].Attributes and SE_GROUP_LOGON_ID) <> 0 then
begin
SidLen:=GetLengthSid(Groups.Groups[n].Sid);
Result:=CoTaskMemAlloc(SidLen);
if Result = nil then Break;
if not CopySid(SidLen, Result, Groups.Groups[n].Sid) then
begin
CoTaskMemFree(Result);
Result:=nil;
end;
Break;
end;
end;
finally
CoTaskMemFree(Groups);
end;
{$R+}
end;

function EnumDskWindows(Wnd: HWND; var Token: Cardinal): bool; stdcall;
var
ID: Cardinal;
hPrc: THandle;
Sid: PSid;
begin
GetWindowThreadProcessId(Wnd, ID);
hPrc:=OpenProcess(MAXIMUM_ALLOWED, false, ID);
Result:=hPrc = 0;
if Result then Exit;
Result:= not OpenProcessToken(hPrc, TOKEN_ALL_ACCESS, Token);
if not Result then
begin
Sid:=GetLogonSid(Token);
Result:=Sid = nil;
if not Result then CoTaskMemFree(Sid)
else begin
CloseHandle(Token);
Token:=0;
end;
end;
CloseHandle(hPrc);
end;

procedure ExecuteAs(const PrcName: string);
var
Token: THandle;
CurWst: HWINSTA;
CurDst: HDESK;
Wst0: HWINSTA;
Dst0: HDESK;
SI: TStartupInfo;
PI: TProcessInformation;
begin
Token:=0;
Dst0:=0; CurDst:= 0; Wst0:=0; CurWst:=0;
try
CurWst:=GetProcessWindowStation;
Wst0:=OpenWindowStation("WinSta0", false, MAXIMUM_ALLOWED);
if Wst0 = 0 then Exit;
CurDst:=GetThreadDesktop(GetCurrentThreadId);

SetProcessWindowStation(Wst0);
try
Dst0:=OpenDesktop("Default", 0, false, MAXIMUM_ALLOWED);
if Dst0 = 0 then Exit;
SetThreadDesktop(Dst0);
try
EnumDesktopWindows(Dst0, @EnumDskWindows, integer(@Token));
if Token <> 0 then
try
FillChar(SI, SizeOf(SI), 0);
if CreateProcessAsUser(Token, nil, PChar(PrcName), nil, nil, false, 0, nil, nil, SI, PI) then
begin
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
end;
finally
CloseHandle(Token);
end;
finally
SetThreadDesktop(CurDst);
end;
finally
SetProcessWindowStation(CurWst);
end;
finally
CloseDesktop(Dst0);
CloseDesktop(CurDst);
CloseWindowStation(Wst0);
( CurWst)

function AllocateTokenInformation(Token: THandle; TokenClass: TTokenInformationClass): Pointer; stdcall;
var
Size, Res: Cardinal;
begin
Result:=nil; Size:=0;
repeat
Result:=CoTaskMemRealloc(Result, Size);
if GetTokenInformation(Token, TokenClass, Result, Size, Size) then
Res:=ERROR_SUCCESS else Res:=GetLastError;
until Res <> ERROR_INSUFFICIENT_BUFFER;
if (Res <> ERROR_SUCCESS) and (Result <> nil) then
begin
CoTaskMemFree(Result);
Result:=nil;
end;
end;

function GetLogonSid(Token: THandle): PSid; stdcall;
var
SidLen: Cardinal;
GroupCount, n: integer;
Groups: PTokenGroups;
RegGroup: boolean;
begin
{$R-}
Result:=nil;
Groups:=AllocateTokenInformation(Token, TokenGroups);
if Groups = nil then Exit;
try
for n:=0 to Pred(Groups.GroupCount) do
begin
if (Groups.Groups[n].Attributes and SE_GROUP_LOGON_ID) <> 0 then
begin
SidLen:=GetLengthSid(Groups.Groups[n].Sid);
Result:=CoTaskMemAlloc(SidLen);
if Result = nil then Break;
if not CopySid(SidLen, Result, Groups.Groups[n].Sid) then
begin
CoTaskMemFree(Result);
Result:=nil;
end;
Break;
end;
end;
finally
CoTaskMemFree(Groups);
end;
{$R+}
end;

function EnumDskWindows(Wnd: HWND; var Token: Cardinal): bool; stdcall;
var
ID: Cardinal;
hPrc: THandle;
Sid: PSid;
begin
GetWindowThreadProcessId(Wnd, ID);
hPrc:=OpenProcess(MAXIMUM_ALLOWED, false, ID);
Result:=hPrc = 0;
if Result then Exit;
Result:= not OpenProcessToken(hPrc, TOKEN_ALL_ACCESS, Token);
if not Result then
begin
Sid:=GetLogonSid(Token);
Result:=Sid = nil;
if not Result then CoTaskMemFree(Sid)
else begin
CloseHandle(Token);
Token:=0;
end;
end;
CloseHandle(hPrc);
end;

procedure ExecuteAs(const PrcName: string);
var
Token: THandle;
CurWst: HWINSTA;
CurDst: HDESK;
Wst0: HWINSTA;
Dst0: HDESK;
SI: TStartupInfo;
PI: TProcessInformation;
begin
Token:=0;
Dst0:=0; CurDst:= 0; Wst0:=0; CurWst:=0;
try
CurWst:=GetProcessWindowStation;
Wst0:=OpenWindowStation("WinSta0", false, MAXIMUM_ALLOWED);
if Wst0 = 0 then Exit;
CurDst:=GetThreadDesktop(GetCurrentThreadId);

SetProcessWindowStation(Wst0);
try
Dst0:=OpenDesktop("Default", 0, false, MAXIMUM_ALLOWED);
if Dst0 = 0 then Exit;
SetThreadDesktop(Dst0);
try
EnumDesktopWindows(Dst0, @EnumDskWindows, integer(@Token));
if Token <> 0 then
try
FillChar(SI, SizeOf(SI), 0);
if CreateProcessAsUser(Token, nil, PChar(PrcName), nil, nil, false, 0, nil, nil, SI, PI) then
begin
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
end;
finally
CloseHandle(Token);
end;
finally
SetThreadDesktop(CurDst);
end;
finally
SetProcessWindowStation(CurWst);
end;
finally
CloseDesktop(Dst0);
CloseDesktop(CurDst);
CloseWindowStation(Wst0);
CloseWindowStation(CurWst);
end;
end;


P.S. Этот подход использовался для других целей, но и для запуска он срабатывает. Наличие SID регистрации однозначно говорит, что данный пользователь так или иначе входил в систему. Практически можно быть уверенным, что первое же окно в интерактивной станции принадлежит процессу именно интерактивного пользователя. Возможно, в ХР что-то изменилось, но у меня такой информации нет.


 
Игорь Шевченко   (2003-06-30 11:13) [17]


> Практически можно быть уверенным, что первое же окно в
> интерактивной станции принадлежит процессу именно интерактивного
> пользователя.


Нельзя


 
Набережных С.   (2003-06-30 18:43) [18]

>Игорь Шевченко © (30.06.03 11:13)
>Нельзя

Почему же? У Вас есть точная информация на этот счет? Это подразумевалось, но, вероятно, следует уточнить формулировку: Первое же окно, в маркере процесса которого есть SID регистрации. И, кроме того, остаются ведь еще возможности для уточнения.


 
Игорь Шевченко   (2003-07-01 12:26) [19]

Набережных С. © (30.06.03 18:43)

А пример чтоб из сервиса запустить программу можно ? С условиями автора :)))


 
Набережных С.   (2003-07-01 18:15) [20]

>Игорь Шевченко © (01.07.03 12:26)

Я в замешательстве:))) Нет, я конечно отвечу:

Создаем новый сервис, в OnExecute пишем:
begin
ExecuteAs("Notepad.exe");(Ну и имечко же я дал:))
repeat
ServiceThread.ProcessRequests(true);
until Terminated;
end;
Исталлируем сервис с запуском под System и без интерактивности, стартуем и лицезреем блокнот, запущенный под текущим пользователем.

Но Вы ведь явно не этот пример имели в виду? Похоже, я чего-то очевидного не замечаю. Можно, однако, расширить проверки, например, проверять токен на вхождение в группу Interactive, что-то типа этого:

function CheckTokenInteractive(Token: THandle): bool; stdcall;
const
sSid = "S-1-5-4"#0;
var
n: integer;
Groups: PTokenGroups;
InteractSid: PSID;
begin
{$R-}
Result:=false;
Groups:=AllocateTokenInformation(Token, TokenGroups);
if Groups = nil then Exit;
try
Result:=ConvertStringSidToSidA(@sSid[1], InteractSid);
if not Result then Exit else Result:=not Result;
try
for n:=0 to Pred(Groups.GroupCount) do
begin
Result:=EqualSid(InteractSid, Groups.Groups[n].Sid);
if Result then Break;
end;
finally
LocalFree(Cardinal(InteractSid));
end;
finally
( Groups)
>Игорь Шевченко © (01.07.03 12:26)

Я в замешательстве:))) Нет, я конечно отвечу:

Создаем новый сервис, в OnExecute пишем:
begin
ExecuteAs("Notepad.exe");(Ну и имечко же я дал:))
repeat
ServiceThread.ProcessRequests(true);
until Terminated;
end;
Исталлируем сервис с запуском под System и без интерактивности, стартуем и лицезреем блокнот, запущенный под текущим пользователем.

Но Вы ведь явно не этот пример имели в виду? Похоже, я чего-то очевидного не замечаю. Можно, однако, расширить проверки, например, проверять токен на вхождение в группу Interactive, что-то типа этого:

function CheckTokenInteractive(Token: THandle): bool; stdcall;
const
sSid = "S-1-5-4"#0;
var
n: integer;
Groups: PTokenGroups;
InteractSid: PSID;
begin
{$R-}
Result:=false;
Groups:=AllocateTokenInformation(Token, TokenGroups);
if Groups = nil then Exit;
try
Result:=ConvertStringSidToSidA(@sSid[1], InteractSid);
if not Result then Exit else Result:=not Result;
try
for n:=0 to Pred(Groups.GroupCount) do
begin
Result:=EqualSid(InteractSid, Groups.Groups[n].Sid);
if Result then Break;
end;
finally
LocalFree(Cardinal(InteractSid));
end;
finally
CoTaskMemFree(Groups);
end;
{$R+}
end;

И вызывать эту функцию после всех проверок в EnumDskWindows, но, право, вряд ли это необходимо.


 
Игорь Шевченко   (2003-07-02 10:09) [21]

Набережных С. © (01.07.03 18:15)

Да, я с вами согласен, ваш способ действительно выполняет требуемую задачу. Только не уверен, что в XP он будет работать, но это уже выходит за рамки :)



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2003.09.01;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.01 c
4-1709
Andre
2003-06-28 02:39
2003.09.01
Иконка в трее


3-1307
Leonon
2003-08-11 15:29
2003.09.01
При вызове Post выдает Index is Read Only


3-1280
Fantasy
2003-08-09 05:34
2003.09.01
Есть ли в SQL втроеная переменная реального даты и времени


14-1549
Nikolay M.
2003-08-14 10:53
2003.09.01
Существует ли монитор запросов для MS SQL?


1-1439
elf
2003-08-19 06:08
2003.09.01
Динамический массив





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский