services.exe 如何触发服务的启动?

逆向工程 视窗
2021-06-19 08:25:01

我正在尝试弄清楚 Windows 进程如何启动并保持与services.exe. 这是在 Windows 8 x64 上,但如果您有 Windows 7 的提示也很好。

到目前为止,我发现services.exe做的事情大约是这样的:

PROCESS_INFORMATION     pi;
    TCHAR                   szExe[] = _T("C:\\Program Files\\TestProgram\\myWindowsService.exe");
    PROCESS_INFORMATION process_information = {0};
    HKEY hOpen;
    DWORD dwNumber = 0;
    DWORD dwType = REG_DWORD;  
    DWORD dwSize = sizeof(DWORD);
    STARTUPINFOEX startup_info;
    SIZE_T attribute_list_size = 0;

    ZeroMemory(&startup_info, sizeof(STARTUPINFOEX));

    // can see EXTENDED_STARTUPINFO_PRESENT is used, but couldn't figure out if any/what attributes are added
    BOOL status = InitializeProcThreadAttributeList(nullptr, 0, 0, &attribute_list_size);
    PPROC_THREAD_ATTRIBUTE_LIST attribute_list = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, attribute_list_size);

    startup_info.StartupInfo.cb = sizeof(STARTUPINFOEX);
    startup_info.lpAttributeList = attribute_list;
    startup_info.StartupInfo.dwFlags = STARTF_FORCEOFFFEEDBACK;
    startup_info.StartupInfo.wShowWindow= SW_HIDE;

        if(CreateProcess(
            NULL,
            szExe,
            NULL,
            NULL, 
            FALSE,
            CREATE_SUSPENDED | 
            CREATE_UNICODE_ENVIRONMENT | 
            DETACHED_PROCESS | 
            EXTENDED_STARTUPINFO_PRESENT,
            NULL,
            NULL, 
            &startup_info.StartupInfo, 
            &pi))
    {
        HANDLE hEvent;
        hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); // I traced this call during service sstartup; no idea what purpose it serves?

        ResumeThread(pi.hThread);

现在我的问题是,如何将实际的“开始”传达给服务?我知道服务本身会做这样的事情:

  1. 主入口点(如控制台程序)
  2. 称呼 advapi!StartServiceCtrlDispatcher
  3. sechost!StartServiceCtrlDispatcher
  4. 这跳入 sechost!QueryServiceDynamicInformation

我试图弄清楚services.exe使用什么方法来连接到这个启动过程。理想情况下,我希望能够编写一个 PoC 代码,该代码可以“启动”一个简单的 Windows 服务并使其启动,而无需将其注册为 Windows 服务,即包装在“独立服务控制管理器”中。我正在寻找有关下一步最佳查找内容的一些提示。

还有对services.exein的引用\\pipe\ntsvcs关于 SCM维基百科文章指的是\Pipe\Net\NtControlPipeX正在创建,但据我所知,那是在 Windows 2000(也许是 XP)中,但我看不到在 Windows 8 上发生这种情况。

1个回答

这是我对 Windows 服务工作原理的基本了解。我在 Windows XP 和 Windows 7 上使用过它。无论如何,这些都是一般概念。

任何服务都需要存在三件事:

  1. 主要入口点
  2. 服务入口点
  3. 服务控制处理程序

你是绝对正确的。在主入口点服务必须调用StartServiceCtrlDispatcher(const SERVICE_TABLE_ENTRY *lpServiceTable)提供服务控制管理器填写的SERVICE_TABLE_ENTRY,即(根据MSDN):

typedef struct _SERVICE_TABLE_ENTRY {
    LPTSTR                  lpServiceName;
    LPSERVICE_MAIN_FUNCTION lpServiceProc;
} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;

如您所见,SERVICE_TABLE_ENTRY 结构中需要提供两件事。这些是指向服务名称的指针,以及指向服务主函数的指针。服务注册后,服务控制管理器立即调用Service Main 函数,该函数也称为ServiceMain 或Service Entry Point。服务控制管理器期望服务入口点执行以下任务:

  1. 注册服务控制处理程序。
  2. 设置服务状态
  3. 执行必要的初始化(创建事件、互斥锁等)

Service Control Handler 是一个回调函数,定义如下VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode):( MSDN )。预计处理服务 STOP、PAUSE、CONTINUE 和 SHUTDOWN。每个服务都必须有一个处理程序来处理来自 SCM 的请求。服务控制处理程序注册到RegisterServiceCtrlHandlerEx()( MSDN ),它返回SERVICE_STATUS_HANDLE. 服务使用句柄与 SCM 通信。控制处理程序也必须在 30 秒内返回。如果没有发生,SCM 将返回一个错误,指出服务没有响应。这是因为处理程序从 SCM 中调用,并且会冻结 SCM,直到它从处理程序返回。只有这样,服务才可以使用SetServiceStatus()MSDN) 函数与服务状态句柄一起与 SCM 通信。

您不会将“开始”传达给服务。每当服务加载时,它都会以“启动”状态加载。服务有责任向 SCM 报告其状态。您可以暂停或继续(加上大约十几个控制代码)。您可以使用ControlService()( MSDN ) 功能将其传达给 SCM SCM 依次使用注册的服务控制处理程序函数将控制代码(例如,SERVICE_CONTROL_PAUSE、SERVICE_CONTROL_CONTINUE 或任何其他代码)中继到服务。之后,根据接收到的控制代码采取行动是服务的责任。

我不认为 services.exe 在实际服务后面执行或运行线程。它是 SCM 本身。我认为它总体上协调服务。每个服务都“存在”于 svchost.exe 实例中。考虑到上述情况,我可以假设 Service Entry Point 或 Service Main 是在 svchost.exe 实例的上下文中执行的。反过来,svchost.exe 在主线程的上下文中执行 Service Main,阻塞主线程,直到 Service Main 存在,表明服务已退出。

如果您正在考虑创建自己的服务控制管理器,则无需对 services.exe 的工作方式进行逆向工程。你可以按照自己的方式来做,无论如何你喜欢它:)

我希望它有帮助。

添加:

正如Mick在下面评论的那样,services.exe是服务控制管理器本身。

如果您要创建自己的服务包装器以在 SCM 之外运行现有的服务可执行文件,则必须遵守上述服务准则和要求。第一个要求是服务将自己注册到 SCM 并提供服务主入口点,这是通过调用StartServiceCtrlDispatcher(). 它将为您提供 Service Main 的入口点。之后,您应该期望 Service Main 调用RegisterServiceCtrlHandler()SetServiceStatus()由于RegisterServiceCtrlHandler()在 Service Main 的上下文中运行并阻塞 Service Main 线程,因此也应该正确处理。此外,您应该想办法通过在 Service Main 中“监视” CreatThread()MSDN来控制/监视服务工作线程