Форум: "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