开发者

Windows EXE can run as service or application. How can I determine if it is running as a service or not?

开发者 https://www.devze.com 2023-04-09 16:47 出处:网络
I am looking for a Win32 API call to return the runtime context of my process. I want to be able to programmatically test if I am running as a service or am I running as standard application process.

I am looking for a Win32 API call to return the runtime context of my process. I want to be able to programmatically test if I am running as a service or am I running as standard application process.

Several ideas come to mind.... Since I always have service DAD.exe who runs SON.exe sometimes as his child and in servi开发者_如何学编程ce context --- and sometimes SON.exe is started not by DAD, and by a user.

SON.EXE would do API whoami() to learn which context he is running in.

Now DAD could create an environment var -- and then SON could test for this var -- and if found he knows he is a son of DAD and thus runnning as a service..... But this is weak...

Another idea would be to look at my SID or token and see if I could make this determination.... Again this looks at best more complex vs. a single API check...


The simple low-tech solution to this is to register your service to run with command line arguments that identify it as a service.


Another option is to use the Tool Help library. Using it, you take a snapshot of all the currently running processes and then you can walk through all the processes using the Process32First and Process32Next function. These return a structure (PROCESSENTRY32) that looks like:

typedef struct tagPROCESSENTRY32 {
  DWORD     dwSize;
  DWORD     cntUsage;
  DWORD     th32ProcessID;
  ULONG_PTR th32DefaultHeapID;
  DWORD     th32ModuleID;
  DWORD     cntThreads;
  DWORD     th32ParentProcessID;
  LONG      pcPriClassBase;
  DWORD     dwFlags;
  TCHAR     szExeFile[MAX_PATH];
} PROCESSENTRY32, *PPROCESSENTRY32;

as you walk through all the processes, as soon as you find the one whose th32ProcessID matches the one for SON.exe (see GetCurrentProcessId or GetProcessId ). If the th32ParentProcessID of that structure matches that of DAD.exe, then you know you were launched from DAD.exe.

Edit: Answering your comment, I guess you could go one step further and then see who the parent of DAD.exe is, if it's services.exe, then you're a service.


Reading the documentation, I think you could determine whether you're in an interactive session or service via:

  • GetProcessWindowStation
  • GetUserObjectInformation(UOI_FLAGS)

and then WSF_VISIBLE should tell you.

If you wanted to differentiate between a logged-in user session and one that's inactive (Fast User Switching), I guess you could use GetThreadDesktop and GetUserObjectInformation(UOI_IO).


The best and simplest way to tell from inside the service is to set a flag when ServiceMain is called. But you're testing a child process, so see above.


I found the following:

bool WinUtil::IsServiceUser(HANDLE hToken, bool *is_service) {
  if (is_service == NULL) {
    return false;
  }

  TOKEN_STATISTICS ts;
  DWORD dwSize = 0;
  // Use token logon LUID instead of user SID, for brevity and safety
  if (!::GetTokenInformation(hToken, TokenStatistics,
                             (LPVOID)&ts, sizeof(ts), &dwSize)) {
    return false;
  }

  // Compare LUID
  const LUID SystemLuid = SYSTEM_LUID;
  const LUID LocalServiceLuid = LOCALSERVICE_LUID;
  const LUID NetworkServiceLuid = NETWORKSERVICE_LUID;
  if (EqualLuid(SystemLuid, ts.AuthenticationId) ||
      EqualLuid(LocalServiceLuid, ts.AuthenticationId) ||
      EqualLuid(NetworkServiceLuid, ts.AuthenticationId)) {
    *is_service = true;
    return true;
  }

  // Not a service account
  *is_service = false;
  return true;
}
bool WinUtil::IsServiceProcess(bool *is_service) {
  if (is_service == NULL) {
    return false;
  }

  if (Util::IsVistaOrLater()) {
    // Session 0 is dedicated to services
    DWORD dwSessionId = 0;
    if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &dwSessionId) ||
        (dwSessionId == 0)) {
      *is_service = true;
      return true;
    }
  }

  // Get process token
  HANDLE hProcessToken = NULL;
  if (!::OpenProcessToken(::GetCurrentProcess(),
                          TOKEN_QUERY | TOKEN_QUERY_SOURCE,
                          &hProcessToken)) {
    return false;
  }

  ScopedHandle process_token(hProcessToken);

  // Process token is one for a service account.
  if (!IsServiceUser(process_token.get(), is_service)) {
    return false;
  }

  return true;
}


I think your looking for Topshelf http://topshelf-project.com/, it does the heavy lifting and makes it easier run as console or install as a service. Topshelf hosting application debugging in VS2010

0

精彩评论

暂无评论...
验证码 换一张
取 消