Index: /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h	(revision 53002)
@@ -61,4 +61,17 @@
 # define SUP_NT_STATUS_IS_VBOX(a_rcNt)          ( ((uint32_t)(a_rcNt) & 0xffff0000) == SUP_NT_STATUS_BASE )
 # define SUP_NT_STATUS_TO_VBOX(a_rcNt)          ( (int)((uint32_t)(a_rcNt) | UINT32_C(0xffff0000)) )
+
+/** NT device name for system access. */
+# define SUPDRV_NT_DEVICE_NAME_SYS              L"\\Device\\VBoxDrv"
+/** NT device name for user access. */
+# define SUPDRV_NT_DEVICE_NAME_USR              L"\\Device\\VBoxDrvU"
+# ifdef VBOX_WITH_HARDENING
+/** NT device name for hardened stub access. */
+#  define SUPDRV_NT_DEVICE_NAME_STUB            L"\\Device\\VBoxDrvStub"
+/** NT device name for getting error information for failed VBoxDrv or
+ * VBoxDrvStub open. */
+#  define SUPDRV_NT_DEVICE_NAME_ERROR_INFO      L"\\Device\\VBoxDrvErrorInfo"
+# endif
+
 
 #elif defined(RT_OS_SOLARIS)
Index: /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/SUPLib.cpp	(revision 53002)
@@ -262,5 +262,6 @@
      * Open the support driver.
      */
-    int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted);
+    SUPINITOP enmWhat = kSupInitOp_Driver;
+    int rc = suplibOsInit(&g_supLibData, g_fPreInited, fUnrestricted, &enmWhat, NULL);
     if (RT_SUCCESS(rc))
     {
Index: /trunk/src/VBox/HostDrivers/Support/SUPLibInternal.h
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPLibInternal.h	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/SUPLibInternal.h	(revision 53002)
@@ -352,5 +352,5 @@
 int     suplibOsInstall(void);
 int     suplibOsUninstall(void);
-int     suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted);
+int     suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo);
 int     suplibOsTerm(PSUPLIBDATA pThis);
 int     suplibOsHardenedVerifyInit(void);
@@ -471,4 +471,5 @@
 DECLHIDDEN(void)    supR3HardenedWinCompactHeaps(void);
 DECLHIDDEN(void)    supR3HardenedMainOpenDevice(void);
+DECLHIDDEN(char *)  supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_t cbErrorInfo, const char *pszPrefix);
 DECLHIDDEN(void)    supR3HardenedWinReportErrorToParent(const char *pszWhere, SUPINITOP enmWhat, int rc,
                                                         const char *pszFormat, va_list va);
Index: /trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/SUPR3HardenedMain.cpp	(revision 53002)
@@ -1232,32 +1232,31 @@
 DECLHIDDEN(void) supR3HardenedMainOpenDevice(void)
 {
-    int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/);
+    RTERRINFOSTATIC ErrInfo;
+    SUPINITOP       enmWhat = kSupInitOp_Driver;
+    int rc = suplibOsInit(&g_SupPreInitData.Data, false /*fPreInit*/, true /*fUnrestricted*/,
+                          &enmWhat, RTErrInfoInitStatic(&ErrInfo));
     if (RT_SUCCESS(rc))
         return;
 
+    if (RTErrInfoIsSet(&ErrInfo.Core))
+        supR3HardenedFatalMsg("suplibOsInit", enmWhat, rc, "%s", ErrInfo.szMsg);
+
     switch (rc)
     {
         /** @todo better messages! */
         case VERR_VM_DRIVER_NOT_INSTALLED:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel driver not installed");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not installed");
         case VERR_VM_DRIVER_NOT_ACCESSIBLE:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel driver not accessible");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver not accessible");
         case VERR_VM_DRIVER_LOAD_ERROR:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "VERR_VM_DRIVER_LOAD_ERROR");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_LOAD_ERROR");
         case VERR_VM_DRIVER_OPEN_ERROR:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "VERR_VM_DRIVER_OPEN_ERROR");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_VM_DRIVER_OPEN_ERROR");
         case VERR_VM_DRIVER_VERSION_MISMATCH:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel driver version mismatch");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel driver version mismatch");
         case VERR_ACCESS_DENIED:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "VERR_ACCESS_DENIED");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "VERR_ACCESS_DENIED");
         case VERR_NO_MEMORY:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Kernel memory allocation/mapping failed");
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Kernel memory allocation/mapping failed");
         case VERR_SUPDRV_HARDENING_EVIL_HANDLE:
             supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPDRV_HARDENING_EVIL_HANDLE");
@@ -1269,6 +1268,5 @@
             supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Integrity, rc, "VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2");
         default:
-            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc,
-                                  "Unknown rc=%d", rc);
+            supR3HardenedFatalMsg("suplibOsInit", kSupInitOp_Driver, rc, "Unknown rc=%d (%Rrc)", rc, rc);
     }
 }
Index: /trunk/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/darwin/SUPLib-darwin.cpp	(revision 53002)
@@ -186,5 +186,5 @@
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
Index: /trunk/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/freebsd/SUPLib-freebsd.cpp	(revision 53002)
@@ -68,5 +68,5 @@
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
Index: /trunk/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp	(revision 53002)
@@ -75,5 +75,5 @@
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
Index: /trunk/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/os2/SUPLib-os2.cpp	(revision 53002)
@@ -66,5 +66,5 @@
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
Index: /trunk/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/solaris/SUPLib-solaris.cpp	(revision 53002)
@@ -78,5 +78,5 @@
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp	(revision 53002)
@@ -42,4 +42,5 @@
 #include <iprt/power.h>
 #include <iprt/rand.h>
