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

Alexandre Julliard julliard at winehq.org
Thu Aug 25 10:39:37 CDT 2016


Module: wine
Branch: master
Commit: a7e9fa625327a4f50d25053e092783a7e82f8584
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=a7e9fa625327a4f50d25053e092783a7e82f8584

Author: Sebastian Lackner <sebastian at fds-team.de>
Date:   Wed Aug 24 06:11:07 2016 +0200

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

Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
Signed-off-by: Aric Stewart <aric at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntoskrnl.exe/Makefile.in       |   1 +
 dlls/ntoskrnl.exe/ntoskrnl.c        | 183 ++++++++++++++++++++++++++++++++++--
 dlls/ntoskrnl.exe/ntoskrnl.exe.spec |   4 +-
 3 files changed, 180 insertions(+), 8 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..7c35d14 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"
@@ -66,6 +68,13 @@ KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4] = { { 0 } };
 typedef void (WINAPI *PCREATE_PROCESS_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN);
 typedef void (WINAPI *PCREATE_THREAD_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN);
 
+static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
+                                  '\\','M','a','c','h','i','n','e',
+                                  '\\','S','y','s','t','e','m',
+                                  '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
+                                  '\\','S','e','r','v','i','c','e','s',
+                                  '\\',0};
+
 /* tid of the thread running client request */
 static DWORD request_thread;
 
@@ -871,12 +880,6 @@ PIRP WINAPI IoBuildSynchronousFsdRequest(ULONG majorfunc, PDEVICE_OBJECT device,
 static void build_driver_keypath( const WCHAR *name, UNICODE_STRING *keypath )
 {
     static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
-    static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
-                                      '\\','M','a','c','h','i','n','e',
-                                      '\\','S','y','s','t','e','m',
-                                      '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
-                                      '\\','S','e','r','v','i','c','e','s',
-                                      '\\',0};
     WCHAR *str;
 
     /* Check what prefix is present */
@@ -2641,3 +2644,171 @@ 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 *service_name, SC_HANDLE *service )
+{
+    QUERY_SERVICE_CONFIGW *service_config = NULL;
+    SC_HANDLE manager_handle;
+    DWORD config_size = 0;
+    WCHAR *name;
+
+    if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, service_name->Length + sizeof(WCHAR) )))
+        return STATUS_NO_MEMORY;
+
+    memcpy( name, service_name->Buffer, service_name->Length );
+    name[ service_name->Length / sizeof(WCHAR) ] = 0;
+
+    if (strncmpW( name, servicesW, strlenW(servicesW) ))
+    {
+        FIXME( "service name %s is not a keypath\n", debugstr_us(service_name) );
+        RtlFreeHeap( GetProcessHeap(), 0, name );
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    if (!(manager_handle = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
+    {
+        WARN( "failed to connect to service manager\n" );
+        RtlFreeHeap( GetProcessHeap(), 0, name );
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    *service = OpenServiceW( manager_handle, name + strlenW(servicesW), SERVICE_ALL_ACCESS );
+    RtlFreeHeap( GetProcessHeap(), 0, name );
+    CloseServiceHandle( manager_handle );
+
+    if (!*service)
+    {
+        WARN( "failed to open service %s\n", debugstr_us(service_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(service_name) );
+        goto error;
+    }
+
+    TRACE( "opened service for driver %s\n", debugstr_us(service_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 *service_name )
+{
+    SERVICE_STATUS_PROCESS service_status;
+    SC_HANDLE service_handle;
+    NTSTATUS status;
+    DWORD bytes;
+    int i;
+
+    TRACE( "(%s)\n", debugstr_us(service_name) );
+
+    if ((status = open_driver( service_name, &service_handle )) != STATUS_SUCCESS)
+        return status;
+
+    TRACE( "trying to start %s\n", debugstr_us(service_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(service_name) );
+
+        status = STATUS_SUCCESS;
+        goto done;
+    }
+
+error:
+    WARN( "failed to start service %s\n", debugstr_us(service_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 *service_name )
+{
+    SERVICE_STATUS service_status;
+    SC_HANDLE service_handle;
+    NTSTATUS status;
+    int i;
+
+    TRACE( "(%s)\n", debugstr_us(service_name) );
+
+    if ((status = open_driver( service_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(service_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 fd820a7..119d406 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




More information about the wine-cvs mailing list