Hardware/KernelDriver.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
parent 367 45215572a774
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
moel@236
     1
/*
moel@236
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@236
     6
 
moel@367
     7
  Copyright (C) 2010-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@236
     9
*/
moel@236
    10
moel@236
    11
using System;
moel@237
    12
using System.IO;
moel@236
    13
using System.Runtime.InteropServices;
moel@237
    14
using System.Security.AccessControl;
moel@236
    15
using Microsoft.Win32.SafeHandles;
moel@236
    16
moel@236
    17
namespace OpenHardwareMonitor.Hardware {
moel@236
    18
  internal class KernelDriver {
moel@236
    19
moel@236
    20
    private string id;
moel@236
    21
moel@236
    22
    private SafeFileHandle device; 
moel@236
    23
    
moel@236
    24
    public KernelDriver(string id) {
moel@236
    25
      this.id = id;
moel@236
    26
    }
moel@236
    27
   
moel@367
    28
    public bool Install(string path, out string errorMessage) {
moel@236
    29
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
    30
        ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
    31
moel@367
    32
      if (manager == IntPtr.Zero) {
moel@367
    33
        errorMessage = "OpenSCManager returned zero.";
moel@236
    34
        return false;
moel@367
    35
      }
moel@236
    36
moel@236
    37
      IntPtr service = NativeMethods.CreateService(manager, id, id,
moel@236
    38
        ServiceAccessRights.SERVICE_ALL_ACCESS,
moel@236
    39
        ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
moel@236
    40
        ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
moel@236
    41
        null);
moel@236
    42
moel@236
    43
      if (service == IntPtr.Zero) {
moel@380
    44
        if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS) {
moel@380
    45
          errorMessage = "Service already exists";
moel@380
    46
          return false;
moel@380
    47
        } else {
moel@367
    48
          errorMessage = "CreateService returned the error: " +
moel@367
    49
            Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()).Message;
moel@380
    50
          NativeMethods.CloseServiceHandle(manager);
moel@236
    51
          return false;
moel@367
    52
        }
moel@236
    53
      }
moel@236
    54
moel@236
    55
      if (!NativeMethods.StartService(service, 0, null)) {
moel@367
    56
        if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING) {
moel@367
    57
          errorMessage = "StartService returned the error: " +
moel@367
    58
            Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()).Message;
moel@367
    59
          NativeMethods.CloseServiceHandle(service);
moel@367
    60
          NativeMethods.CloseServiceHandle(manager);
moel@236
    61
          return false;
moel@367
    62
        }
moel@236
    63
      }
moel@236
    64
moel@236
    65
      NativeMethods.CloseServiceHandle(service);
moel@236
    66
      NativeMethods.CloseServiceHandle(manager);
moel@237
    67
      
moel@237
    68
      try {
moel@237
    69
        // restrict the driver access to system (SY) and builtin admins (BA)
moel@237
    70
        // TODO: replace with a call to IoCreateDeviceSecure in the driver
moel@237
    71
        FileSecurity fileSecurity = File.GetAccessControl(@"\\.\" + id);
moel@237
    72
        fileSecurity.SetSecurityDescriptorSddlForm(
moel@237
    73
          "O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
moel@237
    74
        File.SetAccessControl(@"\\.\" + id, fileSecurity);
moel@237
    75
      } catch { }
moel@367
    76
moel@367
    77
      errorMessage = null;
moel@236
    78
      return true;
moel@236
    79
    }
moel@236
    80
moel@236
    81
    public bool Open() {
moel@236
    82
      device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
moel@236
    83
        FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
moel@236
    84
        CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
moel@236
    85
        IntPtr.Zero), true);
moel@236
    86
moel@236
    87
      if (device.IsInvalid) {
moel@236
    88
        device.Close();
moel@236
    89
        device.Dispose();
moel@236
    90
        device = null;
moel@236
    91
      }
moel@236
    92
moel@236
    93
      return device != null;
moel@236
    94
    }
moel@236
    95
moel@236
    96
    public bool IsOpen {
moel@236
    97
      get { return device != null; }
moel@236
    98
    }
moel@236
    99
moel@236
   100
    public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
moel@236
   101
      if (device == null)
moel@236
   102
        return false;
moel@236
   103
moel@236
   104
      uint bytesReturned;
moel@236
   105
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   106
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   107
        null, 0, out bytesReturned, IntPtr.Zero);
moel@236
   108
      return b;
moel@236
   109
    }
moel@236
   110
moel@236
   111
    public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
moel@236
   112
      ref T outBuffer) 
moel@236
   113
    {
moel@236
   114
      if (device == null)
moel@236
   115
        return false;
moel@236
   116
moel@236
   117
      object boxedOutBuffer = outBuffer;
moel@236
   118
      uint bytesReturned;
moel@236
   119
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   120
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   121
        boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
moel@236
   122
        out bytesReturned, IntPtr.Zero);
moel@236
   123
      outBuffer = (T)boxedOutBuffer;
moel@236
   124
      return b;
moel@236
   125
    }
moel@236
   126
moel@236
   127
    public void Close() {
moel@236
   128
      if (device != null) {
moel@236
   129
        device.Close();
moel@236
   130
        device.Dispose();
moel@236
   131
        device = null;
moel@236
   132
      }
moel@236
   133
    }
moel@236
   134
moel@236
   135
    public bool Delete() {
moel@236
   136
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
   137
      ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
   138
moel@236
   139
      if (manager == IntPtr.Zero)
moel@236
   140
        return false;      
moel@236
   141
moel@236
   142
      IntPtr service = NativeMethods.OpenService(manager, id,
moel@236
   143
        ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
   144
moel@236
   145
      if (service == IntPtr.Zero)
moel@236
   146
        return true;
moel@236
   147
moel@236
   148
      ServiceStatus status = new ServiceStatus();
moel@236
   149
      NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
moel@236
   150
        ref status);
moel@236
   151
moel@236
   152
      NativeMethods.DeleteService(service);
moel@236
   153
moel@236
   154
      NativeMethods.CloseServiceHandle(service);
moel@236
   155
      NativeMethods.CloseServiceHandle(manager);
moel@236
   156
      
moel@236
   157
      return true;
moel@236
   158
    }
moel@236
   159
moel@236
   160
    private enum ServiceAccessRights : uint {
moel@236
   161
      SERVICE_ALL_ACCESS = 0xF01FF
moel@236
   162
    }
moel@236
   163
moel@236
   164
    private enum ServiceControlManagerAccessRights : uint {
moel@236
   165
      SC_MANAGER_ALL_ACCESS = 0xF003F
moel@236
   166
    }
moel@236
   167
moel@236
   168
    private enum ServiceType : uint {
moel@236
   169
      SERVICE_KERNEL_DRIVER = 1,
moel@236
   170
      SERVICE_FILE_SYSTEM_DRIVER = 2
moel@236
   171
    }
moel@236
   172
moel@236
   173
    private enum StartType : uint {
moel@236
   174
      SERVICE_BOOT_START = 0,
moel@236
   175
      SERVICE_SYSTEM_START = 1,
moel@236
   176
      SERVICE_AUTO_START = 2,
moel@236
   177
      SERVICE_DEMAND_START = 3,
moel@236
   178
      SERVICE_DISABLED = 4
moel@236
   179
    }
moel@236
   180
moel@236
   181
    private enum ErrorControl : uint {
moel@236
   182
      SERVICE_ERROR_IGNORE = 0,
moel@236
   183
      SERVICE_ERROR_NORMAL = 1,
moel@236
   184
      SERVICE_ERROR_SEVERE = 2,
moel@236
   185
      SERVICE_ERROR_CRITICAL = 3
moel@236
   186
    }
moel@236
   187
moel@236
   188
    private enum ServiceControl : uint {
moel@236
   189
      SERVICE_CONTROL_STOP = 1,
moel@236
   190
      SERVICE_CONTROL_PAUSE = 2,
moel@236
   191
      SERVICE_CONTROL_CONTINUE = 3,
moel@236
   192
      SERVICE_CONTROL_INTERROGATE = 4,
moel@236
   193
      SERVICE_CONTROL_SHUTDOWN = 5,
moel@236
   194
      SERVICE_CONTROL_PARAMCHANGE = 6,
moel@236
   195
      SERVICE_CONTROL_NETBINDADD = 7,
moel@236
   196
      SERVICE_CONTROL_NETBINDREMOVE = 8,
moel@236
   197
      SERVICE_CONTROL_NETBINDENABLE = 9,
moel@236
   198
      SERVICE_CONTROL_NETBINDDISABLE = 10,
moel@236
   199
      SERVICE_CONTROL_DEVICEEVENT = 11,
moel@236
   200
      SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
moel@236
   201
      SERVICE_CONTROL_POWEREVENT = 13,
moel@236
   202
      SERVICE_CONTROL_SESSIONCHANGE = 14
moel@236
   203
    }