+#include <iprt/semaphore.h>
 #include <iprt/spinlock.h>
 #include <iprt/string.h>
@@ -62,17 +63,21 @@
 #define SUPDRV_NT_POOL_TAG  'xoBV'
 
-/** NT device name for system access. */
-#define DEVICE_NAME_NT_SYS      L"\\Device\\VBoxDrv"
 /** NT device name for user access. */
-#define DEVICE_NAME_NT_USR      L"\\Device\\VBoxDrvU"
+#define DEVICE_NAME_NT_USR          L"\\Device\\VBoxDrvU"
 #ifdef VBOX_WITH_HARDENING
-/** NT device name for hardened stub access. */
-# define DEVICE_NAME_NT_STUB    L"\\Device\\VBoxDrvStub"
-
 /** Macro for checking for deflecting calls to the stub device. */
 # define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) \
-    do { if ((a_pDevObj) == g_pDevObjStub) supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); } while (0)
+    do { if ((a_pDevObj) == g_pDevObjStub) \
+            return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
+    } while (0)
+/** Macro for checking for deflecting calls to the stub and error info
+ *  devices. */
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) \
+    do { if ((a_pDevObj) == g_pDevObjStub || (a_pDevObj) == g_pDevObjErrorInfo) \
+            return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
+    } while (0)
 #else
-# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) do {} while (0)
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp)                 do {} while (0)
+# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp)   do {} while (0)
 #endif
 
@@ -109,5 +114,5 @@
 
 /**
- * Device extension used by VBoxDrvS.
+ * Device extension used by VBoxDrvStub.
  */
 typedef struct SUPDRVDEVEXTSTUB
@@ -116,8 +121,43 @@
     SUPDRVDEVEXTUSR     Common;
 } SUPDRVDEVEXTSTUB;
-/** Pointer to the VBoxDrvS device extension. */
+/** Pointer to the VBoxDrvStub device extension. */
 typedef SUPDRVDEVEXTSTUB *PSUPDRVDEVEXTSTUB;
 /** Value of SUPDRVDEVEXTSTUB::Common.u32Cookie. */
 #define SUPDRVDEVEXTSTUB_COOKIE      UINT32_C(0x90abcdef)
+
+
+/**
+ * Device extension used by VBoxDrvErrorInfo.
+ */
+typedef struct SUPDRVDEVEXTERRORINFO
+{
+    /** Common header. */
+    SUPDRVDEVEXTUSR     Common;
+} SUPDRVDEVEXTERRORINFO;
+/** Pointer to the VBoxDrvErrorInfo device extension. */
+typedef SUPDRVDEVEXTERRORINFO *PSUPDRVDEVEXTERRORINFO;
+/** Value of SUPDRVDEVEXTERRORINFO::Common.u32Cookie. */
+#define SUPDRVDEVEXTERRORINFO_COOKIE      UINT32_C(0xBadC0ca0)
+
+/**
+ * Error info for a failed VBoxDrv or VBoxDrvStub open attempt.
+ */
+typedef struct SUPDRVNTERRORINFO
+{
+    /** The list entry (in g_ErrorInfoHead). */
+    RTLISTNODE      ListEntry;
+    /** The ID of the process this error info belongs to.  */
+    HANDLE          hProcessId;
+    /** The ID of the thread owning this info. */
+    HANDLE          hThreadId;
+    /** Milliseconds createion timestamp (for cleaning up).  */
+    uint64_t        uCreatedMsTs;
+    /** Number of bytes of valid info. */
+    uint32_t        cchErrorInfo;
+    /** The error info. */
+    char            szErrorInfo[2048];
+} SUPDRVNTERRORINFO;
+/** Pointer to error info. */
+typedef SUPDRVNTERRORINFO *PSUPDRVNTERRORINFO;
 
 
@@ -247,4 +287,5 @@
 static NTSTATUS _stdcall   VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
 static VOID     _stdcall   VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
+static NTSTATUS _stdcall   VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp);
 static NTSTATUS _stdcall   VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
 static NTSTATUS            VBoxDrvNtErr2NtStatus(int rc);
@@ -260,4 +301,6 @@
 
 static bool                 supdrvNtIsDebuggerAttached(void);
+static void                 supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId);
+
 #endif
 
@@ -355,4 +398,11 @@
 static POBJECT_TYPE volatile        g_pAlpcPortObjectType2 = NULL;
 
+/** Pointer to the error information device instance. */
+static PDEVICE_OBJECT               g_pDevObjErrorInfo = NULL;
+/** Fast mutex semaphore protecting the error info list. */
+static RTSEMMUTEX                   g_hErrorInfoLock = NIL_RTSEMMUTEX;
+/** Head of the error info (SUPDRVNTERRORINFO). */
+static RTLISTANCHOR                 g_ErrorInfoHead;
+
 #endif
 
@@ -370,5 +420,5 @@
      */
     UNICODE_STRING DevName;
-    RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_SYS);
+    RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_SYS);
     NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
     if (NT_SUCCESS(rcNt))
