From 06e11512f9f6c51d1a8e37db8b1605aa03d503fc Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Wed, 9 Apr 2008 13:43:34 +0000 Subject: [PATCH] Test code for loading and unloading a driver via 3 different methods. SCM, native methods and via the relatively unknown NtSetSystemInformation methods. Needs rbuild files to test in ros. svn path=/trunk/; revision=32897 --- .../Application/Application.vcproj | 214 ++++++++++++++ .../DriverLoading/Application/DriverTester.h | 72 +++++ .../win32/DriverLoading/Application/main.c | 157 ++++++++++ .../win32/DriverLoading/Application/umode.c | 162 ++++++++++ .../win32/DriverLoading/Application/undoc.c | 276 ++++++++++++++++++ .../win32/DriverLoading/Driver/Driver.vcproj | 213 ++++++++++++++ rostests/win32/DriverLoading/Driver/driver.c | 18 ++ rostests/win32/DriverLoading/DriverTester.sln | 26 ++ 8 files changed, 1138 insertions(+) create mode 100644 rostests/win32/DriverLoading/Application/Application.vcproj create mode 100644 rostests/win32/DriverLoading/Application/DriverTester.h create mode 100644 rostests/win32/DriverLoading/Application/main.c create mode 100644 rostests/win32/DriverLoading/Application/umode.c create mode 100644 rostests/win32/DriverLoading/Application/undoc.c create mode 100644 rostests/win32/DriverLoading/Driver/Driver.vcproj create mode 100644 rostests/win32/DriverLoading/Driver/driver.c create mode 100644 rostests/win32/DriverLoading/DriverTester.sln diff --git a/rostests/win32/DriverLoading/Application/Application.vcproj b/rostests/win32/DriverLoading/Application/Application.vcproj new file mode 100644 index 00000000000..be8af33fd0c --- /dev/null +++ b/rostests/win32/DriverLoading/Application/Application.vcproj @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rostests/win32/DriverLoading/Application/DriverTester.h b/rostests/win32/DriverLoading/Application/DriverTester.h new file mode 100644 index 00000000000..b5cca46b092 --- /dev/null +++ b/rostests/win32/DriverLoading/Application/DriverTester.h @@ -0,0 +1,72 @@ +#define _WIN32_WINNT 0x0500 +#include +#include +#include + +#define DRIVER_NAME L"TestDriver" + +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS)0xC0000061L) + +typedef LONG NTSTATUS; + +// +// umode methods +// +BOOL RegisterDriver(LPCWSTR lpDriverName, LPCWSTR lpPathName); +BOOL StartDriver(LPCWSTR lpDriverName); +BOOL StopDriver(LPCWSTR lpDriverName); +BOOL UnregisterDriver(LPCWSTR lpDriverName); + +// +// undoc methods +// +BOOL ConvertPath(LPCWSTR lpPath, LPWSTR lpDevice); +BOOL LoadVia_SystemLoadGdiDriverInformation(LPWSTR lpDriverPath); +BOOL LoadVia_SystemExtendServiceTableInformation(LPWSTR lpDriverPath); +BOOL NtStartDriver(LPCWSTR lpService); +BOOL NtStopDriver(LPCWSTR lpService); + + +// +// undocumented stuff +// +#define SystemLoadGdiDriverInformation 26 +#define SystemExtendServiceTableInformation 38 +NTSYSAPI NTSTATUS NTAPI +NtSetSystemInformation(IN INT SystemInformationClass, + IN PVOID SystemInformation, + IN ULONG SystemInformationLength ); +NTSTATUS +NtUnloadDriver(IN PUNICODE_STRING DriverServiceName); + +typedef struct _SYSTEM_GDI_DRIVER_INFORMATION +{ + UNICODE_STRING DriverName; + PVOID ImageAddress; + PVOID SectionPointer; + PVOID EntryPoint; + PIMAGE_EXPORT_DIRECTORY ExportSectionPointer; + ULONG ImageLength; +} SYSTEM_GDI_DRIVER_INFORMATION, *PSYSTEM_GDI_DRIVER_INFORMATION; + +typedef enum _OBJECT_INFORMATION_CLASS { + ObjectBasicInformation, + ObjectNameInformation, + ObjectTypeInformation, + ObjectAllTypesInformation, + ObjectHandleInformation +} OBJECT_INFO_CLASS; + +NTSTATUS NtQueryObject(IN HANDLE Handle, + IN OBJECT_INFO_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG ObjectInformationLength, + OUT PULONG ReturnLength); + + +typedef struct _OBJECT_NAME_INFORMATION { + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + + diff --git a/rostests/win32/DriverLoading/Application/main.c b/rostests/win32/DriverLoading/Application/main.c new file mode 100644 index 00000000000..01d856a66df --- /dev/null +++ b/rostests/win32/DriverLoading/Application/main.c @@ -0,0 +1,157 @@ +#include "DriverTester.h" + +static BOOL +Initialize(LPCWSTR lpDriverPath) +{ + if (!RegisterDriver(DRIVER_NAME, lpDriverPath)) + { + wprintf(L"[%lu] Failed to install %s\n", GetLastError(), DRIVER_NAME); + return FALSE; + } + + return TRUE; +} + +static BOOL +Uninitialize(LPCWSTR lpDriverPath) +{ + if (!UnregisterDriver(DRIVER_NAME)) + { + wprintf(L"[%lu] Failed to unregister %s\n", GetLastError(), DRIVER_NAME); + return FALSE; + } + + return TRUE; +} + +static BOOL +UsermodeMethod(LPCWSTR lpDriverPath) +{ + wprintf(L"\nStarting %s.sys via the SCM\n", DRIVER_NAME); + + if (!StartDriver(DRIVER_NAME)) + { + wprintf(L"[%lu] Failed to start %s\n", GetLastError(), DRIVER_NAME); + UnregisterDriver(DRIVER_NAME); + return FALSE; + } + + wprintf(L"\tStarted\n"); + + wprintf(L"Stopping %s.sys via the SCM\n", DRIVER_NAME); + + if (!StopDriver(DRIVER_NAME)) + { + wprintf(L"[%lu] Failed to stop %s\n", GetLastError(), DRIVER_NAME); + UnregisterDriver(DRIVER_NAME); + return FALSE; + } + + wprintf(L"\tStopped\n"); + + return TRUE; +} + +static BOOL +UndocumentedMethod(LPCWSTR lpDriverPath) +{ + wprintf(L"\nStarting %s.sys via native API\n", DRIVER_NAME); + + if (!NtStartDriver(DRIVER_NAME)) + { + wprintf(L"[%lu] Failed to start %s\n", GetLastError(), DRIVER_NAME); + UnregisterDriver(DRIVER_NAME); + return FALSE; + } + + wprintf(L"\tStarted\n"); + + wprintf(L"Stopping %s.sys via native API\n", DRIVER_NAME); + + if (!NtStopDriver(DRIVER_NAME)) + { + wprintf(L"[%lu] Failed to stop %s\n", GetLastError(), DRIVER_NAME); + UnregisterDriver(DRIVER_NAME); + return FALSE; + } + + wprintf(L"\tStopped\n"); + + return TRUE; +} + + +static BOOL +SneakyUndocumentedMethods(LPCWSTR lpDriverPath) +{ + WCHAR szDevice[MAX_PATH]; + + if (ConvertPath(lpDriverPath, szDevice)) + { + wprintf(L"\nStarting %s.sys via NtSetSystemInformation with SystemLoadGdiDriverInformation\n", DRIVER_NAME); + if (LoadVia_SystemLoadGdiDriverInformation(szDevice)) + { + wprintf(L"\tStarted\n"); + + NtStopDriver(DRIVER_NAME); + } + + wprintf(L"\nStarting %s.sys via NtSetSystemInformation with SystemExtendServiceTableInformation\n", DRIVER_NAME); + if (LoadVia_SystemExtendServiceTableInformation(szDevice)) + { + wprintf(L"\tStarted\n"); + + NtStopDriver(DRIVER_NAME); + } + + return TRUE; + } + + return FALSE; +} + + +int __cdecl wmain(int argc, wchar_t *argv[]) +{ + WCHAR buf[MAX_PATH]; + + if (argc != 2) + { + wprintf(L"Usage: DriverTester.exe "); + return -1; + } + + if (!SearchPathW(NULL, + argv[1], + L".sys", + MAX_PATH, + buf, + NULL)) + { + wprintf(L"%s does not exist", argv[1]); + return -1; + } + + if (Initialize(argv[1])) + { + // + // Load using conventional SCM methods + // + UsermodeMethod(argv[1]); + + // + // Load using undocumented NtLoad/UnloadDriver + // + UndocumentedMethod(argv[1]); + + // + // Load using hidden unknown methods + // + SneakyUndocumentedMethods(argv[1]); + + Uninitialize(argv[1]); + } + + return 0; +} + diff --git a/rostests/win32/DriverLoading/Application/umode.c b/rostests/win32/DriverLoading/Application/umode.c new file mode 100644 index 00000000000..9bf10580b4c --- /dev/null +++ b/rostests/win32/DriverLoading/Application/umode.c @@ -0,0 +1,162 @@ +#include "DriverTester.h" + + +BOOL +RegisterDriver(LPCWSTR lpDriverName, + LPCWSTR lpPathName) +{ + SC_HANDLE hSCManager; + SC_HANDLE hService; + + hSCManager = OpenSCManagerW(NULL, + NULL, + SC_MANAGER_ALL_ACCESS); + if (!hSCManager) + return FALSE; + +retry: + hService = CreateServiceW(hSCManager, + lpDriverName, + lpDriverName, + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_DEMAND_START, + SERVICE_ERROR_NORMAL, + lpPathName, + NULL, + NULL, + NULL, + NULL, + NULL); + + if (hService) + { + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + return TRUE; + } + else + { + DWORD err = GetLastError(); + + if (err == ERROR_SERVICE_MARKED_FOR_DELETE) + { + StopDriver(DRIVER_NAME); + goto retry; + } + + CloseServiceHandle(hSCManager); + + // return TRUE if the driver is already registered + return (err == ERROR_SERVICE_EXISTS); + } +} + +BOOL +StartDriver(LPCWSTR lpDriverName) +{ + SC_HANDLE hSCManager; + SC_HANDLE hService; + BOOL bRet; + + hSCManager = OpenSCManagerW(NULL, + NULL, + SC_MANAGER_ALL_ACCESS); + if (!hSCManager) + return FALSE; + + hService = OpenServiceW(hSCManager, + lpDriverName, + SERVICE_ALL_ACCESS); + if (!hService) + { + CloseServiceHandle(hSCManager); + return FALSE; + } + + bRet = StartServiceW(hService, 0, NULL); + if (!bRet) + { + if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) + { + wprintf(L"%s.sys already running\n", DRIVER_NAME); + bRet = TRUE; + } + } + + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + + return bRet; +} + +BOOL +StopDriver(LPCWSTR lpDriverName) +{ + SC_HANDLE hSCManager; + SC_HANDLE hService; + SERVICE_STATUS serviceStatus; + BOOL bRet; + + hSCManager = OpenSCManagerW(NULL, + NULL, + SC_MANAGER_ALL_ACCESS); + if (!hSCManager) + return FALSE; + + hService = OpenServiceW(hSCManager, + lpDriverName, + SERVICE_ALL_ACCESS); + if (!hService) + { + CloseServiceHandle(hSCManager); + return FALSE; + } + + bRet = ControlService(hService, + SERVICE_CONTROL_STOP, + &serviceStatus); + if (!bRet) + { + if (GetLastError() == ERROR_SERVICE_NOT_ACTIVE) + { + wprintf(L"%s.sys wasn't running\n", DRIVER_NAME); + bRet = TRUE; + } + } + + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + + return bRet; +} + +BOOL +UnregisterDriver(LPCWSTR lpDriverName) +{ + SC_HANDLE hService; + SC_HANDLE hSCManager; + BOOL bRet; + + hSCManager = OpenSCManagerW(NULL, + NULL, + SC_MANAGER_ALL_ACCESS); + if (!hSCManager) + return FALSE; + + hService = OpenServiceW(hSCManager, + lpDriverName, + SERVICE_ALL_ACCESS); + if (!hService) + { + CloseServiceHandle(hSCManager); + return FALSE; + } + + bRet = DeleteService(hService); + + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + + return bRet; +} diff --git a/rostests/win32/DriverLoading/Application/undoc.c b/rostests/win32/DriverLoading/Application/undoc.c new file mode 100644 index 00000000000..6a3f8c098a6 --- /dev/null +++ b/rostests/win32/DriverLoading/Application/undoc.c @@ -0,0 +1,276 @@ +#include "DriverTester.h" + +static BOOL +SetPrivilege(BOOL bSet) +{ + TOKEN_PRIVILEGES tp; + HANDLE hToken; + LUID luid; + + if (!OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES, + &hToken)) + { + return FALSE; + } + + if(!LookupPrivilegeValue(NULL, + SE_LOAD_DRIVER_NAME, + &luid)) + { + CloseHandle(hToken); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + + if (bSet) + { + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + } + else + { + tp.Privileges[0].Attributes = 0; + } + + AdjustTokenPrivileges(hToken, + FALSE, + &tp, + sizeof(TOKEN_PRIVILEGES), + NULL, + NULL); + if (GetLastError() != ERROR_SUCCESS) + { + CloseHandle(hToken); + return FALSE; + } + + CloseHandle(hToken); + + return TRUE; +} + + +BOOL +ConvertPath(LPCWSTR lpPath, + LPWSTR lpDevice) +{ + LPWSTR lpFullPath = NULL; + DWORD size; + + if (lpPath) + { + size = GetLongPathNameW(lpPath, + 0, + 0); + if (!size) + return FALSE; + + size = (size + 1) * sizeof(WCHAR); + + lpFullPath = HeapAlloc(GetProcessHeap(), + 0, + size); + if (!lpFullPath) + return FALSE; + + if (GetLongPathNameW(lpPath, + lpFullPath, + size)) + { + HANDLE hDevice; + POBJECT_NAME_INFORMATION pObjName; + NTSTATUS Status; + DWORD len; + + hDevice = CreateFileW(lpFullPath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + HeapFree(GetProcessHeap(), 0, lpFullPath); + + if(hDevice == INVALID_HANDLE_VALUE) + { + wprintf(L"[%x] Failed to open %s\n", GetLastError(), DRIVER_NAME); + return FALSE; + } + + size = MAX_PATH * sizeof(WCHAR); + pObjName = HeapAlloc(GetProcessHeap(), 0, size); + if (!pObjName) + return FALSE; + + Status = NtQueryObject(hDevice, + ObjectNameInformation, + pObjName, + size, + &size); + if (Status == STATUS_SUCCESS) + { + len = pObjName->Name.Length / sizeof(WCHAR); + wcsncpy(lpDevice, pObjName->Name.Buffer, len); + lpDevice[len] = UNICODE_NULL; + + HeapFree(GetProcessHeap(), 0, pObjName); + + return TRUE; + } + + HeapFree(GetProcessHeap(), 0, pObjName); + } + } + + return FALSE; +} + + +BOOL +NtStartDriver(LPCWSTR lpService) +{ + WCHAR szDriverPath[MAX_PATH]; + UNICODE_STRING DriverPath; + NTSTATUS Status = -1; + + wcscpy(szDriverPath, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); + wcscat(szDriverPath, + lpService); + + RtlInitUnicodeString(&DriverPath, + szDriverPath); + + if (SetPrivilege(TRUE)) + { + Status = NtLoadDriver(&DriverPath); + if (Status != STATUS_SUCCESS) + { + DWORD err = RtlNtStatusToDosError(Status); + wprintf(L"NtUnloadDriver failed [%lu]\n", err); + } + + SetPrivilege(FALSE); + } + + return (Status == STATUS_SUCCESS); +} + + +BOOL +NtStopDriver(LPCWSTR lpService) +{ + WCHAR szDriverPath[MAX_PATH]; + UNICODE_STRING DriverPath; + NTSTATUS Status = -1; + + wcscpy(szDriverPath, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); + wcscat(szDriverPath, + lpService); + + RtlInitUnicodeString(&DriverPath, + szDriverPath); + + if (SetPrivilege(TRUE)) + { + Status = NtUnloadDriver(&DriverPath); + if (Status != STATUS_SUCCESS) + { + DWORD err = RtlNtStatusToDosError(Status); + wprintf(L"NtUnloadDriver failed [%lu]\n", err); + } + + SetPrivilege(FALSE); + } + + return (Status == STATUS_SUCCESS); +} + + +// +// We shouldn't be able to call this from umode. +// Returns true if +// +BOOL +LoadVia_SystemLoadGdiDriverInformation(LPWSTR lpDriverPath) +{ + NTSTATUS Status; + SYSTEM_GDI_DRIVER_INFORMATION Buffer; + DWORD bufSize; + + bufSize = sizeof(SYSTEM_GDI_DRIVER_INFORMATION); + + ZeroMemory(&Buffer, bufSize); + RtlInitUnicodeString(&Buffer.DriverName, lpDriverPath); + + if (SetPrivilege(TRUE)) + { + Status = NtSetSystemInformation(SystemLoadGdiDriverInformation, + &Buffer, + bufSize); + if (Status == STATUS_PRIVILEGE_NOT_HELD) + { + wprintf(L"SystemLoadGdiDriverInformation can only be used in kmode.\n"); + } + else if (Status == STATUS_SUCCESS) + { + wprintf(L"SystemLoadGdiDriverInformation incorrectly loaded the driver\n"); + NtUnloadDriver(&Buffer.DriverName); + + return TRUE; + } + else + { + DWORD err = RtlNtStatusToDosError(Status); + wprintf(L"LoadVia_SystemLoadGdiDriverInformation failed [%lu]\n", err); + } + + SetPrivilege(FALSE); + } + + return FALSE; +} + + +BOOL +LoadVia_SystemExtendServiceTableInformation(LPWSTR lpDriverPath) +{ + NTSTATUS Status; + UNICODE_STRING Buffer; + DWORD bufSize; + + RtlInitUnicodeString(&Buffer, lpDriverPath); + bufSize = sizeof(UNICODE_STRING); + + if (SetPrivilege(TRUE)) + { + Status = NtSetSystemInformation(SystemExtendServiceTableInformation, + &Buffer, + bufSize); + if (Status == STATUS_PRIVILEGE_NOT_HELD) + { + wprintf(L"SystemExtendServiceTableInformation can only be used in kmode.\n"); + } + else if (Status == STATUS_SUCCESS) + { + wprintf(L"SystemExtendServiceTableInformation incorrectly loaded the driver\n"); + NtUnloadDriver(&Buffer); + + return TRUE; + } + else + { + DWORD err = RtlNtStatusToDosError(Status); + wprintf(L"LoadVia_SystemExtendServiceTableInformation failed [%lu] - 0x%x\n", err, Status); + } + + SetPrivilege(FALSE); + } + + return FALSE; +} + diff --git a/rostests/win32/DriverLoading/Driver/Driver.vcproj b/rostests/win32/DriverLoading/Driver/Driver.vcproj new file mode 100644 index 00000000000..ed3acacdf0f --- /dev/null +++ b/rostests/win32/DriverLoading/Driver/Driver.vcproj @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rostests/win32/DriverLoading/Driver/driver.c b/rostests/win32/DriverLoading/Driver/driver.c new file mode 100644 index 00000000000..8d2e56182a8 --- /dev/null +++ b/rostests/win32/DriverLoading/Driver/driver.c @@ -0,0 +1,18 @@ +#include + +VOID +DriverUnload(PDRIVER_OBJECT pDriverObject) +{ + DbgPrint("Test driver unloaded sucessfully\n"); +} + +NTSTATUS +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + DriverObject->DriverUnload = DriverUnload; + + DbgPrint("Test driver loaded sucessfully\n"); + + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/rostests/win32/DriverLoading/DriverTester.sln b/rostests/win32/DriverLoading/DriverTester.sln new file mode 100644 index 00000000000..8be28b2176e --- /dev/null +++ b/rostests/win32/DriverLoading/DriverTester.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "Application\Application.vcproj", "{EABF0755-CD33-43CC-9062-DD5C5E0AC229}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Driver", "Driver\Driver.vcproj", "{983A51E3-3E69-4C26-B34B-7F17089CD4E3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EABF0755-CD33-43CC-9062-DD5C5E0AC229}.Debug|Win32.ActiveCfg = Debug|Win32 + {EABF0755-CD33-43CC-9062-DD5C5E0AC229}.Debug|Win32.Build.0 = Debug|Win32 + {EABF0755-CD33-43CC-9062-DD5C5E0AC229}.Release|Win32.ActiveCfg = Release|Win32 + {EABF0755-CD33-43CC-9062-DD5C5E0AC229}.Release|Win32.Build.0 = Release|Win32 + {983A51E3-3E69-4C26-B34B-7F17089CD4E3}.Debug|Win32.ActiveCfg = Debug|Win32 + {983A51E3-3E69-4C26-B34B-7F17089CD4E3}.Debug|Win32.Build.0 = Debug|Win32 + {983A51E3-3E69-4C26-B34B-7F17089CD4E3}.Release|Win32.ActiveCfg = Release|Win32 + {983A51E3-3E69-4C26-B34B-7F17089CD4E3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal