ntoskrnl.exe: Implement ZwLoadDriver and ZwUnloadDriver based on services API.

Sebastian Lackner sebastian at fds-team.de
Mon Aug 22 09:12:53 CDT 2016


Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---

This hides the complicated services API behind some easy to use functions :)
The timeout are a bit arbitrary and can be adjusted if they do not work well
enough in practice. Based on Arics feedback this solution is confirmed to work
for his purpose.

 dlls/ntoskrnl.exe/Makefile.in       |    1 
 dlls/ntoskrnl.exe/ntoskrnl.c        |  164 ++++++++++++++++++++++++++++++++++++
 dlls/ntoskrnl.exe/ntoskrnl.exe.spec |    4 
 3 files changed, 167 insertions(+), 2 deletions(-)

diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in
index 875be8e..b459c54 100644
--- a/dlls/ntoskrnl.exe/Makefile.in
+++ b/dlls/ntoskrnl.exe/Makefile.in
@@ -1,5 +1,6 @@
 MODULE    = ntoskrnl.exe
 IMPORTLIB = ntoskrnl
+IMPORTS   = advapi32
 
 C_SRCS = \
 	instr.c \
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index d9ebc40..fab767f 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2007 Alexandre Julliard
  * Copyright (C) 2010 Damjan Jovanovic
+ * Copyright (C) 2016 Sebastian Lackner
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,6 +31,7 @@
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
 #include "windef.h"
+#include "winsvc.h"
 #include "winternl.h"
 #include "excpt.h"
 #include "winioctl.h"
@@ -2641,3 +2643,165 @@ NTSTATUS WINAPI IoAttachDevice(DEVICE_OBJECT *source, UNICODE_STRING *target, DE
     FIXME("(%p, %s, %p): stub\n", source, debugstr_us(target), attached);
     return STATUS_NOT_IMPLEMENTED;
 }