@@ -377,5 +427,5 @@
          * User device.
          */
-        RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_USR);
+        RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_USR);
         rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
         if (NT_SUCCESS(rcNt))
@@ -389,5 +439,5 @@
              * Hardened stub device.
              */
-            RtlInitUnicodeString(&DevName, DEVICE_NAME_NT_STUB);
+            RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_STUB);
             rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
             if (NT_SUCCESS(rcNt))
@@ -398,9 +448,31 @@
                     pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
                     pDevExtStub->Common.u32Cookie   = SUPDRVDEVEXTSTUB_COOKIE;
+
+                    /*
+                     * Hardened error information device.
+                     */
+                    RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
+                    rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTERRORINFO), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE,
+                                          &g_pDevObjErrorInfo);
+                    if (NT_SUCCESS(rcNt))
+                    {
+                        g_pDevObjErrorInfo->Flags |= DO_BUFFERED_IO;
+
+                        if (NT_SUCCESS(rcNt))
+                        {
+                            PSUPDRVDEVEXTERRORINFO pDevExtStub = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
+                            pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
+                            pDevExtStub->Common.u32Cookie   = SUPDRVDEVEXTERRORINFO_COOKIE;
+
 #endif
-
-                    /* Done. */
-                    return rcNt;
+                            /* Done. */
+                            return rcNt;
 #ifdef VBOX_WITH_HARDENING
+                        }
+
+                        /* Bail out. */
+                        IoDeleteDevice(g_pDevObjErrorInfo);
+                        g_pDevObjErrorInfo = NULL;
+                    }
                 }
 
@@ -435,7 +507,14 @@
         pDevExtStub->Common.pMainDrvExt = NULL;
     }
+    if (g_pDevObjErrorInfo)
+    {
+        PSUPDRVDEVEXTERRORINFO pDevExtErrorInfo = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
+        pDevExtErrorInfo->Common.pMainDrvExt = NULL;
+    }
 #endif
 
 #ifdef VBOX_WITH_HARDENING
+    IoDeleteDevice(g_pDevObjErrorInfo);
+    g_pDevObjErrorInfo = NULL;
     IoDeleteDevice(g_pDevObjStub);
     g_pDevObjStub = NULL;
@@ -512,5 +591,5 @@
                     pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]           = VBoxDrvNtDeviceControl;
                     pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL]  = VBoxDrvNtInternalDeviceControl;
-                    pDrvObj->MajorFunction[IRP_MJ_READ]                     = VBoxDrvNtNotSupportedStub;
+                    pDrvObj->MajorFunction[IRP_MJ_READ]                     = VBoxDrvNtRead;
                     pDrvObj->MajorFunction[IRP_MJ_WRITE]                    = VBoxDrvNtNotSupportedStub;
 
@@ -663,4 +742,14 @@
         rcNt = STATUS_ACCESS_DENIED;
     }
+#ifdef VBOX_WITH_HARDENING
+    /*
+     * Anyone can open the error device.
+     */
+    else if (pDevObj == g_pDevObjErrorInfo)
+    {
+        pFileObj->FsContext = NULL;
+        return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
+    }
+#endif
     else
     {
@@ -838,4 +927,6 @@
         }
     }
+    else if (pDevObj == g_pDevObjErrorInfo)
+        supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
     else
 #endif
@@ -878,4 +969,6 @@
         }
     }
+    else if (pDevObj == g_pDevObjErrorInfo)
+        supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
     else
 #endif
