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

Вниз

Как достоверно определить что программа запущена как сервис?   Найти похожие ветки 

 
SPeller ©   (2009-04-15 09:15) [0]

Был откуда-то у меня пример, но он вытаскивает имя юзера, с которым сервис запускается, и сравнивает его с именем, под которым запущен процесс. Совпало - типа мы сервис. Но одинаковый юзер еще не означает того, что наш процесс - сервис. Сервис может быть запущен от имени другой учетки, поэтому данный метод отпадает. Каким образом определить что процесс запущен сервис-менеджером, а не кем-то другим?


 
12 ©   (2009-04-15 09:30) [1]

http://forum.sources.ru/index.php?showtopic=209024
может это поможет?


 
Palladin ©   (2009-04-15 09:31) [2]


> Каким образом определить что процесс запущен сервис-менеджером,
>  а не кем-то другим

Ты что, думаешь, что если я зайду в консоль управления и запущу сервис, он от моего имени запустится?


 
SPeller ©   (2009-04-15 09:36) [3]


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

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


 
SPeller ©   (2009-04-15 09:42) [4]


> Ты что, думаешь, что если я зайду в консоль управления и
> запущу сервис, он от моего имени запустится?

В настройках сервиса можно прописать любую учетку, под которой запускается сервис. Хоть под гостем запускать. И это будут совсем разные вещи, будет ожидаться совсем разное поведение программы, нежели если этот гость как-то сам запустит программу. Вот в чем дело.


 
Palladin ©   (2009-04-15 09:58) [5]


> SPeller ©   (15.04.09 09:42) [4]
> В настройках сервиса можно прописать любую учетку, под которой
> запускается сервис.

И что? Запускатся он будет в любом случае сервис манагером. Тебе в самом сервисе нужно определять под чьей учеткой он запущен, а не определять откуда сервис запущен. Короче не путай теплое с мягким!


 
Anatoly Podgoretsky ©   (2009-04-15 10:02) [6]

> Palladin  (15.04.2009 9:31:02)  [2]

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


 
KSergey ©   (2009-04-15 10:04) [7]

Если я ничего не путаю, то при запуске "как сервис" программа получает спец. параметры (или из нее спец. call-back"и дергаются? совершенно забыл).
А потому вопрос не понятен: прога если сервис - запускается совершенно определенным образом.

PS
под рукой нет где глянуть быстро, но надеюсь, что не вру


 
SPeller ©   (2009-04-15 10:06) [8]


> И что? Запускатся он будет в любом случае сервис манагером

Ты не понял :) Юзер может, например, в проводнике взять и запустить ЕХЕ с сервисом. И будет не то что надо )

Для чего это всё: пишу сервис, который должен работать строго под отведенной ему учеткой. Но для отладки нужно чтобы он мог запускаться и как сервис и как обычная программа, немного корректируя при этом внутреннюю логику. В последствии, когда дело приблизится к концу, нужно будет вообще запретить запуск иной кроме как сервисом.


 
SPeller ©   (2009-04-15 10:08) [9]


> KSergey ©   (15.04.09 10:04) [7]

Никаких параметров не получает. Процесс регистрирует callback через RegisterServiceCtrlHandler.


 
sniknik ©   (2009-04-15 10:09) [10]

> Тебе в самом сервисе нужно определять под чьей учеткой он запущен, а не определять откуда сервис запущен.
а как тогда с вариантом если его запускают как программу? учетки не показатель, т.к. возможен запуск от любой, единственный вариант разделить это узнать кто (откуда) программу запускал.
т.е. "откуда сервис запущен" как раз определяет будет ли это сервис или программа.

речь идет о разделении, и соответственно ветвлении кода в зависимости от того как программу стартуют, как сервис или как программу.
для примера можно посмотреть scktsrvr.exe (есть исходники) в дельфе, речь идет о их способе определения (о том что он не всегда правильно определит).
> Был откуда-то у меня пример
оттуда наверняка.


 
sniknik ©   (2009-04-15 10:11) [11]

> SPeller ©
а ссылка не помогла? как раз если запускает сервис менеджер (родительский процесс) то это показатель.


 
Palladin ©   (2009-04-15 10:14) [12]

тьфу блин... ну так разделяй понятия сервис и приложение.... запутал совсем... )


 
SPeller ©   (2009-04-15 10:19) [13]


> а ссылка не помогла?

