如何使用C语言获取Windows系统服务的可执行文件路径?
使用C语言获取Windows服务的可执行文件路径
你提到的GetService、GetServiceDisplayName这类函数确实只能获取服务的名称、显示名这类基础信息,没法直接拿到可执行文件的系统路径。要解决这个问题,我们需要用到Windows API中的QueryServiceConfig函数——它专门用于查询服务的详细配置信息,其中就包含了服务可执行文件的路径。
核心思路
获取服务可执行路径的完整流程如下:
- 打开服务控制管理器(SCM):通过
OpenSCManager函数获取SCM的句柄,这是操作服务的入口。 - 打开目标服务:用
OpenService函数传入SCM句柄和目标服务的内部名称,得到对应服务的句柄。 - 查询服务配置:先调用一次
QueryServiceConfig传入空缓冲区,获取所需的内存大小;再分配足够内存后第二次调用,拿到包含可执行路径的完整配置信息。 - 清理资源:及时关闭打开的句柄,释放分配的内存,避免资源泄漏。
完整示例代码
下面是一个可直接运行的示例,以查询Windows更新服务(内部服务名wuauserv)为例:
#include <windows.h> #include <stdio.h> #include <malloc.h> int main() { SC_HANDLE hSCM = NULL; SC_HANDLE hService = NULL; LPQUERY_SERVICE_CONFIG pServiceConfig = NULL; DWORD dwBytesNeeded = 0; // 1. 打开服务控制管理器 hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (hSCM == NULL) { printf("OpenSCManager failed! Error: %d\n", GetLastError()); goto Cleanup; } // 2. 打开目标服务(替换成你需要查询的服务内部名称) hService = OpenService(hSCM, "wuauserv", SERVICE_QUERY_CONFIG); if (hService == NULL) { printf("OpenService failed! Error: %d\n", GetLastError()); goto Cleanup; } // 3. 第一次调用QueryServiceConfig,获取所需缓冲区大小 if (!QueryServiceConfig(hService, NULL, 0, &dwBytesNeeded)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { printf("QueryServiceConfig (first call) failed! Error: %d\n", GetLastError()); goto Cleanup; } } // 分配内存存储配置信息 pServiceConfig = (LPQUERY_SERVICE_CONFIG)malloc(dwBytesNeeded); if (pServiceConfig == NULL) { printf("Memory allocation failed!\n"); goto Cleanup; } // 第二次调用QueryServiceConfig,获取实际配置数据 if (!QueryServiceConfig(hService, pServiceConfig, dwBytesNeeded, &dwBytesNeeded)) { printf("QueryServiceConfig (second call) failed! Error: %d\n", GetLastError()); goto Cleanup; } // 输出服务可执行文件路径 printf("Service Executable Path: %s\n", pServiceConfig->lpBinaryPathName); Cleanup: // 清理所有资源 if (pServiceConfig != NULL) { free(pServiceConfig); } if (hService != NULL) { CloseServiceHandle(hService); } if (hSCM != NULL) { CloseServiceHandle(hSCM); } return 0; }
注意事项
- 权限要求:查询部分系统服务需要管理员权限,否则会出现
OpenService失败(错误码5,拒绝访问)的情况,记得以管理员身份运行程序。 - 路径含参数处理:
lpBinaryPathName返回的内容可能包含命令行参数,比如"C:\Windows\system32\svchost.exe" -k netsvcs。如果只需要纯路径,可以自行解析字符串,提取引号包裹的部分。 - 服务名正确性:传入
OpenService的必须是服务的内部名称(不是显示名),比如Windows更新服务的内部名是wuauserv,显示名是"Windows Update"。你可以通过services.msc查看服务的内部名称。
内容的提问来源于stack exchange,提问作者Poseidon Security
相关产品推荐
相关产品推荐