@@ -917,11 +1010,20 @@
                                                      PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
 {
-    PSUPDRVDEVEXT   pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
+    /*
+     * Only the normal devices, not the stub or error info ones.
+     */
+    if (pDevObj != g_pDevObjSys && pDevObj != g_pDevObjUsr)
+    {
+        pIoStatus->Status      = STATUS_NOT_SUPPORTED;
+        pIoStatus->Information = 0;
+        return TRUE;
+    }
 
     /*
      * Check the input a little bit and get a the session references.
      */
-    PSUPDRVSESSION  pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
-                                                          (PSUPDRVSESSION *)&pFileObj->FsContext);
+    PSUPDRVDEVEXT  pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
+    PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
+                                                         (PSUPDRVSESSION *)&pFileObj->FsContext);
     if (!pSession)
     {
@@ -1102,5 +1204,5 @@
 NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
 {
-    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
+    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
 
     PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
@@ -1244,5 +1346,5 @@
 NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
 {
-    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(pDevObj, pIrp);
+    VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
 
     PSUPDRVDEVEXT       pDevExt  = SUPDRVNT_GET_DEVEXT(pDevObj);
@@ -1322,4 +1424,113 @@
     pIrp->IoStatus.Status = rcNt;
     pIrp->IoStatus.Information = cbOut;
+    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+    return rcNt;
+}
+
+
+/**
+ * Implementation of the read major function for VBoxDrvErrorInfo.
+ *
+ * This is a stub function for the other devices.
+ *
+ * @returns NT status code.
+ * @param   pDevObj             The device object.
+ * @param   pIrp                The I/O request packet.
+ */
+NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
+{
+    Log(("VBoxDrvNtRead\n"));
+
+    NTSTATUS rcNt;
+    pIrp->IoStatus.Information = 0;
+
+#ifdef VBOX_WITH_HARDENING
+    /*
+     * VBoxDrvErrorInfo?
+     */
+    if (pDevObj == g_pDevObjErrorInfo)
+    {
+        PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
+        if (   pStack
+            && (pIrp->Flags & IRP_BUFFERED_IO))
+        {
+            /*
+             * Look up the process error information.
+             */
+            HANDLE hCurThreadId  = PsGetCurrentThreadId();
+            HANDLE hCurProcessId = PsGetCurrentProcessId();
+            int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+            if (RT_SUCCESS(rc))
+            {
+                PSUPDRVNTERRORINFO  pCur;
+                RTListForEach(&g_ErrorInfoHead, pCur, SUPDRVNTERRORINFO, ListEntry)
+                {
+                    if (   pCur->hProcessId == hCurProcessId
+                        && pCur->hThreadId  == hCurThreadId)
+                        break;
+                }
+
+                /*
+                 * Did we find error info and is the caller requesting data within it?
+                 * If so, cehck the destination buffer and copy the data into it.
+                 */
+                if (   pCur
+                    && pStack->Parameters.Read.ByteOffset.QuadPart < pCur->cchErrorInfo
+                    && pStack->Parameters.Read.ByteOffset.QuadPart >= 0)
+                {
+                    PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
+                    if (pvDstBuf)
+                    {
+                        uint32_t offRead  = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
+                        uint32_t cbToRead = pCur->cchErrorInfo - (uint32_t)offRead;
+                        if (cbToRead > pStack->Parameters.Read.Length)
+                        {
+                            cbToRead = pStack->Parameters.Read.Length;
+                            RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
+                        }
+                        memcpy(pvDstBuf, &pCur->szErrorInfo[offRead], cbToRead);
+                        pIrp->IoStatus.Information = cbToRead;
+
+                        rcNt = STATUS_SUCCESS;
+                    }
+                    else
+                        rcNt = STATUS_INVALID_ADDRESS;
+                }
+                /*
+                 * End of file. Free the info.
+                 */
+                else if (pCur)
+                {
+                    RTListNodeRemove(&pCur->ListEntry);
+                    RTMemFree(pCur);
+                    rcNt = STATUS_END_OF_FILE;
+                }
+                /*
+                 * We found no error info. Return EOF.
+                 */
+                else
+                    rcNt = STATUS_END_OF_FILE;
+
+                RTSemMutexRelease(g_hErrorInfoLock);
+            }
+            else
+                rcNt = STATUS_UNSUCCESSFUL;
+        }
+        else
+            rcNt = STATUS_INVALID_PARAMETER;
+    }
+    else
+#endif /* VBOX_WITH_HARDENING */
+    {
+        /*
+         * Stub.
+         */
+        rcNt = STATUS_NOT_SUPPORTED;
+    }
+
+    /*
+     * Complete the request.
+     */
+    pIrp->IoStatus.Status = rcNt;
     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
     return rcNt;
@@ -2591,4 +2802,29 @@
  * @{ */
 
+
+/**
+ * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
+ *
+ * @param   hProcessId          The ID of the dead process.
+ */
+static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
+{
+    int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+    if (RT_SUCCESS(rc))
+    {
+        PSUPDRVNTERRORINFO pCur, pNext;
+        RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
+        {
+            if (pCur->hProcessId == hProcessId)
+            {
+                RTListNodeRemove(&pCur->ListEntry);
+                RTMemFree(pCur);
+            }
+        }
+        RTSemMutexRelease(g_hErrorInfoLock);
+    }
+}
+
+
 /**
  * Common worker used by the process creation hooks as well as the process
@@ -2837,5 +3073,8 @@
      */
     else
+    {
         supdrvNtProtectUnprotectDeadProcess(hNewPid);
+        supdrvNtErrorInfoCleanupProcess(hNewPid);
+    }
 }
 
@@ -2893,5 +3132,8 @@
      */
     else
+    {
         supdrvNtProtectUnprotectDeadProcess(hNewPid);
+        supdrvNtErrorInfoCleanupProcess(hNewPid);
+    }
 }
 
@@ -3614,6 +3856,7 @@
  * @param   pNtProtect          The NT protect structure for getting information
  *                              about special processes.
- */
-static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect)
+ * @param   pErrInfo            Where to return additional error details.
+ */
+static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
 {
     /*
@@ -3644,5 +3887,5 @@
             pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
             if (!pbBuf)
-                return VERR_NO_MEMORY;
+                return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
             rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
         }
@@ -3650,5 +3893,6 @@
         {
             RTMemFree(pbBuf);
-            return RTErrConvertFromNtStatus(rcNt);
+            return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
+                                 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
         }
     }
@@ -3764,5 +4008,22 @@
                     pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
                     pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
-            rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
+            rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
+                               *pErrInfo->pszMsg
+                               ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
+                               : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
+                               pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
+                               pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
+
+            /* Try add the process name. */
+            PEPROCESS pOffendingProcess;
+            rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
+            if (NT_SUCCESS(rcNt))
+            {
+                const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
+                if (pszName && *pszName)
+                    rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
+
+                ObDereferenceObject(pOffendingProcess);
+            }
         }
     }
@@ -3789,20 +4050,24 @@
      */
     int rc = VINF_SUCCESS;
