C Windows EXE可以作为服务或应用程序运行。如何确定它是否作为服务运行?
我正在寻找Win32 API调用以返回进程的运行时上下文。我希望能够以编程方式测试我是作为服务运行还是作为标准应用程序进程运行 我想到了几个主意。。。。因为我总是有服务DAD.exe,有时作为他的孩子在服务上下文中运行SON.exe,有时SON.exe不是由DAD启动的,而是由用户启动的 SON.EXE将执行API whoami()以了解他运行的上下文 现在爸爸可以创建一个环境变量——然后儿子可以测试这个变量——如果发现了,他知道自己是爸爸的儿子,因此可以作为服务运行。。。。。但这是脆弱的C Windows EXE可以作为服务或应用程序运行。如何确定它是否作为服务运行?,c,windows,winapi,windows-services,C,Windows,Winapi,Windows Services,我正在寻找Win32 API调用以返回进程的运行时上下文。我希望能够以编程方式测试我是作为服务运行还是作为标准应用程序进程运行 我想到了几个主意。。。。因为我总是有服务DAD.exe,有时作为他的孩子在服务上下文中运行SON.exe,有时SON.exe不是由DAD启动的,而是由用户启动的 SON.EXE将执行API whoami()以了解他运行的上下文 现在爸爸可以创建一个环境变量——然后儿子可以测试这个变量——如果发现了,他知道自己是爸爸的儿子,因此可以作为服务运行。。。。。但这是脆弱的 另一
另一个想法是查看我的SID或令牌,看看我是否可以做出这个决定。。。。同样,与单个API检查相比,这看起来更复杂…简单的低技术解决方案是使用命令行参数注册要运行的服务,命令行参数将其标识为服务。另一个选项是使用。使用它,可以对当前运行的所有进程进行快照,然后可以使用and函数遍历所有进程。它们返回的结构()如下所示:
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;
在浏览所有进程时,只要找到th32ProcessID
与SON.exe匹配的进程(请参阅或)。如果该结构的th32ParentProcessID与DAD.exe的匹配,则您知道您是从DAD.exe启动的
编辑:
回答您的评论,我想您可以更进一步,然后看看谁是DAD.exe的家长,如果它是services.exe,那么您就是一个服务。我想您在寻找Topshelf时,它起到了繁重的作用,使其更容易作为控制台运行或作为服务安装 阅读文档后,我认为您可以通过以下方式确定是否正在进行交互式会话或服务:
WSF\u VISIBLE
应该会告诉您
如果您想区分登录用户会话和非活动用户会话(快速用户切换),我想您可以使用和GetUserObjectInformation(UOI\u IO)
从服务内部进行判断的最好和最简单的方法是在调用
ServiceMain
时设置一个标志。但是您正在测试一个子进程,请参见上文。I以下内容:
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;
}
实际上,我有DAD.EXE、SON.EXE和GSON.EXE,其中GSON.EXE有时在服务上下文中运行,有时在用户上下文中运行。这里的要点是,GSON.EXE不能简单地询问他的父母是否是DAD.EXE——询问它是否是SON.EXE也是有问题的,因为实际上SON.EXE是常见的CMD.EXE——所以键入父母姓名不是正确的想法……我想我误解了你的问题。您不是要确定父对象是谁,而是要确定父对象是否恰好是服务?是吗?你可以用OpenProcessToken()+CreateWellKnownSid(WinServiceSid)+CheckTokenMembership()来实现这一点。卢克,你能解释一下打赌吗,我看到并可以研究您列出的API——但当我的程序作为服务运行时,它们如何产生True,而当通过用户从用户会话启动它时,它们如何产生fals?当进程作为服务运行时,Windows将安全服务添加到其令牌中。不幸的是,我有一个相当大的安装基础,没有这个连接。酷。这种方法能为我的基本问题提供正确或错误的答案吗——如果(以服务的形式运行)ras=True,否则ras=False。。。。我的目标只是想知道程序是在服务上下文还是在用户上下文中运行。酷。。。。当我的程序作为应用程序从用户会话中运行时,这些api及其进程“行走”功能是否可以调用?(没有管理员提升等,例如标准用户。。。。谢谢@凯文韦特:这是个好问题。它们应该作为标准用户工作,但您可能需要提升以查看系统上的所有进程。但这应该足以告诉您需要知道的内容。仅仅因为流程在会话0中运行或在其中一个帐户下运行并不一定使其成为服务,尽管它对于99.9%的情况可能足够好。@Luke我同意它不是100%准确。re:上面的代码片段/示例。。。IsServiceUser()和IsServiceProcess()对于Vista之前的OSs环境有一个bug。