主页
Top.Mail.Ru Yandeks.Metrika
论坛:“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,

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

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

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

function ThreadProc(WinExecBlock : PWinExecBlock): Integer; stdcall;
开始
with WinExecBlock^ do
pWinExec(ProgramPath, SW_SHOWNORMAL);
结果:= 0
结束;

procedure RemoteRunProgram(const ProcessName, CommandLine : string);
VAR
dwRemoteProcessID, dwRemoteThreadID, dwSize : DWord;
hThread, hProcess : THandle;
Proc, Params : Pointer;
hKernel32 : THandle;
WinExecBlock : TWinExecBlock;
开始
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);
最后
CloseHandle(hThread)
结束
结束
最后
FreeLibrary(hKernel32)
结束
最后
VirtualFreeEx(hProcess, Params, 0, MEM_RELEASE)
结束
最后
VirtualFreeEx(hProcess, Proc, 0, MEM_RELEASE)
结束
最后
( hProcess) Запустить процесс из текущего Shell-а, обычно это Explorer,

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

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

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

function ThreadProc(WinExecBlock : PWinExecBlock): Integer; stdcall;
开始
with WinExecBlock^ do
pWinExec(ProgramPath, SW_SHOWNORMAL);
结果:= 0
结束;

procedure RemoteRunProgram(const ProcessName, CommandLine : string);
VAR
dwRemoteProcessID, dwRemoteThreadID, dwSize : DWord;
hThread, hProcess : THandle;
Proc, Params : Pointer;
hKernel32 : THandle;
WinExecBlock : TWinExecBlock;
开始
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);
最后
CloseHandle(hThread)
结束
结束
最后
FreeLibrary(hKernel32)
结束
最后
VirtualFreeEx(hProcess, Params, 0, MEM_RELEASE)
结束
最后
VirtualFreeEx(hProcess, Proc, 0, MEM_RELEASE)
结束
最后
CloseHandle(hProcess)
结束
结束
结束;



Набережных С.   (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]

> Igor Shevchenko©(30.06.03 11:13)
>Нельзя

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



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

Naberezhnykh S.©(30.06.03 18:43)

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



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

> Igor Shevchenko©(01.07.03 12:26)

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

Создаем новый сервис, в OnExecute пишем:
开始
ExecuteAs("Notepad.exe");(Ну и имечко же я дал:))
重复
ServiceThread.ProcessRequests(true);
直到终止
结束;
Исталлируем сервис с запуском под 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]

Naberezhnykh S.©(01.07.03 18:15)

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



Страницы: 1 整个分支

论坛:“WinAPI”;
当前存档:2003.09.01;
下载:[xml.tar.bz2];

楼上









内存:0.68 MB
时间:0.065 c
3-1317
长Renat
2003-08-08 11:11
2003.09.01
执行SQL命令时出错


1-1392
FEV
2003-08-16 09:28
2003.09.01
字母和数字


4-1732
海豚!
2003-06-30 07:58
2003.09.01
如何保持滚动条位置?


8-1516
法案
2003-04-10 14:56
2003.09.01
丢失画布


7-1691
雷沃
2003-06-17 14:53
2003.09.01
ISA + NT





南非荷兰语 阿尔巴尼亚人 阿拉伯语 亚美尼亚 阿塞拜疆 巴斯克 白俄罗斯 保加利亚语 加泰罗尼亚 简体中文 中国(繁体) 克罗地亚 捷克 丹麦语 荷兰人 英语 爱沙尼亚语 菲律宾人 芬兰 法文
加利亚西语 格鲁吉亚语 德语 希腊语 海地克里奥尔语 希伯来语 印地语 匈牙利 北日耳曼语 印度尼西亚人 爱尔兰语 意大利语 日本性玩偶 韩语 拉脱维亚 立陶宛 马其顿 马来语 马耳他语 挪威语
波斯语 波兰语 葡萄牙语 罗马尼亚 俄语 塞尔维亚 斯洛伐克 斯洛文尼亚 西班牙语 斯瓦希里 瑞典语 泰国人 土耳其 乌克兰 乌尔都语 越南人 威尔士语 意第绪语 孟加拉 波斯尼亚
宿务 世界语 古吉拉特语 豪萨语 苗族 伊博 爪哇 卡纳达语 高棉 老挝 拉丁语 毛利 马拉 蒙古人 尼泊尔 旁遮普 索马里 泰米尔人 泰卢固语 约鲁巴语
祖鲁
英文 Французский Немецкий Итальянский Португальский 俄文 Испанский