-    if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
-        rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect);
+    PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
     if (RT_SUCCESS(rc))
     {
-        char szErr[256];
-        RT_ZERO(szErr);
+        pErrorInfo->hProcessId = PsGetCurrentProcessId();
+        pErrorInfo->hThreadId  = PsGetCurrentThreadId();
         RTERRINFO ErrInfo;
-        RTErrInfoInit(&ErrInfo, szErr, sizeof(szErr));
-
-        rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY,
-                                         NULL /*pcFixes*/, &ErrInfo);
-        if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
-            rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
-        if (RT_FAILURE(rc))
-            RTLogWriteDebugger(szErr, strlen(szErr));
-    }
+        RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
+
+        if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
+            rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
+        if (RT_SUCCESS(rc))
+        {
+            rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY,
+                                             NULL /*pcFixes*/, &ErrInfo);
+            if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
+                rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
 
     /*
@@ -3863,4 +4128,42 @@
 
     RTSpinlockRelease(g_hNtProtectLock);
+
+    /*
+     * Free error info on success, keep it on failure.
+     */
+    if (RT_SUCCESS(rc))
+        RTMemFree(pErrorInfo);
+    else if (pErrorInfo)
+    {
+        pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
+        if (!pErrorInfo->cchErrorInfo)
+            pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
+                                                             "supdrvNtProtectVerifyProcess: rc=%d", rc);
+        if (RT_FAILURE(rc))
+            RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
+
+        int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
+        if (RT_SUCCESS(rc2))
+        {
+            pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
+
+            /* Free old entries. */
+            PSUPDRVNTERRORINFO pCur;
+            while (   (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
+                   && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
+            {
+                RTListNodeRemove(&pCur->ListEntry);
+                RTMemFree(pCur);
+            }
+
+            /* Insert our new entry. */
+            RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
+
+            RTSemMutexRelease(g_hErrorInfoLock);
+        }
+        else
+            RTMemFree(pErrorInfo);
+    }
+
     return rc;
 }
@@ -3912,4 +4215,14 @@
     RTSpinlockDestroy(g_hNtProtectLock);
     g_NtProtectTree = NIL_RTSPINLOCK;
+
+    RTSemMutexDestroy(g_hErrorInfoLock);
+    g_hErrorInfoLock = NIL_RTSEMMUTEX;
+
+    PSUPDRVNTERRORINFO pCur;
+    while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
+    {
+        RTListNodeRemove(&pCur->ListEntry);
+        RTMemFree(pCur);
+    }
 
     supHardenedWinTermImageVerifier();
@@ -4081,117 +4394,129 @@
     g_NtProtectTree = NULL;
 
-    /* Image stuff + certificates. */
     NTSTATUS rcNt;