Разбираюсь в коде. Похоже, что проверки на имя процесса services.exe и на статус SERVICE_START_PENDING должно хватить.


 
SPeller ©   (2009-04-15 10:25) [14]

В приведенной ссылке смущает только красная надпись из msdn:
[ZwQuerySystemInformation may be altered or unavailable in subsequent versions of Windows. Applications should use the alternate functions listed in this topic.]


 
SPeller ©   (2009-04-15 10:28) [15]

А еще тот момент, что по ссылке приведено развернутое описание структуры SYSTEM_PROCESS_INFORMATION, тогда как msdn от 2008-й студии гораздо более скуден в плане информации об этой структуре:

typedef struct _SYSTEM_PROCESS_INFORMATION {
   ULONG NextEntryOffset;
   ULONG NumberOfThreads;
   BYTE Reserved1[48];
   PVOID Reserved2[3];
   HANDLE UniqueProcessId;
   PVOID Reserved3;
   ULONG HandleCount;
   BYTE Reserved4[4];
   PVOID Reserved5[11];
   SIZE_T PeakPagefileUsage;
   SIZE_T PrivatePageCount;
   LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION;


 
Anatoly Podgoretsky ©   (2009-04-15 11:22) [16]

> SPeller  (15.04.2009 10:06:08)  [8]

Тогда и нечего голову ломать. Просто закончить отладку.


 
SPeller ©   (2009-04-15 11:30) [17]

Вот бы еще из-под ограниченного аккаунта получить полное имя файла родительского процесса с путем. А то GetModuleFileNameEx хочет права, которых нет:

The handle must have the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights


 
SPeller ©   (2009-04-15 11:34) [18]


> Anatoly Podgoretsky ©   (15.04.09 11:22) [16]

Это не последний мой сервис :) Нужны наработки чтобы в будущем легко с ними обращаться.


 
SPeller ©   (2009-04-15 12:05) [19]

Вобщем, получился такой код. Интересует критика

function GetProcessParentID: Cardinal;
var
 ProcEntry: TProcessEntry32;
 hSnapshot: THandle;
 CurrID: Cardinal;
 Success: Boolean;
begin
 Result := 0;
 hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 if (hSnapshot <> INVALID_HANDLE_VALUE) then
   try
     ProcEntry.dwSize := SizeOf(ProcEntry);
     Success := Process32First(hSnapshot, ProcEntry);
     if Success then
     begin
       CurrID := GetCurrentProcessId;
       SetLastError(ERROR_SUCCESS);
       while Success do
         if (ProcEntry.th32ProcessID = CurrID) then
         begin
           Result := ProcEntry.th32ParentProcessID;
           Break;
         end
         else
           Success := Process32Next(hSnapshot, ProcEntry);
     end;
     Win32Check(GetLastError);
   finally
     CloseHandle(hSnapshot);
   end
 else
   Win32Check(GetLastError);
end;

function GetProcessParentName: string;
var
 ProcEntry: TProcessEntry32;
 hSnapshot: THandle;
 Success: Boolean;
 ParentPID: Cardinal;
begin
 Result := "";
 hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 if (hSnapshot <> INVALID_HANDLE_VALUE) then
   try
     ProcEntry.dwSize := SizeOf(ProcEntry);
     Success := Process32First(hSnapshot, ProcEntry);
     if Success then
     begin
       ParentPID := GetProcessParentID;
       SetLastError(ERROR_SUCCESS);
       while Success do
         if (ProcEntry.th32ProcessID = ParentPID) then
         begin
           Result := ProcEntry.szExeFile;
           Break;
         end
         else
           Success := Process32Next(hSnapshot, ProcEntry);
     end;
     Win32Check(GetLastError);
   finally
     CloseHandle(hSnapshot);
   end
 else
   Win32Check(GetLastError);
end;

function GetStartingAsService(const SrvName: string): Boolean;
var
 Mgr, Svc: Integer;
 SSBuf: PServiceStatus;
 SSBufSz: Cardinal;
 SvcState: Cardinal;
