Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

A C++ class wrapper to load/unload device drivers

4.80/5 (15 votes)
20 Dec 2008CPOL2 min read 73.4K   5.5K  
A C++ class to register and start device drivers.

Introduction

A loader/unloader tool is very useful if you frequently play with device derivers. There are a lot of tools that are good, the most popular I think is OSRLoader. But, I decided to write this wrapper in order to explain which Win32 APIs are involved in this process.

The Win32 APIs

A device driver is different from a normal user level program, so its installation and execution are more complex, because we are in the kernel space. We have to do two main operations:

  1. Register the driver as a Windows service.
  2. Start the driver as a service.

The reason for this is that Windows sees the device drivers as normal services. Now, we can explore the APIs that allow us to work with a process. The Service Control Manager (SCM) is the component that manages a database with all the services and device drivers installed. Let us see the API that establishes a connection to the SCM on our box.

C++
SC_HANDLE WINAPI OpenSCManager(
  __in_opt  LPCTSTR lpMachineName,
  __in_opt  LPCTSTR lpDatabaseName,
  __in      DWORD dwDesiredAccess
);

After this, we can create a new service like this:

C++
SC_HANDLE WINAPI CreateService(
  __in       SC_HANDLE hSCManager,
  __in       LPCTSTR lpServiceName,
  __in_opt   LPCTSTR lpDisplayName,
  __in       DWORD dwDesiredAccess,
  __in       DWORD dwServiceType,
  __in       DWORD dwStartType,
  __in       DWORD dwErrorControl,
  __in_opt   LPCTSTR lpBinaryPathName,
  __in_opt   LPCTSTR lpLoadOrderGroup,
  __out_opt  LPDWORD lpdwTagId,
  __in_opt   LPCTSTR lpDependencies,
  __in_opt   LPCTSTR lpServiceStartName,
  __in_opt   LPCTSTR lpPassword
);

The explanation for each parameter is available on the MSDN. Now, I will show you how to use this API to create a new service:

C++
DWORD CService::CreateSvc(void)
{
    if (!IsInit())
        return SVC_NOT_INIT;
    
    if (IsLoaded())
        return SVC_OK;

    SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);

    if (hSCManager == NULL)
        return SVC_ERROR_SCMANAGER;

    hService = CreateService(hSCManager,lpServiceName,lpDisplayName,
                             SERVICE_ALL_ACCESS,    
                             SERVICE_KERNEL_DRIVER, 
                             dwStartType,  
                             SERVICE_ERROR_NORMAL,  
                             lpFilePath,              
                             NULL,                  
                             NULL,                  
                             NULL,                 
                             NULL,                  
                             NULL);

    if (hService == NULL){

        hService = OpenService(hSCManager, lpServiceName, SERVICE_ALL_ACCESS);
        
        if (hService == NULL) {
            CloseServiceHandle(hSCManager);
            return SVC_ERROR_CREATE;
        }
    }
    
    loaded = true;
    CloseServiceHandle(hSCManager);
    
    return SVC_OK;    
}

The OpenSCManager(…)returns the handle of the SCM, so we use it in CreateService(…) for installing the device driver. hService is the handle of the service installed. Now, we can start it. The API:

C++
BOOL WINAPI StartService(
  __in      SC_HANDLE hService,
  __in      DWORD dwNumServiceArgs,
  __in_opt  LPCTSTR *lpServiceArgVectors
);

Here is the code:

C++
DWORD CService::StartSvc(void)
{
    if (!IsLoaded())
        return SVC_NOT_CREATE;

    if (IsStarted())
        return SVC_OK;

    SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);

    if (hSCManager == NULL)
        return SVC_ERROR_SCMANAGER;

    hService = OpenService(hSCManager, lpServiceName, SERVICE_ALL_ACCESS);
        
    if (hService == NULL) {
        CloseServiceHandle(hSCManager);
        return SVC_ERROR_OPEN;
    }

    if (StartService(hService,0,NULL)== NULL){
        CloseServiceHandle(hSCManager);
        CloseServiceHandle(hService);
        return SVC_ERROR_START;
    }

    CloseServiceHandle(hSCManager);
    started = true;

    return SVC_OK;
}

The StartService function take three parameters: the handle of the service, the number of arguments, and an array with the arguments.

OK, after working, it’s time to shutdown the driver. To stop the driver, we use this API:

C++
BOOL WINAPI ControlService(
  __in   SC_HANDLE hService,
  __in   DWORD dwControl,
  __out  LPSERVICE_STATUS lpServiceStatus
);

This sends the control message to the service, in our case dwControl = SERVICE_CONTROL_STOP. The out SERVICE_STATUS struct contains the status information about the service.

C++
DWORD CService::StopSvc(void)
{
    SERVICE_STATUS ss;

    if (!IsStarted())
        return SVC_OK;

    SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);

    if (hSCManager == NULL)
        return SVC_ERROR_SCMANAGER;

    hService = OpenService(hSCManager, lpServiceName, SERVICE_ALL_ACCESS);
        
    if (hService == NULL) {
        CloseServiceHandle(hSCManager);
        return SVC_ERROR_OPEN;
    }

    if (ControlService(hService,SERVICE_CONTROL_STOP,&ss) == NULL){
        CloseServiceHandle(hSCManager);
        CloseServiceHandle(hService);
        return SVC_ERROR_STOP;
    
    }
    
    started = false;

    CloseServiceHandle(hSCManager);
    CloseServiceHandle(hService);
    return SVC_OK;
}

Finally, we have to unload the driver.

C++
BOOL WINAPI DeleteService(
  __in  SC_HANDLE hService
);

This is the API to delete the driver from the SCM, and this is how we use it:

C++
DWORD CService::UnloadSvc(void)
{
    if (!IsLoaded())
        return SVC_OK;

    if (IsStarted())
        if (StopSvc() != SVC_OK)
            return SVC_ERROR_UNLOAD;

    SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);

    if (hSCManager == NULL)
        return SVC_ERROR_SCMANAGER;

    hService = OpenService(hSCManager, lpServiceName, SERVICE_ALL_ACCESS);
        
    if (hService == NULL) {
        CloseServiceHandle(hSCManager);
        return SVC_ERROR_OPEN;
    }

    DeleteService(hService);
    CloseServiceHandle(hSCManager);
    
    loaded = false;

    return SVC_OK;
}

Using the code

Well, if you are lazy, or you can’t waste your time to understand how all these APIs work, I have written this simple wrapper that I hope you will find useful:

C++
#include <windows.h>
#include "stdafx.h"

//Error codes

#define SVC_OK (DWORD)0
#define SVC_NOT_CREATE (DWORD)1
#define SVC_NOT_START (DWORD)2
#define SVC_NOT_INIT (DWORD)3
#define SVC_ERROR_SCMANAGER (DWORD)4
#define SVC_ERROR_CREATE (DWORD)5
#define SVC_ERROR_START (DWORD)6
#define SVC_ERROR_OPEN (DWORD) 7
#define SVC_ERROR_STOP (DWORD)8
#define SVC_ERROR_UNLOAD (DWORD) 9


class CService
{
public:
    //Constructor
    CService(void);
    CService(LPTSTR _lpFilePath,LPTSTR _lpServiceName,
             LPTSTR _lpDisplayName,DWORD _dwStartType);
    //Destructor
    ~CService(void);
    
    //init function
    DWORD InitSvc(LPTSTR _lpFilePath,LPTSTR _lpServiceName,
                  LPTSTR _lpDisplayName,DWORD _dwStartType);
    DWORD CreateSvc(void);  //create service
    DWORD UnloadSvc(void);  //unload service
    DWORD StartSvc(void);  //start service
    DWORD StopSvc(void);   //stop service


    BOOL   IsInit(void); //check if service is init
    BOOL   IsLoaded(void); //check if service is loaded
    BOOL   IsStarted(void); //check if service is started

private:
    
    LPTSTR lpFilePath; //driver file path
    LPTSTR lpServiceName; //service name
    LPTSTR lpDisplayName; //service's dos name

    DWORD dwStartType; //start type

    SC_HANDLE hService; //service's handle
    
    // Status variables
    BOOL init; 
    BOOL loaded;
    BOOL started;    

};

The CService object creation:

C++
CService svc("C:\\test.sys","Test","Test",SERVICE_DEMAND_START);

Driver registration:

C++
if (svc.CreateSvc() == SVC_OK)
        …
else{
        …
}

Driver startup:

C++
if (svc.StartSvc() == SVC_OK)
        …
else{
        …
}

Driver stop:

C++
if (svc.StopSvc() == SVC_OK)
        …
else{
        …
}

Driver erase:

C++
if (svc.UnloadSvc() == SVC_OK)
        …
else{
        …
}

Conclusion

OK, that’s all. I also wrote a little app that use the CService class. I hope you will find these few lines of code useful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)