-    rc = supHardenedWinInitImageVerifier(NULL);
+
+    /* The mutex protecting the error information. */
+    RTListInit(&g_ErrorInfoHead);
+    rc = RTSemMutexCreate(&g_hErrorInfoLock);
     if (RT_SUCCESS(rc))
     {
-        /*
-         * Intercept process creation and termination.
-         */
-        if (g_pfnPsSetCreateProcessNotifyRoutineEx)
-            rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
-        else
-            rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
-        if (NT_SUCCESS(rcNt))
+        /* Image stuff + certificates. */
+        rc = supHardenedWinInitImageVerifier(NULL);
+        if (RT_SUCCESS(rc))
         {
             /*
-             * Intercept process and thread handle creation calls.
-             * The preferred method is only available on Vista SP1+.
+             * Intercept process creation and termination.
              */
-            if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
-            {
-                static OB_OPERATION_REGISTRATION s_aObOperations[] =
+            if (g_pfnPsSetCreateProcessNotifyRoutineEx)
+                rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
+            else
+                rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
+            if (NT_SUCCESS(rcNt))
+            {
+                /*
+                 * Intercept process and thread handle creation calls.
+                 * The preferred method is only available on Vista SP1+.
+                 */
+                if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
                 {
+                    static OB_OPERATION_REGISTRATION s_aObOperations[] =
                     {
-                        PsProcessType,
-                        OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
-                        supdrvNtProtectCallback_ProcessHandlePre,
-                        supdrvNtProtectCallback_ProcessHandlePost,
-                    },
+                        {
+                            PsProcessType,
+                            OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
+                            supdrvNtProtectCallback_ProcessHandlePre,
+                            supdrvNtProtectCallback_ProcessHandlePost,
+                        },
+                        {
+                            PsThreadType,
+                            OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
+                            supdrvNtProtectCallback_ThreadHandlePre,
+                            supdrvNtProtectCallback_ThreadHandlePost,
+                        },
+                    };
+                    static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
                     {
-                        PsThreadType,
-                        OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
-                        supdrvNtProtectCallback_ThreadHandlePre,
-                        supdrvNtProtectCallback_ThreadHandlePost,
-                    },
-                };
-                static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
-                {
-                    /* .Version                     = */ OB_FLT_REGISTRATION_VERSION,
-                    /* .OperationRegistrationCount  = */ RT_ELEMENTS(s_aObOperations),
-                    /* .Altitude.Length             = */ 0,
-                    /* .Altitude.MaximumLength      = */ 0,
-                    /* .Altitude.Buffer             = */ NULL,
-                    /* .RegistrationContext         = */ NULL,
-                    /* .OperationRegistration       = */ &s_aObOperations[0]
-                };
-                static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
-                {
-                     L"48596.98940",  L"46935.19485",  L"49739.39704",  L"40334.74976",
-                     L"66667.98940",  L"69888.19485",  L"69889.39704",  L"60364.74976",
-                     L"85780.98940",  L"88978.19485",  L"89939.39704",  L"80320.74976",
-                     L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
-                };
-
-                rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
-                for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
-                {
-                    s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
-                    s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
-                    s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
-
-                    rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
-                    if (NT_SUCCESS(rcNt))
+                        /* .Version                     = */ OB_FLT_REGISTRATION_VERSION,
+                        /* .OperationRegistrationCount  = */ RT_ELEMENTS(s_aObOperations),
+                        /* .Altitude.Length             = */ 0,
+                        /* .Altitude.MaximumLength      = */ 0,
+                        /* .Altitude.Buffer             = */ NULL,
+                        /* .RegistrationContext         = */ NULL,
+                        /* .OperationRegistration       = */ &s_aObOperations[0]
+                    };
+                    static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
                     {
-                        /*
-                         * Happy ending.
-                         */
-                        return STATUS_SUCCESS;
+                         L"48596.98940",  L"46935.19485",  L"49739.39704",  L"40334.74976",
+                         L"66667.98940",  L"69888.19485",  L"69889.39704",  L"60364.74976",
+                         L"85780.98940",  L"88978.19485",  L"89939.39704",  L"80320.74976",
+                         L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
+                    };
+
+                    rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
+                    for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
+                    {
+                        s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
+                        s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
+                        s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
+
+                        rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
+                        if (NT_SUCCESS(rcNt))
+                        {
+                            /*
+                             * Happy ending.
+                             */
+                            return STATUS_SUCCESS;
+                        }
                     }
-                }
-                LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
-                g_pvObCallbacksCookie = NULL;
-            }
-            else
-            {
-                /*
-                 * For the time being, we do not implement extra process
-                 * protection on pre-Vista-SP1 systems as they are lacking
-                 * necessary KPIs.  XP is end of life, we do not wish to
-                 * spend more time on it, so we don't put up a fuss there.
-                 * Vista users without SP1 can install SP1 (or later), darn it,
-                 * so refuse to load.
-                 */
-                /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
-                 *        stuff to a couple of object types. */
-# ifndef VBOX_WITH_VISTA_NO_SP
-                if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
-# else
-                if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
-# endif
-                {
-                    DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
-                    rcNt = STATUS_SXS_VERSION_CONFLICT;
+                    LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
+                    g_pvObCallbacksCookie = NULL;
                 }
                 else
                 {
-                    Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
-                    return rcNt = STATUS_SUCCESS;
+                    /*
+                     * For the time being, we do not implement extra process
+                     * protection on pre-Vista-SP1 systems as they are lacking
+                     * necessary KPIs.  XP is end of life, we do not wish to
+                     * spend more time on it, so we don't put up a fuss there.
+                     * Vista users without SP1 can install SP1 (or later), darn it,
+                     * so refuse to load.
+                     */
+                    /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
+                     *        stuff to a couple of object types. */
+# ifndef VBOX_WITH_VISTA_NO_SP
+                    if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
+# else
+                    if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
+# endif
+                    {
+                        DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
+                        rcNt = STATUS_SXS_VERSION_CONFLICT;
+                    }
+                    else
+                    {
+                        Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
+                        return rcNt = STATUS_SUCCESS;
+                    }
+                    g_pvObCallbacksCookie = NULL;
                 }
-                g_pvObCallbacksCookie = NULL;
-            }
-
-            /*
-             * Drop process create/term notifications.
-             */
-            if (g_pfnPsSetCreateProcessNotifyRoutineEx)
-                g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
+
+                /*
+                 * Drop process create/term notifications.
+                 */
+                if (g_pfnPsSetCreateProcessNotifyRoutineEx)
+                    g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
+                else
+                    PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
+            }
             else
-                PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
+                LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
+                        g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
+            supHardenedWinTermImageVerifier();
         }
         else
-            LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
-                    g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
-        supHardenedWinTermImageVerifier();
+            rcNt = VBoxDrvNtErr2NtStatus(rc);
+
+        RTSemMutexDestroy(g_hErrorInfoLock);
+        g_hErrorInfoLock = NIL_RTSEMMUTEX;
     }
     else
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp	(revision 53002)
@@ -110,5 +110,5 @@
 
 
-int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted)
+int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
 {
     /*
@@ -117,5 +117,5 @@
     int rc = suplibOsHardenedVerifyInit();
     if (RT_FAILURE(rc))
-        return rc;
+        return RTErrInfoSetF(pErrInfo, rc, "suplibOsHardenedVerifyInit failed: %Rrc", rc);
 
     /*
@@ -170,56 +170,95 @@
         if (NT_SUCCESS(rcNt))
             rcNt = Ios.Status;
-        if (!NT_SUCCESS(rcNt))
-        {
+        if (NT_SUCCESS(rcNt))
+        {
+            /*
+             * We're good.
+             */
+            pThis->hDevice       = hDevice;
+            pThis->fUnrestricted = fUnrestricted;
+            return VINF_SUCCESS;
+        }
+
 #ifndef IN_SUP_HARDENED_R3