begin
 Result := False;
 // То что мы сервис - еще не значит что мы запущены с правами SYSTEM! Поэтому запрашиваем только право чтения
 Mgr := OpenSCManager(nil, nil, GENERIC_READ);
 if (Mgr <> 0) then
 begin
   // Аналогично. Будем только читать
   Svc := OpenService(Mgr, PChar(SrvName), GENERIC_READ);
   Result := (Svc <> 0);
   if Result then
   begin
     QueryServiceStatusEx2(Svc, SC_STATUS_PROCESS_INFO, nil, 0, SSBufSz);
     GetMem(SSBuf, SSBufSz);
     QueryServiceStatusEx2(Svc, SC_STATUS_PROCESS_INFO, SSBuf, SSBufSz, SSbufSz);
     SvcState := SSBuf.dwCurrentState;
     FreeMem(SSBuf);
     Result :=
       (SvcState = SERVICE_START_PENDING) and
       AnsiSameText(GetProcessParentName, "services.exe");

     CloseServiceHandle(Svc);
   end;
   CloseServiceHandle(Mgr);
 end;
end;

procedure Win32Check(ErrorCode: Cardinal);
begin
 if (ErrorCode <> ERROR_SUCCESS) then
   raise Win32Exception.Create(SysErrorMessage(ErrorCode));
end;


Кстати, нашел багу в д2009 в объявлении функции QueryServiceStatusEx: последний параметр не должен быть указателем. Поэтому в тексте у меня QueryServiceStatusEx2, определенная как должно быть.


 
KSergey ©   (2009-04-15 12:18) [20]

> SPeller ©   (15.04.09 10:08) [9]
> Никаких параметров не получает. Процесс регистрирует callback через RegisterServiceCtrlHandler.

Ну так я о чем и толкую: запустили - оно регистрирует свой call-back да и все. И ничем кроме сервиса быть не может по определению.
А если нужна отладка - то телается распознавание ключика /d - по нему вместо регистрации call-back передается управление в основную функцию обработки с выставлением флажка "запустили как консольку", в этом случае в консольку можно смело лог, например, писать. Вот и все.
Зачем родительсткие процессы шукать - мне не ясно.


 
Anatoly Podgoretsky ©   (2009-04-15 13:11) [21]

> SPeller  (15.04.2009 11:34:18)  [18]

Можно попытаться передавать в строке запуска ключ.
Это если не изучать работу с сервисами и менеджером служб


 
sniknik ©   (2009-04-15 13:12) [22]

> Вобщем, получился такой код. Интересует критика
тебе за построчно платят? тогда все замечательно, отлично просто. но вообще там Rouse_ предлагал более компактный, наглядный вариант, который ничего не стоит переделать...
вот в это например

function ParentProcName: string;
const
 ProcessBasicInformation = 0;
var
 Info: PROCESS_BASIC_INFORMATION;
 dwProcessHandle: dword;
 ProcessName: string;
 Hndl: THandle;
begin
 Result:= "noname";
 dwProcessHandle:= GetCurrentProcess;
 if NtQueryInformationProcess(dwProcessHandle, ProcessBasicInformation, @Info, SizeOf(Info), nil) = NO_ERROR
   then begin
     Hndl:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, Info.uInheritedFromUniqueProcessId);
     if Hndl <> 0 then
       try
         SetLength(ProcessName, MAX_PATH);
         if GetModuleBaseNameA(Hndl, 0, PChar(ProcessName), MAX_PATH) > 0
           then Result:= PChar(ProcessName);
       finally
         CloseHandle(Hndl);
       end;
   end;
end;


это заменяет две трети твоего кода.

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


 
SPeller ©   (2009-04-16 03:35) [23]


> запустили - оно регистрирует свой call-back да и все. И
> ничем кроме сервиса быть не может по определению

Может :) Сервис - это тот же самый процесс, и ничем не отличается от обычного процесса кроме того, что запускается и управляется системным менеджером.


> тебе за построчно платят? тогда все замечательно, отлично
> просто. но вообще там Rouse_ предлагал более компактный,
>  наглядный вариант, который ничего не стоит переделать..

См пост 14 и 15. Если msdn красным не рекомендует использовать - значит нафик. Сегодня работает, завтра не известно будет или нет. Админы поставят 2008-й сервак, а там кто даст гарантию что будет работать? Если бы это было поделкой для своих личных нужд - без проблем. А когда этот софт делается для работы - то лучше избавить себя от потенциальных ошибок в будущем. Имхо.


 
SPeller ©   (2009-04-16 03:59) [24]


> это заменяет две трети твоего кода

Так то оно так, но помимо красных предупреждений по поводу NtQueryInformationProcess, есть еще один момент, который я тоже упоминал:

