This code manually creates a service key. AFAIK you don't need to create all these values, just some of them are required for drivers. When writing this code, I just did not want to spent time by determining which values are actually required and which are not.
The first argument is a service name for the new driver, the second one an absolute path to driver file (the routine automatically prepends the \??\ string).
Code: Select allDWORD _InstallDriver(PWCHAR ServiceName, PWCHAR FileName)
{
DWORD dwordValue = 0;
HKEY driverKey = NULL;
HKEY servicesHandle = NULL;
DWORD ret = ERROR_GEN_FAILURE;
ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\services", 0, KEY_WRITE, &servicesHandle);
if (ret == ERROR_SUCCESS) {
ret = RegCreateKeyEx(servicesHandle, ServiceName, 0, NULL, 0, KEY_WRITE, NULL, &driverKey, NULL);
if (ret == ERROR_SUCCESS) {
dwordValue = SERVICE_KERNEL_DRIVER;
ret = RegSetValueExW(driverKey, L"Type", 0, REG_DWORD, (PBYTE)&dwordValue, sizeof(DWORD));
if (ret == ERROR_SUCCESS) {
dwordValue = SERVICE_SYSTEM_START;
ret = RegSetValueExW(driverKey, L"Start", 0, REG_DWORD, (PBYTE)&dwordValue, sizeof(DWORD));
if (ret == ERROR_SUCCESS) {
dwordValue = SERVICE_ERROR_NORMAL;
ret = RegSetValueExW(driverKey, L"ErrorControl", 0, REG_DWORD, (PBYTE)&dwordValue, sizeof(DWORD));
if (ret == ERROR_SUCCESS) {
PWCHAR imagePath = NULL;
DWORD imagePathLen = (4 + wcslen(FileName))*sizeof(WCHAR);
imagePath = (PWCHAR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, imagePathLen + sizeof(WCHAR));
if (imagePath != NULL) {
SIZE_T prefixLen = wcslen(L"\\??\\")*sizeof(WCHAR);
memcpy(imagePath, L"\\??\\", prefixLen);
memcpy(imagePath + (prefixLen / sizeof(WCHAR)), FileName, imagePathLen - prefixLen);
ret = RegSetValueExW(driverKey, L"ImagePath", 0, REG_SZ, (PBYTE)imagePath, imagePathLen + sizeof(WCHAR));
HeapFree(GetProcessHeap(), 0, imagePath);
} else ret = ERROR_NOT_ENOUGH_MEMORY;
}
}
}
if (ret != ERROR_SUCCESS)
RegDeleteKeyW(servicesHandle, ServiceName);
RegCloseKey(driverKey);
}
RegCloseKey(servicesHandle);
}
return ret;
}
Then, you just need to call NtLoadDriver with a propper parameter.
Code: Select allNTSTATUS _LoadUnloadDriver(PWCHAR ServiceName, BOOLEAN Load)
{
PWCHAR driverName = NULL;
SIZE_T prefixLen = 0;
SIZE_T serviceLen = 0;
PWCHAR prefix = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\services\\";
typedef NTSTATUS(WINAPI NTLOADDRIVER)(PUNICODE_STRING DriverName);
typedef NTSTATUS(WINAPI NTUNLOADDRIVER)(PUNICODE_STRING DriverName);
NTSTATUS status = STATUS_UNSUCCESSFUL;
UNICODE_STRING uDriverName;
prefixLen = wcslen(prefix);
serviceLen = wcslen(ServiceName);
driverName = (PWCHAR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (prefixLen + serviceLen + 1)*sizeof(WCHAR));
if (driverName != NULL) {
memcpy(driverName, prefix, prefixLen*sizeof(WCHAR));
memcpy(driverName + prefixLen, ServiceName, serviceLen*sizeof(WCHAR));
uDriverName.Buffer = driverName;
uDriverName.Length = (USHORT)((prefixLen + serviceLen)*sizeof(WCHAR));
uDriverName.MaximumLength = uDriverName.Length;
if (Load) {
NTLOADDRIVER *_NtLoadDriver = NULL;
_NtLoadDriver = (NTLOADDRIVER *)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtLoadDriver");
if (_NtLoadDriver != NULL)
status = _NtLoadDriver(&uDriverName);
else status = STATUS_NOT_FOUND;
} else {
NTUNLOADDRIVER *_NtUnloadDriver = NULL;
_NtUnloadDriver = (NTUNLOADDRIVER *)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtUnloadDriver");
if (_NtUnloadDriver != NULL)
status = _NtUnloadDriver(&uDriverName);
else status = STATUS_NOT_FOUND;
}
HeapFree(GetProcessHeap(), 0, driverName);
} else status = STATUS_NO_MEMORY;
return status;
}
Of course, if you create a registry key for your driver and reboot the computer, SCM will see the key and creates a service for you (the service will be then visible in its local database).
HTH
EDIT:
Statics removed