-            /*
-             * Failed to open, try starting the service and reopen the device
-             * exactly once.
-             */
-            if (cTry == 0 && !NT_SUCCESS(rcNt))
-            {
-                cTry++;
-                suplibOsStartService();
-                continue;
-            }
-#endif
-            switch (rcNt)
-            {
-                /** @todo someone must test what is actually returned. */
-                case STATUS_DEVICE_DOES_NOT_EXIST:
-                case STATUS_DEVICE_NOT_CONNECTED:
-                //case ERROR_BAD_DEVICE:
-                case STATUS_DEVICE_REMOVED:
-                //case ERROR_DEVICE_NOT_AVAILABLE:
-                    return VERR_VM_DRIVER_LOAD_ERROR;
-                case STATUS_OBJECT_PATH_NOT_FOUND:
-                case STATUS_NO_SUCH_DEVICE:
-                case STATUS_NO_SUCH_FILE:
-                case STATUS_OBJECT_NAME_NOT_FOUND:
-                    return VERR_VM_DRIVER_NOT_INSTALLED;
-                case STATUS_ACCESS_DENIED:
-                case STATUS_SHARING_VIOLATION:
-                    return VERR_VM_DRIVER_NOT_ACCESSIBLE;
-                case STATUS_UNSUCCESSFUL:
-                    return VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0;
-                case STATUS_TRUST_FAILURE:
-                    return VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1;
-                case STATUS_TOO_LATE:
-                    return VERR_SUPDRV_HARDENING_EVIL_HANDLE;
-                default:
-                    if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
-                        return SUP_NT_STATUS_TO_VBOX(rcNt);
-                    return VERR_VM_DRIVER_OPEN_ERROR;
-            }
-        }
-        break;
-    }
-
-    /*
-     * We're done.
-     */
-    pThis->hDevice       = hDevice;
-    pThis->fUnrestricted = fUnrestricted;
-    return VINF_SUCCESS;
+        /*
+         * Failed to open, try starting the service and reopen the device
+         * exactly once.
+         */
+        if (cTry == 0 && !NT_SUCCESS(rcNt))
+        {
+            cTry++;
+            suplibOsStartService();
+            continue;
+        }
+#endif
+
+        /*
+         * Translate the error code.
+         */
+        switch (rcNt)
+        {
+            /** @todo someone must test what is actually returned. */
+            case STATUS_DEVICE_DOES_NOT_EXIST:
+            case STATUS_DEVICE_NOT_CONNECTED:
+            //case ERROR_BAD_DEVICE:
+            case STATUS_DEVICE_REMOVED:
+            //case ERROR_DEVICE_NOT_AVAILABLE:
+                rc = VERR_VM_DRIVER_LOAD_ERROR;
+                break;
+            case STATUS_OBJECT_PATH_NOT_FOUND:
+            case STATUS_NO_SUCH_DEVICE:
+            case STATUS_NO_SUCH_FILE:
+            case STATUS_OBJECT_NAME_NOT_FOUND:
+                rc = VERR_VM_DRIVER_NOT_INSTALLED;
+                break;
+            case STATUS_ACCESS_DENIED:
+            case STATUS_SHARING_VIOLATION:
+                rc = VERR_VM_DRIVER_NOT_ACCESSIBLE;
+                break;
+            case STATUS_UNSUCCESSFUL:
+                rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0;
+                break;
+            case STATUS_TRUST_FAILURE:
+                rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1;
+                break;
+            case STATUS_TOO_LATE:
+                rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
+                break;
+            default:
+                if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
+                    rc = SUP_NT_STATUS_TO_VBOX(rcNt);
+                else
+                    rc = VERR_VM_DRIVER_OPEN_ERROR;
+                break;
+        }
+
+#ifdef IN_SUP_HARDENED_R3
+        /*
+         * Get more details from VBoxDrvErrorInfo if present.
+         */
+        if (pErrInfo && pErrInfo->cbMsg > 32)
+        {
+            /* Prefix. */
+            size_t      cchPrefix;
+            const char *pszDefine = RTErrGetDefine(rc);
+            if (strncmp(pszDefine, RT_STR_TUPLE("Unknown")))
+                cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%s): ", rcNt, pszDefine);
+            else
+                cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%d): ", rcNt, rc);
+
+            /* Get error info. */
+            supR3HardenedWinReadErrorInfoDevice(pErrInfo->pszMsg + cchPrefix, pErrInfo->cbMsg - cchPrefix, "");
+            if (pErrInfo->pszMsg[cchPrefix] != '\0')
+            {
+                pErrInfo->fFlags |= RTERRINFO_FLAGS_SET;
+                pErrInfo->rc      = rc;
+                *penmWhat = kSupInitOp_Integrity;
+            }
+            else
+                pErrInfo->pszMsg[0] = '\0';
+        }
+#endif
+        return rc;
+    }
 }
 