+
+
+static NTSTATUS open_driver( const UNICODE_STRING *driver_name, SC_HANDLE *service )
+{
+    QUERY_SERVICE_CONFIGW *service_config = NULL;
+    SC_HANDLE manager_handle;
+    DWORD config_size = 0;
+    WCHAR *name;
+
+    if (!(manager_handle = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
+    {
+        WARN( "failed to connect to service manager\n" );
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, driver_name->Length + sizeof(WCHAR) )))
+    {
+        CloseServiceHandle( manager_handle );
+        return STATUS_NO_MEMORY;
+    }
+
+    memcpy( name, driver_name->Buffer, driver_name->Length );
+    name[ driver_name->Length/sizeof(WCHAR) ] = 0;
+    *service = OpenServiceW( manager_handle, name, SERVICE_ALL_ACCESS );
+    HeapFree( GetProcessHeap(), 0, name );
+    CloseServiceHandle( manager_handle );
+
+    if (!*service)
+    {
+        WARN( "failed to open service %s\n", debugstr_us(driver_name) );
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    QueryServiceConfigW( *service, NULL, 0, &config_size );
+    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+    {
+        WARN( "failed to query service config\n" );
+        goto error;
+    }
+
+    if (!(service_config = RtlAllocateHeap( GetProcessHeap(), 0, config_size )))
+        goto error;
+
+    if (!QueryServiceConfigW( *service, service_config, config_size, &config_size ))
+    {
+        WARN( "failed to query service config\n" );
+        goto error;
+    }
+
+    if (service_config->dwServiceType != SERVICE_KERNEL_DRIVER &&
+        service_config->dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)
+    {
+        WARN( "service %s is not a kernel driver\n", debugstr_us(driver_name) );
+        goto error;
+    }
+
+    TRACE( "opened service for driver %s\n", debugstr_us(driver_name) );
+    RtlFreeHeap( GetProcessHeap(), 0, service_config );
+    return STATUS_SUCCESS;
+
+error:
+    CloseServiceHandle( *service );
+    RtlFreeHeap( GetProcessHeap(), 0, service_config );
+    return STATUS_UNSUCCESSFUL;
+}
+
+
+/***********************************************************************
+ *           ZwLoadDriver (NTOSKRNL.EXE.@)
+ */
+NTSTATUS WINAPI ZwLoadDriver( const UNICODE_STRING *driver_name )
+{
+    SERVICE_STATUS_PROCESS service_status;
+    SC_HANDLE service_handle;
+    NTSTATUS status;
+    DWORD bytes;
+    int i;
+
+    TRACE( "(%s)\n", debugstr_us(driver_name) );
+
+    if ((status = open_driver( driver_name, &service_handle )) != STATUS_SUCCESS)
+        return status;
+
+    TRACE( "trying to start %s\n", debugstr_us(driver_name) );
+
+    for (i = 0; i < 100; i++)  /* 10 sec timeout */
+    {
+        if (StartServiceW( service_handle, 0, NULL )) break;
+        if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) break;
+        if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) goto error;
+        Sleep(100);
+    }
+    if (i == 100) goto error;
+
+    for (i = 0; i < 100; i++)  /* 10 sec timeout */
+    {
+        if (!QueryServiceStatusEx( service_handle, SC_STATUS_PROCESS_INFO,
+                                   (BYTE *)&service_status, sizeof(service_status), &bytes )) goto error;
+        if (service_status.dwCurrentState != SERVICE_START_PENDING) break;
+        Sleep(100);
+    }
+
+    if (service_status.dwCurrentState == SERVICE_RUNNING)
+    {
+        if (service_status.dwProcessId != GetCurrentProcessId())
+            FIXME( "driver %s was loaded into a different process\n", debugstr_us(driver_name) );
+
+        status = STATUS_SUCCESS;
+        goto done;
+    }
+
+error:
+    WARN( "failed to start service %s\n", debugstr_us(driver_name) );
+    status = STATUS_UNSUCCESSFUL;
+
+done:
+    TRACE( "returning status %08x\n", status );
+    CloseServiceHandle( service_handle );
+    return status;
+}
+
+
+/***********************************************************************
+ *           ZwUnloadDriver (NTOSKRNL.EXE.@)
+ */
+NTSTATUS WINAPI ZwUnloadDriver( const UNICODE_STRING *driver_name )
+{
+    SERVICE_STATUS service_status;
+    SC_HANDLE service_handle;
+    NTSTATUS status;
+    int i;
+
+    TRACE( "(%s)\n", debugstr_us(driver_name) );
+
+    if ((status = open_driver( driver_name, &service_handle )) != STATUS_SUCCESS)
+        return status;
+
+    if (!ControlService( service_handle, SERVICE_CONTROL_STOP, &service_status ))
+        goto error;
+
+    for (i = 0; i < 100; i++)  /* 10 sec timeout */
+    {
+        if (!QueryServiceStatus( service_handle, &service_status )) goto error;
+        if (service_status.dwCurrentState != SERVICE_STOP_PENDING) break;
+        Sleep(100);
+    }
+
+    if (service_status.dwCurrentState == SERVICE_STOPPED)
+    {
+        status = STATUS_SUCCESS;
+        goto done;
+    }
+
+error:
+    WARN( "failed to stop service %s\n", debugstr_us(driver_name) );
+    status = STATUS_UNSUCCESSFUL;
+
+done:
+    TRACE( "returning status %08x\n", status );
+    CloseServiceHandle( service_handle );
+    return status;
+}
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 5acfe6f..5408e91 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -1314,7 +1314,7 @@
 @ stdcall ZwFsControlFile(long long long long long long long long long long) ntdll.ZwFsControlFile
 @ stdcall ZwInitiatePowerAction(long long long long) ntdll.ZwInitiatePowerAction
 @ stdcall ZwIsProcessInJob(long long) ntdll.ZwIsProcessInJob
-@ stdcall ZwLoadDriver(ptr) ntdll.ZwLoadDriver
+@ stdcall ZwLoadDriver(ptr)
 @ stdcall ZwLoadKey(ptr ptr) ntdll.ZwLoadKey
 @ stdcall ZwMakeTemporaryObject(long) ntdll.ZwMakeTemporaryObject
 @ stdcall ZwMapViewOfSection(long long ptr long long ptr ptr long long long) ntdll.ZwMapViewOfSection
@@ -1384,7 +1384,7 @@
 @ stdcall ZwTerminateJobObject(long long) ntdll.ZwTerminateJobObject
 @ stdcall ZwTerminateProcess(long long) ntdll.ZwTerminateProcess
 @ stub ZwTranslateFilePath
-@ stdcall ZwUnloadDriver(ptr) ntdll.ZwUnloadDriver
+@ stdcall ZwUnloadDriver(ptr)
 @ stdcall ZwUnloadKey(long) ntdll.ZwUnloadKey
 @ stdcall ZwUnmapViewOfSection(long ptr) ntdll.ZwUnmapViewOfSection
 @ stdcall ZwWaitForMultipleObjects(long ptr long long ptr) ntdll.ZwWaitForMultipleObjects
-- 
2.9.0



More information about the wine-patches mailing list