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

Aric Stewart aric at codeweavers.com
Wed Aug 24 07:05:09 CDT 2016


Signed-off-by: Aric Stewart <aric at codeweavers.com>

On 8/23/16 11:11 PM, Sebastian Lackner wrote:
> Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
> ---
> 
> Changes in v2:
> * Expect service name including registry prefix.
> 
>  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 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