Index: /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp	(revision 53001)
+++ /trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp	(revision 53002)
@@ -4186,4 +4186,68 @@
 
 /**
+ * Tries to open VBoxDrvErrorInfo and read extra error info from it.
+ *
+ * @returns pszErrorInfo.
+ * @param   pszErrorInfo        The destination buffer.  Will always be
+ *                              terminated.
+ * @param   cbErrorInfo         The size of the destination buffer.
+ * @param   pszPrefix           What to prefix the error info with, if we got
+ *                              anything.
+ */
+DECLHIDDEN(char *) supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_t cbErrorInfo, const char *pszPrefix)
+{
+    RT_BZERO(pszErrorInfo, cbErrorInfo);
+
+    /*
+     * Try open the device.
+     */
+    HANDLE              hFile  = RTNT_INVALID_HANDLE_VALUE;
+    IO_STATUS_BLOCK     Ios    = RTNT_IO_STATUS_BLOCK_INITIALIZER;
+    UNICODE_STRING      NtName = RTNT_CONSTANT_UNISTR(SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
+    OBJECT_ATTRIBUTES   ObjAttr;
+    InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
+    NTSTATUS rcNt = NtCreateFile(&hFile,
+                                 GENERIC_READ,
+                                 &ObjAttr,
+                                 &Ios,
+                                 NULL /* Allocation Size*/,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 FILE_OPEN,
+                                 FILE_NON_DIRECTORY_FILE,
+                                 NULL /*EaBuffer*/,
+                                 0 /*EaLength*/);
+    if (NT_SUCCESS(rcNt))
+        rcNt = Ios.Status;
+    if (NT_SUCCESS(rcNt))
+    {
+        /*
+         * Try read error info.
+         */
+        size_t cchPrefix = strlen(pszPrefix);
+        if (cchPrefix + 3 < cbErrorInfo)
+        {
+            LARGE_INTEGER offRead;
+            offRead.QuadPart = 0;
+            rcNt = NtReadFile(hFile, NULL /*hEvent*/, NULL /*ApcRoutine*/, NULL /*ApcContext*/, &Ios,
+                              &pszErrorInfo[cchPrefix], (ULONG)(cbErrorInfo - cchPrefix - 1), &offRead, NULL);
+            if (NT_SUCCESS(rcNt))
+            {
+                memcpy(pszErrorInfo, pszPrefix, cchPrefix);
+                pszErrorInfo[cbErrorInfo - 1] = '\0';
+            }
+            else
+                *pszErrorInfo = '\0';
+        }
+        else
+            RTStrCopy(pszErrorInfo, cbErrorInfo, "error info buffer too small");
+        NtClose(hFile);
+    }
+    return pszErrorInfo;
+}
+
+
+
+/**
  * Checks if the driver exists.
  *
@@ -4270,5 +4334,5 @@
      * Retry if we think driver might still be initializing (STATUS_NO_SUCH_DEVICE + \Drivers\VBoxDrv).
      */
-    static const WCHAR  s_wszName[] = L"\\Device\\VBoxDrvStub";
+    static const WCHAR  s_wszName[] = SUPDRV_NT_DEVICE_NAME_STUB;
     uint64_t const      uMsTsStart = supR3HardenedWinGetMilliTS();
     NTSTATUS            rcNt;
@@ -4334,4 +4398,5 @@
          * better chance resolving the issue.
          */
+        char szErrorInfo[_4K];
         int rc = VERR_OPEN_FAILED;
         if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
@@ -4359,4 +4424,5 @@
                 supR3HardenedWinLogObjDir("\\Windows");
                 supR3HardenedWinLogObjDir("\\Sessions");
+
                 supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Misc, rc,
                                       "NtCreateFile(%ls) failed: VERR_SUPDRV_APIPORT_OPEN_ERROR\n"
@@ -4366,6 +4432,8 @@
                                       "Could be due to security software is redirecting access to it, so please include full "
                                       "details of such software in a bug report. VBoxStartup.log may contain details important "
-                                      "to resolving the issue."
-                                      , s_wszName, szDir);
+                                      "to resolving the issue.%s"
+                                      , s_wszName, szDir,
+                                      supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                          "\n\nVBoxDrvStub error: "));
             }
 
@@ -4374,5 +4442,7 @@
              */
             supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, rc,
-                                  "NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)\n", s_wszName, rc, rcNt);
+                                  "NtCreateFile(%ls) failed: %Rrc (rcNt=%#x)%s", s_wszName, rc, rcNt,
+                                  supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                    "\nVBoxDrvStub error: "));
         }
         else
@@ -4403,6 +4473,8 @@
                                           "\n"
                                           "Driver is probably stuck stopping/starting. Try 'sc.exe query vboxdrv' to get more "
-                                          "information about its state. Rebooting may actually help.\n"
-                                          , s_wszName, rcNt, pszDefine, iTry);
+                                          "information about its state. Rebooting may actually help.%s"
+                                          , s_wszName, rcNt, pszDefine, iTry,
+                                          supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                              "\nVBoxDrvStub error: "));
                 else
                     supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
@@ -4410,11 +4482,16 @@
                                           "\n"
                                           "Driver is does not appear to be loaded. Try 'sc.exe start vboxdrv', reinstall "
-                                          "VirtualBox or reboot.\n"
-                                          , s_wszName, rcNt, pszDefine, iTry);
+                                          "VirtualBox or reboot.%s"
+                                          , s_wszName, rcNt, pszDefine, iTry,
+                                          supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                              "\nVBoxDrvStub error: "));
             }
 
             /* Generic NT failure message. */
             supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Driver, VERR_OPEN_FAILED,
-                                  "NtCreateFile(%ls) failed: %#x%s (%u retries)\n", s_wszName, rcNt, pszDefine, iTry);
+                                  "NtCreateFile(%ls) failed: %#x%s (%u retries)%s",
+                                  s_wszName, rcNt, pszDefine, iTry,
+                                  supR3HardenedWinReadErrorInfoDevice(szErrorInfo, sizeof(szErrorInfo),
+                                                                      "\nVBoxDrvStub error: "));
         }
     }
