Здравствуйте, Аноним, Вы писали:
А>>ЛЕГКО — но пока сам не пробовал
SH>Но раз уж такое дело, сегодня вечером попробую, о результатах доложу.
Очень коротко о результатах: работает.
Коротко о результатах:
0. Написал некое UI
примерно такая основная рабочая функция:
void Work::Run()
{
if (!IsInteractive())
{
MessageBox(NULL, TEXT("Not interactive!"), TEXT("TrayService"), MB_OK | MB_SERVICE_NOTIFICATION);
if (!MakeInteractive())
{
MessageBox(NULL, TEXT("Sevice yet is not interactive! It can not work normal."), TEXT("TrayService"), MB_OK | MB_SERVICE_NOTIFICATION);
StdServFunc::FatalError(NO_ERROR, 0);
return;
}
}
HWND hwnd = CreateDialog(
GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG),
NULL,
DlgProc);
ShowWindow(hwnd, SW_SHOWNORMAL);
for (;;)
{
DWORD res = MsgWaitForMultipleObjects(1, &hEndEvent, FALSE, INFINITE, QS_ALLEVENTS);
if (res == WAIT_OBJECT_0)
{
// событие hEndEvent - кончаем работать
PostMessage(hwnd, WM_COMMAND, IDCANCEL, 0);
}
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
StdServFunc::FatalError(NO_ERROR, 0);
}
и такая диалоговая функция
BOOL CALLBACK Work::DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static int time = 130;
NOTIFYICONDATA data = {0};
data.cbSize = sizeof(data);
data.hWnd = hwnd;
data.uID = 1;
switch (uMsg)
{
case WM_INITDIALOG:
data.uFlags = NIF_ICON | NIF_MESSAGE;
data.uCallbackMessage = WM_USER + 200;
data.hIcon = LoadIcon(NULL, IDI_HAND);
Shell_NotifyIcon(NIM_ADD, &data);
break;
case WM_COMMAND:
if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hwnd, 0);
Shell_NotifyIcon(NIM_DELETE, &data);
return TRUE;
}
break;
}
return FALSE;
}
1. написал функцию IsInteractive. Без проверок на ошибки она выглядит так:
bool IsInteractive()
{
SC_HANDLE hSCM;
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
SC_HANDLE hService;
hService = OpenService(hSCM, ServiceName, SERVICE_QUERY_CONFIG);
DWORD need = 0;
QueryServiceConfig(hService, NULL, 0, &need);
QUERY_SERVICE_CONFIG* pConfig = (QUERY_SERVICE_CONFIG*) malloc(need);
QueryServiceConfig(hService, pConfig, need, &need);
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
DWORD type = pConfig->dwServiceType;
free(pConfig);
return (type & SERVICE_INTERACTIVE_PROCESS);
}
2. Написал функцию MakeInteractive. Сначала она выглядела так:
bool MakeInteractive()
{
HWINSTA hWinSta0 = OpenWindowStation(L"WinSta0", FALSE, WINSTA_READSCREEN);
if (!hWinSta0)
{
return false;
}
SetProcessWindowStation(hWinSta0);
CloseWindowStation(hWinSta0);
HDESK hDefault = OpenDesktop(L"Default", 0, FALSE, DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU);
if (!hDefault)
{
return false;
}
SetThreadDesktop(hDefault);
CloseDesktop(hDefault);
return true;
}
3. Неинтерактивная служба, но запущенная под LocalSystem пробивается к десктопу на ура.
4. Неинтерактивная служба, запущенная под админом не может открыть оконную станцию.
5. Немного подумав переписал MakeInteractive так:
bool MakeInteractive()
{
HWINSTA hWinSta0 = OpenWindowStation(L"WinSta0", FALSE, WINSTA_READSCREEN);
if (!hWinSta0)
{
if (GetLastError() != ERROR_ACCESS_DENIED)
{
return false;
}
// Включаем привелегию SE_TAKE_OWNERSHIP_NAME
EnableTakeOwnershipName();
hWinSta0 = OpenWindowStation(L"WinSta0", FALSE, WRITE_OWNER);
if (hWinSta0)
{
// Делаем текущего пользователя владельцем. Этот этап
// не критичен, критичен следующий, поэтому здесь
// ошибки не проверяем.
SetUserObjectOwner(hWinSta0);
CloseWindowStation(hWinSta0);
}
hWinSta0 = OpenWindowStation(L"WinSta0", FALSE, WRITE_DAC | READ_CONTROL);
if (!hWinSta0)
{
return false;
}
// Даём текущему пользователю доступ. Я поступил радикально - обнулил DACL :)
if (!SetUserObjectAccess(hWinSta0))
{
CloseWindowStation(hWinSta0);
return false;
}
CloseWindowStation(hWinSta0);
hWinSta0 = OpenWindowStation(L"WinSta0", FALSE, WINSTA_READSCREEN);
if (!hWinSta0)
{
return false;
}
}
SetProcessWindowStation(hWinSta0);
CloseWindowStation(hWinSta0);
HDESK hDefault = OpenDesktop(L"Default", 0, FALSE, DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU);
if (!hDefault)
{
return false;
}
SetThreadDesktop(hDefault);
CloseDesktop(hDefault);
return true;
}
Код функций
bool EnableTakeOwnershipName();
bool SetUserObjectOwner(HANDLE hUser);
bool SetUserObjectAccess(HANDLE hUser);
не привожу, он довольно прост. Из под админа теперь работает.
Ну что я могу сказать — спасибо тебе, добрый человек! Наконец-то я начал потихоньку трахаться с security...