The handle must have the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights

Это и к GetModuleFileNameEx  относится, и к GetModuleBaseName. Взгляни в msdn, если не веришь. А сервис, напомню, не обязан иметь указанные права, поскольку может быть запущен от имени любого пользователя.


 
sniknik ©   (2009-04-16 10:25) [25]

> Если msdn красным не рекомендует использовать - значит нафик.
не вижу красного
http://msdn.microsoft.com/en-us/library/ms684280(VS.85).aspx

> The handle must have the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights
именно поэтому они здесь и запрашиваются
Hndl:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, Info.uInheritedFromUniqueProcessId)
потому, что handle должен их иметь...

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

вообще права на чтение инфы, имхо, есть даже у гостя... проверь, запусти свой сервис под юзером с правами гостя... в вариантах без этого кода/с ним.
кстати а на снепшот процессов права на чтения их инфы разве не нужны? он же тоже ее читает.

> поскольку может быть запущен от имени любого пользователя.
вообще то по логике не может... сервис сам по себе для своего обслуживания должен иметь кое какие права... и они, имхо, больше чем требуется чтобы прочитать имя модуля.


 
SPeller ©   (2009-04-17 02:31) [26]


> не вижу красного
Там оно не красным, а черным. В локальной версии - красным выделена строка may be altered or unavailable in future versions of Windows. Разве этого не достаточно чтобы опасаться воплощения в жизнь обещания "may be altered or unavailable"? Да и поля uInheritedFromUniqueProcessId в структуре PROCESS_BASIC_INFORMATION даже в самой свежей, онлайн версии msdn, нет. Изменит там что-то мелкософт, а пинать-то за ошибки в программе будут меня )


> именно поэтому они здесь и запрашиваются
И именно из-за ограниченности прав юзверя OpenProcess возвращает Access denied при попытке открыть родительский процесс.


> там запрашивается инфа о собственном процессе
Зачем мне собственный? Мне родительский нужен. PID я получу родительского, а вот имя файла родительского процесса - только через ToolHelp, который работает из-под ограниченной учетки.


 
SPeller ©   (2009-04-17 02:36) [27]


> проверь, запусти свой сервис под юзером с правами гостя
Я это с самого начала и делал :) Правда, не под гостем, а под специальной учеткой, которая состоит в группе пользователей. Права на функции Nt/ZwХХХ не проверял, а вот на GetModuleFileNameEx и GetModuleBaseName споткнулся сразу. Через снапшот всё получилось без вопросов.


 
SPeller ©   (2009-04-17 02:39) [28]

Кстати, работаю тут еще с правами. Оказалось что у борланда несколько функций объявлены неправильно.BuildExplicitAccessWithName и GetSecurityInfo некорректно объявлены. А рядом с BuildExplicitAccessWithName еще видел функции, которые с постфиксом W имеют параметры PAnsiChar.


 
Игорь Шевченко ©   (2009-04-17 02:51) [29]


> Оказалось что у борланда несколько функций объявлены неправильно.
> BuildExplicitAccessWithName и GetSecurityInfo некорректно
> объявлены. А рядом с BuildExplicitAccessWithName еще видел
> функции, которые с постфиксом W имеют параметры PAnsiChar.
>


И на солнце бывают пятна.

Пользуйся лучше Jedi API Translation (http://www.delphi-jedi.org) - там вроде меньше ошибок


 
Anatoly Podgoretsky ©   (2009-04-17 09:59) [30]

> SPeller  (17.04.2009 2:39:28)  [28]

Не несколько, а много и исправляются или медленно или никогда.


 
SPeller ©   (2009-04-17 16:37) [31]

Удалено модератором



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

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

Наверх




Память: 0.55 MB
Время: 0.004 c
15-1276193680
AKE
2010-06-10 22:14
2010.09.05
Я забыл можно ли объявлять функцию внутри функции?


4-1239652712
Unlocker
2009-04-13 23:58
2010.09.05
Запуск под админом


6-1225280196
Андрей
2008-10-29 14:36
2010.09.05
TServerSocket/TClientSocket SendText


15-1276115374
Юрий
2010-06-10 00:29
2010.09.05
С днем рождения ! 10 июня 2010 четверг


2-1275993844
DROWSY
2010-06-08 14:44
2010.09.05
Type mismatch for field "DIAMETR", expecting: Float actual BCD.





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский