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:
- Register the driver as a Windows service.
- 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.
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:
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:
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:
BOOL WINAPI StartService(
__in SC_HANDLE hService,
__in DWORD dwNumServiceArgs,
__in_opt LPCTSTR *lpServiceArgVectors
);
Here is the code:
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:
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.
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.
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:
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:
#include <windows.h>
#include "stdafx.h"
#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:
CService(void);
CService(LPTSTR _lpFilePath,LPTSTR _lpServiceName,
LPTSTR _lpDisplayName,DWORD _dwStartType);
~CService(void);
DWORD InitSvc(LPTSTR _lpFilePath,LPTSTR _lpServiceName,
LPTSTR _lpDisplayName,DWORD _dwStartType);
DWORD CreateSvc(void); DWORD UnloadSvc(void); DWORD StartSvc(void); DWORD StopSvc(void);
BOOL IsInit(void); BOOL IsLoaded(void); BOOL IsStarted(void);
private:
LPTSTR lpFilePath; LPTSTR lpServiceName; LPTSTR lpDisplayName;
DWORD dwStartType;
SC_HANDLE hService;
BOOL init;
BOOL loaded;
BOOL started;
};
The CService
object creation:
CService svc("C:\\test.sys","Test","Test",SERVICE_DEMAND_START);
Driver registration:
if (svc.CreateSvc() == SVC_OK)
…
else{
…
}
Driver startup:
if (svc.StartSvc() == SVC_OK)
…
else{
…
}
Driver stop:
if (svc.StopSvc() == SVC_OK)
…
else{
…
}
Driver erase:
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.