7

I'm trying to work out the internals of how a Windows process starts and maintains communication with services.exe. This is on Windows 8 x64, but if you have tips for Windows 7 that is fine too.

So far I figure out services.exe does something approximately like this:

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);

Now my question is, how does the actual "Start" get communicated to the service? I know the service itself does something like this:

  1. main entry point (à la console program)
  2. Call advapi!StartServiceCtrlDispatcher
  3. Goes to sechost!StartServiceCtrlDispatcher
  4. This jumps into sechost!QueryServiceDynamicInformation

I'm trying to figure out what method in services.exe is used to hook into this start process. Ideally I want to be able to write a PoC code that can "launch" a simple Windows service and get it to start, without it being registered as a Windows Service, i.e. wrapped inside a "stand alone service control manager". I'm looking for some tips of what best to look for next.

There is also a reference to services.exe in \\pipe\ntsvcs. The Wikipedia article about SCM refers to \Pipe\Net\NtControlPipeX being created, but as far as I can tell, that is in Windows 2000 (maybe XP) but I can't see this happening on Windows 8.

9

This is my basic understanding of how Windows service works. I have used it with Windows XP and Windows 7. These are general concepts anyways.

Any service requires three things to be present:

  1. A Main Entry Point
  2. A Service Entry Point
  3. A Service Control Handler

You are absolutely right. In the Main Entry Point service must call StartServiceCtrlDispatcher(const SERVICE_TABLE_ENTRY *lpServiceTable) providing Service Control Manager with filled in SERVICE_TABLE_ENTRY, which is (per MSDN):

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

As you can see, there are two things which are required to be supplied in SERVICE_TABLE_ENTRY structure. Those are pointer to name of the service, and pointer to service main function. Right after service registration, Service Control Manager calls Service Main function, which is also called ServiceMain or Service Entry Point. Service Control Manager expects that following tasks are performed by Service Entry Point:

  1. Register the service control handler.
  2. Set Service Status
  3. Perform necessary initialization (creating events, mutex, etc)

Service Control Handler is a callback function with the following definition: VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode)(MSDN). It is expected to handle service STOP, PAUSE, CONTINUE, and SHUTDOWN. It is imperative that each service has a handler to handle requests from the SCM. Service control handler is registered with RegisterServiceCtrlHandlerEx()(MSDN), which returns SERVICE_STATUS_HANDLE. Service uses the handle to communicate to the SCM. The control handler must also return within 30 seconds. If it does not happen the SCM will return an error stating that the service is unresponsive. This is due to the fact that the handler is called out of the SCM and will freeze the SCM until it returns from the handler. Only then, service may use SetServiceStatus()(MSDN) function along with service status handle to communicate back to the SCM.

You don't communicate "Start" to a service. Whenever a service loads, it loads in the "started" state. It is service's responsibility to report its state to the SCM. You can PAUSE it or CONTINUE (plus about dozen more control codes). You communicate it to the SCM by using ControlService()(MSDN) function. The SCM in turn relays the control code (e.g. SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_CONTINUE or any other one) through to the service using registered service control handler function. Afterwards, it is the services responsibility to act upon received control code.

I don't think services.exe executes or runs threads behind actual services. It is the SCM itself. I take it coordinates services in general. Each service "lives" in svchost.exe instance. Taking mentioned above into account, I could assume that Service Entry Point or Service Main is executed in the context of instance of the svchost.exe. In its turn, svchost.exe executes Service Main in context of main thread, blocking main thread until Service Main exists signaling that the service exited.

If you are thinking to create your own service control manager, there is no need to reverse engineer how services.exe does it. You can do it your own way and anyway that you like it :)

I hope it helps.

ADDED:

As Mick commented below, services.exe is the Service Control Manager itself.

If you are creating your own service wrapper to run existing serivce executables outside of the SCM, you will have to adhere to above mentioned service quidelines and requirements. The fist requirement is for the service to get itself registered with the SCM and provide Service Main Entry Point, which is done by calling StartServiceCtrlDispatcher(). It will get you the entry point to Service Main. Afterwards, you should expect the Service Main to call RegisterServiceCtrlHandler() and SetServiceStatus(). Since RegisterServiceCtrlHandler() runs in context of Service Main and blocks Service Main thread, it should be handled properly as well. In addition, you should think of a way to control/monitor the service worker thread(s) by "watching" for CreatThread()(MSDN) within Service Main.

  • Good answer. I'd only add for clarity (you do imply it) that the Service Control Manager's executable is "services.exe", a console application that is launched by Winlogon early in the startup process. – Mick Jun 12 '13 at 2:40
  • Thank you PSS, a very good response. Following along with what you said I found when a service EXE is launched outside SCM the call to StartServiceCtrlDispatcher fails err code 1063 The service process could not connect to the service controller. I suspect then if I want to write my own "wrapper" i.e. run service without SCM, I need to hook advapi32!StartServiceCtrlDispatcher and replace with my own function to execute service main. Would this be correct understanding? – chentiangemalc Jun 12 '13 at 11:35
  • @MalcolmMcCaffery. Exactly. Please see above. I have amended my answer. – PSS Jun 12 '13 at 14:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.