moel@236
   204
moel@236
   205
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   206
    private struct ServiceStatus {
moel@236
   207
      public uint dwServiceType;
moel@236
   208
      public uint dwCurrentState;
moel@236
   209
      public uint dwControlsAccepted;
moel@236
   210
      public uint dwWin32ExitCode;
moel@236
   211
      public uint dwServiceSpecificExitCode;
moel@236
   212
      public uint dwCheckPoint;
moel@236
   213
      public uint dwWaitHint;
moel@236
   214
    }
moel@236
   215
moel@236
   216
    private enum FileAccess : uint {
moel@236
   217
      GENERIC_READ = 0x80000000,
moel@236
   218
      GENERIC_WRITE = 0x40000000
moel@236
   219
    }
moel@236
   220
moel@236
   221
    private enum CreationDisposition : uint {
moel@236
   222
      CREATE_NEW = 1,
moel@236
   223
      CREATE_ALWAYS = 2,
moel@236
   224
      OPEN_EXISTING = 3,
moel@236
   225
      OPEN_ALWAYS = 4,
moel@236
   226
      TRUNCATE_EXISTING = 5
moel@236
   227
    }
moel@236
   228
moel@236
   229
    private enum FileAttributes : uint {
moel@236
   230
      FILE_ATTRIBUTE_NORMAL = 0x80
moel@236
   231
    }
moel@236
   232
moel@236
   233
    private const int
moel@236
   234
      ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
moel@236
   235
      ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
moel@236
   236
moel@236
   237
    private static class NativeMethods {
moel@236
   238
      private const string ADVAPI = "advapi32.dll";
moel@236
   239
      private const string KERNEL = "kernel32.dll";
moel@236
   240
moel@236
   241
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   242
      public static extern IntPtr OpenSCManager(string machineName,
moel@236
   243
        string databaseName, ServiceControlManagerAccessRights dwAccess);
moel@236
   244
moel@236
   245
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   246
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   247
      public static extern bool CloseServiceHandle(IntPtr hSCObject);
moel@236
   248
moel@236
   249
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   250
        SetLastError = true)]
moel@236
   251
      public static extern IntPtr CreateService(IntPtr hSCManager,
moel@236
   252
        string lpServiceName, string lpDisplayName, 
moel@236
   253
        ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
moel@236
   254
        StartType dwStartType, ErrorControl dwErrorControl,
moel@236
   255
        string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
moel@236
   256
        string lpDependencies, string lpServiceStartName, string lpPassword);
moel@236
   257
moel@236
   258
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   259
        SetLastError = true)]
moel@236
   260
      public static extern IntPtr OpenService(IntPtr hSCManager,
moel@236
   261
        string lpServiceName, ServiceAccessRights dwDesiredAccess);
moel@236
   262
moel@236
   263
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   264
        SetLastError = true)]
moel@236
   265
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   266
      public static extern bool DeleteService(IntPtr hService);
moel@236
   267
moel@236
   268
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   269
        SetLastError = true)]
moel@236
   270
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   271
      public static extern bool StartService(IntPtr hService, 
moel@236
   272
        uint dwNumServiceArgs, string[] lpServiceArgVectors);
moel@236
   273
moel@236
   274
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   275
        SetLastError = true)]
moel@236
   276
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   277
      public static extern bool ControlService(IntPtr hService,
moel@236
   278
        ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
moel@236
   279
moel@236
   280
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   281
      public static extern bool DeviceIoControl(SafeFileHandle device,
moel@236
   282
        IOControlCode ioControlCode, 
moel@236
   283
        [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
moel@236
   284
        uint inBufferSize,
moel@236
   285
        [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
moel@236
   286
        uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
moel@236
   287
moel@236
   288
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
moel@236
   289
        SetLastError = true)]
moel@236
   290
      public static extern IntPtr CreateFile(string lpFileName,
moel@236
   291
        FileAccess dwDesiredAccess, uint dwShareMode, 
moel@236
   292
        IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
moel@236
   293
        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
moel@236
   294
    }
moel@236
   295
  }
moel@236
   296
}