Конференция "WinAPI" » Как достоверно определить что программа запущена как сервис?
 
  • SPeller © (15.04.09 09:15) [0]
    Был откуда-то у меня пример, но он вытаскивает имя юзера, с которым сервис запускается, и сравнивает его с именем, под которым запущен процесс. Совпало - типа мы сервис. Но одинаковый юзер еще не означает того, что наш процесс - сервис. Сервис может быть запущен от имени другой учетки, поэтому данный метод отпадает. Каким образом определить что процесс запущен сервис-менеджером, а не кем-то другим?
  • 12 © (15.04.09 09:30) [1]
  • Palladin © (15.04.09 09:31) [2]

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

    Ты что, думаешь, что если я зайду в консоль управления и запущу сервис, он от моего имени запустится?
  • SPeller © (15.04.09 09:36) [3]

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

    Процесс можно запустить от того же имени, от которого запускается сервис, и тогда сверка имен даст некорректный результат.
  • SPeller © (15.04.09 09:42) [4]

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

    В настройках сервиса можно прописать любую учетку, под которой запускается сервис. Хоть под гостем запускать. И это будут совсем разные вещи, будет ожидаться совсем разное поведение программы, нежели если этот гость как-то сам запустит программу. Вот в чем дело.
  • Palladin © (15.04.09 09:58) [5]

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

    И что? Запускатся он будет в любом случае сервис манагером. Тебе в самом сервисе нужно определять под чьей учеткой он запущен, а не определять откуда сервис запущен. Короче не путай теплое с мягким!
  • Anatoly Podgoretsky © (15.04.09 10:02) [6]
    > Palladin  (15.04.2009 9:31:02)  [2]

    Почему бы и нет?
    Плохо другое автор как обычно молчит о задаче, вместо этого говорит только о реализации, при том вероятно неправильной.
  • KSergey © (15.04.09 10:04) [7]
    Если я ничего не путаю, то при запуске "как сервис" программа получает спец. параметры (или из нее спец. call-back'и дергаются? совершенно забыл).
    А потому вопрос не понятен: прога если сервис - запускается совершенно определенным образом.

    PS
    под рукой нет где глянуть быстро, но надеюсь, что не вру
  • SPeller © (15.04.09 10:06) [8]

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

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

    Для чего это всё: пишу сервис, который должен работать строго под отведенной ему учеткой. Но для отладки нужно чтобы он мог запускаться и как сервис и как обычная программа, немного корректируя при этом внутреннюю логику. В последствии, когда дело приблизится к концу, нужно будет вообще запретить запуск иной кроме как сервисом.
  • SPeller © (15.04.09 10:08) [9]

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

    Никаких параметров не получает. Процесс регистрирует callback через RegisterServiceCtrlHandler.
  • sniknik © (15.04.09 10:09) [10]
    > Тебе в самом сервисе нужно определять под чьей учеткой он запущен, а не определять откуда сервис запущен.
    а как тогда с вариантом если его запускают как программу? учетки не показатель, т.к. возможен запуск от любой, единственный вариант разделить это узнать кто (откуда) программу запускал.
    т.е. "откуда сервис запущен" как раз определяет будет ли это сервис или программа.

    речь идет о разделении, и соответственно ветвлении кода в зависимости от того как программу стартуют, как сервис или как программу.
    для примера можно посмотреть scktsrvr.exe (есть исходники) в дельфе, речь идет о их способе определения (о том что он не всегда правильно определит).
    > Был откуда-то у меня пример
    оттуда наверняка.
  • sniknik © (15.04.09 10:11) [11]
    > SPeller ©
    а ссылка не помогла? как раз если запускает сервис менеджер (родительский процесс) то это показатель.
  • Palladin © (15.04.09 10:14) [12]
    тьфу блин... ну так разделяй понятия сервис и приложение.... запутал совсем... )
  • SPeller © (15.04.09 10:19) [13]

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

    Разбираюсь в коде. Похоже, что проверки на имя процесса services.exe и на статус SERVICE_START_PENDING должно хватить.
  • SPeller © (15.04.09 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 © (15.04.09 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 © (15.04.09 11:22) [16]
    > SPeller  (15.04.2009 10:06:08)  [8]

    Тогда и нечего голову ломать. Просто закончить отладку.
  • SPeller © (15.04.09 11:30) [17]
    Вот бы еще из-под ограниченного аккаунта получить полное имя файла родительского процесса с путем. А то GetModuleFileNameEx хочет права, которых нет:

    The handle must have the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights
  • SPeller © (15.04.09 11:34) [18]

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

    Это не последний мой сервис :) Нужны наработки чтобы в будущем легко с ними обращаться.
  • SPeller © (15.04.09 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, определенная как должно быть.
 
Конференция "WinAPI" » Как достоверно определить что программа запущена как сервис?
Есть новые Нет новых   [134434   +28][b:0][p:0.003]