SUPR3HardenedMain-win.cpp revision ee6e158c08eec8c8cbec363eb13d9ecd81a5d105
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * VirtualBox Support Library - Hardened main(), windows bits.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Copyright (C) 2006-2014 Oracle Corporation
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * available from http://www.virtualbox.org. This file is free software;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * General Public License (GPL) as published by the Free Software
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * The contents of this file may alternatively be used under the terms
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * of the Common Development and Distribution License Version 1.0
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * VirtualBox OSE distribution, in which case the provisions of the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * CDDL are applicable instead of those of the GPL.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * You may elect to license modified versions of this file under the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * terms and conditions of either the GPL or the CDDL or both.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/*******************************************************************************
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync* Header Files *
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync*******************************************************************************/
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync/*******************************************************************************
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync* Defined Constants And Macros *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync*******************************************************************************/
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The first argument of a respawed stub when respawned for the first time.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * This just needs to be unique enough to avoid most confusion with real
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * executable names, there are other checks in place to make sure we've respanwed. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPR3_RESPAWN_1_ARG0 "60eaff78-4bdd-042d-2e72-669728efd737-suplib-2ndchild"
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The first argument of a respawed stub when respawned for the second time.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * This just needs to be unique enough to avoid most confusion with real
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * executable names, there are other checks in place to make sure we've respanwed. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPR3_RESPAWN_2_ARG0 "60eaff78-4bdd-042d-2e72-669728efd737-suplib-3rdchild"
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Unconditional assertion. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync supR3HardenedFatal("%s: %s\n", __FUNCTION__, #a_Expr); \
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync } while (0)
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/** Unconditional assertion of NT_SUCCESS. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, rcNtAssert); \
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync } while (0)
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync/** Unconditional assertion of a WIN32 API returning non-FALSE. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync#define SUPR3HARDENED_ASSERT_WIN32_SUCCESS(a_Expr) \
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync supR3HardenedFatal("%s: %s -> %#x\n", __FUNCTION__, #a_Expr, RtlGetLastWin32Error()); \
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync } while (0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/*******************************************************************************
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync* Structures and Typedefs *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync*******************************************************************************/
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Security descriptor cleanup structure.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to security cleanup structure. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Image verifier cache entry.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Pointer to the next entry with the same hash value. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Next entry in the WinVerifyTrust todo list. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The file handle. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** If fIndexNumber is set, this is an file system internal file identifier. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The path hash value. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The verification result. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Used for shutting up load and error messages after a while so they don't
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * flood the the log file and fill up the disk. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The validation flags (for WinVerifyTrust retry). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Whether IndexNumber is valid */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Whether verified by WinVerifyTrust. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync bool volatile fWinVerifyTrust;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** cwcPath * sizeof(RTUTF16). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The full path of this entry (variable size). */
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync/** Pointer to an image verifier path entry. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Name of an import DLL that we need to check out.
11b175175a0ed424b8e8354acda681ad0adde0f8vboxsync /** Pointer to the next DLL in the list. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The length of pwszAltSearchDir if available. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** This points the directory containing the DLL needing it, this will be
11b175175a0ed424b8e8354acda681ad0adde0f8vboxsync * NULL for a System32 DLL. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The name of the import DLL (variable length). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to a import DLL that needs checking out. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Child requests.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Perform child purification and close full access handles (must be zero). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Close the events, we're good on our own from here on. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Reporting error. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** End of valid requests. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Child process parameters.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The event semaphore the child will be waiting on. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The event semaphore the parent will be waiting on. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The address of the NTDLL. This is only valid during the very early
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * initialization as we abuse for thread creation protection. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The requested operation (set by the child). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The last status. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The init operation the error relates to if message, kSupInitOp_Invalid if
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * not message. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Where if message. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Error message / path name string space. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Child process data structure for use during child process init setup and
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * purification.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Process handle. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Primary thread handle. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Handle to the parent process, if we're the middle (stub) process. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The event semaphore the child will be waiting on. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The event semaphore the parent will be waiting on. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The address of NTDLL in the child. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The address of NTDLL in this process. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** Which respawn number this is (1 = stub, 2 = VM). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The basic process info. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The probable size of the PEB. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The pristine process environment block. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /** The child process parameters. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to a child process data structure. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/*******************************************************************************
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync* Global Variables *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync*******************************************************************************/
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Process parameters. Specified by parent if VM process, see
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * supR3HardenedVmProcessInit. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic SUPR3WINPROCPARAMS g_ProcParams = { NULL, NULL, 0, (SUPR3WINCHILDREQ)0, 0 };
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Set if supR3HardenedEarlyProcessInit was invoked. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Set if the stub device has been opened (stub process only). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** @name Global variables initialized by suplibHardenedWindowsMain.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Count calls to the special main function for linking santity checks. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic uint32_t volatile g_cSuplibHardenedWindowsMainCalls;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The UTF-16 windows path to the executable. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The NT path of the executable. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The offset into g_SupLibHardenedExeNtPath of the executable name (WCHAR,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * not byte). This also gives the length of the exectuable directory path,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * including a trailing slash. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** @name Hook related variables.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to the bit of assembly code that will perform the original
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * NtCreateSection operation. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic NTSTATUS (NTAPI * g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to the NtCreateSection function in NtDll (for patching purposes). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The patched NtCreateSection bytes (for restoring). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to the bit of assembly code that will perform the original
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * LdrLoadDll operation. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic NTSTATUS (NTAPI * g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Pointer to the LdrLoadDll function in NtDll (for patching purposes). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The patched LdrLoadDll bytes (for restoring). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The hash table of verifier cache . */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic PVERIFIERCACHEENTRY volatile g_apVerifierCache[128];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Queue of cached images which needs WinVerifyTrust to check them. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic PVERIFIERCACHEENTRY volatile g_pVerifierCacheTodoWvt = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Queue of cached images which needs their imports checked. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic PVERIFIERCACHEIMPORT volatile g_pVerifierCacheTodoImports = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The windows path to dir \\SystemRoot\\System32 directory (technically
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * this whatever \KnownDlls\KnownDllPath points to). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Positive if the DLL notification callback has been registered, counts
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * registration attempts as negative. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The registration cookie of the DLL notification callback. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Static error info structure used during init. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** In the assembly file. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncextern "C" uint8_t g_abSupHardReadWriteExecPage[PAGE_SIZE];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Whether we've patched our own LdrInitializeThunk or not. We do this to
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * disable thread creation. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** The backup of our own LdrInitializeThunk code, for enabling and disabling
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * thread creation in this process. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Mask of adversaries that we've detected (SUPHARDNT_ADVERSARY_XXX). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** @name SUPHARDNT_ADVERSARY_XXX - Adversaries
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Symantec endpoint protection or similar including SysPlant.sys. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPHARDNT_ADVERSARY_SYMANTEC_SYSPLANT RT_BIT_32(0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Symantec Norton 360. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPHARDNT_ADVERSARY_SYMANTEC_N360 RT_BIT_32(1)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Avast! */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** TrendMicro OfficeScan and probably others. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** TrendMicro potentially buggy sakfile.sys. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE RT_BIT_32(4)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** McAfee. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Kaspersky or OEMs of it. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Malwarebytes Anti-Malware (MBAM). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** AVG Internet Security. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Panda Security. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Microsoft Security Essentials. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Comodo. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Check Point's Zone Alarm (may include Kaspersky). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPHARDNT_ADVERSARY_ZONE_ALARM RT_BIT_32(12)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Digital guardian. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync#define SUPHARDNT_ADVERSARY_DIGITAL_GUARDIAN RT_BIT_32(13)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/** Unknown adversary detected while waiting on child. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync/*******************************************************************************
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync* Internal Functions *
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync*******************************************************************************/
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, bool fIgnoreArch, PULONG pfAccess, PULONG pfProtect,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync bool *pfCallRealApi, const char *pszCaller, bool fAvoidWinVerifyTrust,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic void supR3HardenedWinRegisterDllNotificationCallback(void);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic void supR3HardenedWinReInstallHooks(bool fFirst);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncDECLASM(void) supR3HardenedEarlyProcessInitThunk(void);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Simple wide char search routine.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns Pointer to the first location of @a wcNeedle in @a pwszHaystack.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * NULL if not found.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pwszHaystack Pointer to the string that should be searched.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param wcNeedle The character to search for.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic PRTUTF16 suplibHardenedWStrChr(PCRTUTF16 pwszHaystack, RTUTF16 wcNeedle)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Simple wide char string length routine.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns The number of characters in the given string. (Excludes the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * terminator.)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pwsz The string.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Our version of GetTickCount.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns Millisecond timestamp.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PKUSER_SHARED_DATA pUserSharedData = (PKUSER_SHARED_DATA)(uintptr_t)0x7ffe0000;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* use interrupt time */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync Time.HighPart = pUserSharedData->InterruptTime.High1Time;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync Time.LowPart = pUserSharedData->InterruptTime.LowPart;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync } while (pUserSharedData->InterruptTime.High2Time != Time.HighPart);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Wrapper around LoadLibraryEx that deals with the UTF-8 to UTF-16 conversion
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * and supplies the right flags.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns Module handle on success, NULL on failure.
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync * @param pszName The full path to the DLL.
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync * @param fSystem32Only Whether to only look for imports in the system32
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * directory. If set to false, the application
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * directory is also searched.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncDECLHIDDEN(void *) supR3HardenedWinLoadLibrary(const char *pszName, bool fSystem32Only)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync int rc = RTStrToUtf16Ex(pszName, RTSTR_MAX, &pwszPath, RT_ELEMENTS(wszPath), NULL);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync void *pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, fFlags);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Vista, W7, W2K8R might not work without KB2533623, so retry with no flags. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && RtlGetLastWin32Error() == ERROR_INVALID_PARAMETER)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pvRet = (void *)LoadLibraryExW(wszPath, NULL /*hFile*/, 0);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync supR3HardenedFatal("RTStrToUtf16Ex failed on '%s': %Rrc", pszName, rc);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Gets the internal index number of the file.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns True if we got an index number, false if not.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param hFile The file in question.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pIndexNumber where to return the index number.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic bool supR3HardenedWinVerifyCacheGetIndexNumber(HANDLE hFile, PLARGE_INTEGER pIndexNumber)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, pIndexNumber, sizeof(*pIndexNumber), FileInternalInformation);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return NT_SUCCESS(rcNt) && pIndexNumber->QuadPart != 0;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Calculates the hash value for the given UTF-16 path string.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns Hash value.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pUniStr String to hash.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic uint32_t supR3HardenedWinVerifyCacheHashPath(PCUNICODE_STRING pUniStr)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync unsigned cwcLeft = pUniStr->Length / sizeof(WCHAR);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (cwcLeft-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Calculates the hash value for a directory + filename combo as if they were
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * one single string.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns Hash value.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pawcDir The directory name.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param cwcDir The length of the directory name. RTSTR_MAX if
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * not available.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pszName The import name (UTF-8).
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic uint32_t supR3HardenedWinVerifyCacheHashDirAndFile(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (cwcDir-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Verify string cache compare function.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @returns true if the strings match, false if not.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pawcLeft The left hand string.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pawcRight The right hand string.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param cwcToCompare The number of chars to compare.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic bool supR3HardenedWinVerifyCacheIsMatch(PCRTUTF16 pawcLeft, PCRTUTF16 pawcRight, uint32_t cwcToCompare)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Try a quick memory compare first. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (memcmp(pawcLeft, pawcRight, cwcToCompare * sizeof(RTUTF16)) == 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return true;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Slow char by char compare. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (cwcToCompare-- > 0)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync wcLeft = wcLeft != '/' ? RT_C_TO_LOWER(wcLeft) : '\\';
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync wcRight = wcRight != '/' ? RT_C_TO_LOWER(wcRight) : '\\';
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return false;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync return true;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Inserts the given verifier result into the cache.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pUniStr The full path of the image.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param hFile The file handle - must either be entered into
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * the cache or closed.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param rc The verifier result.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param fWinVerifyTrust Whether verified by WinVerifyTrust or not.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param fFlags The image verification flags.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic void supR3HardenedWinVerifyCacheInsert(PCUNICODE_STRING pUniStr, HANDLE hFile, int rc,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Allocate and initalize a new entry.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PVERIFIERCACHEENTRY pEntry = (PVERIFIERCACHEENTRY)RTMemAllocZ(sizeof(VERIFIERCACHEENTRY) + pUniStr->Length);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pEntry->uHash = supR3HardenedWinVerifyCacheHashPath(pUniStr);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync memcpy(pEntry->wszPath, pUniStr->Buffer, pUniStr->Length);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pEntry->wszPath[pUniStr->Length / sizeof(WCHAR)] = '\0';
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pEntry->fIndexNumberValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &pEntry->IndexNumber);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Try insert it, careful with concurrent code as well as potential duplicates.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t iHashTab = pEntry->uHash % RT_ELEMENTS(g_apVerifierCache);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync VERIFIERCACHEENTRY * volatile *ppEntry = &g_apVerifierCache[iHashTab];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoWvt, pEntry, pEntry->pNextTodoWvt));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheInsert: %ls\n", pUniStr->Buffer));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && supR3HardenedWinVerifyCacheIsMatch(pOther->wszPath, pEntry->wszPath, pEntry->cbPath / sizeof(RTUTF16)))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Duplicate entry (may happen due to races). */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Looks up an entry in the verifier hash table.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @return Pointer to the entry on if found, NULL if not.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pUniStr The full path of the image.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param hFile The file handle.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookup(PCUNICODE_STRING pUniStr, HANDLE hFile)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t uHash = supR3HardenedWinVerifyCacheHashPath(pUniStr);
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync uint32_t iHashTab = uHash % RT_ELEMENTS(g_apVerifierCache);
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync PVERIFIERCACHEENTRY pCur = g_apVerifierCache[iHashTab];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && supR3HardenedWinVerifyCacheIsMatch(pCur->wszPath, pwszPath, cbPath / sizeof(RTUTF16)))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync bool fIndexNumberValid = supR3HardenedWinVerifyCacheGetIndexNumber(hFile, &IndexNumber);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && IndexNumber.QuadPart == pCur->IndexNumber.QuadPart)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Looks up an import DLL in the verifier hash table.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @return Pointer to the entry on if found, NULL if not.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pawcDir The directory name.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param cwcDir The length of the directory name.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pszName The import name (UTF-8).
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic PVERIFIERCACHEENTRY supR3HardenedWinVerifyCacheLookupImport(PCRTUTF16 pawcDir, uint32_t cwcDir, const char *pszName)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t uHash = supR3HardenedWinVerifyCacheHashDirAndFile(pawcDir, cwcDir, pszName);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t iHashTab = uHash % RT_ELEMENTS(g_apVerifierCache);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t const cbPath = (uint32_t)((cwcDir + 1 + strlen(pszName)) * sizeof(RTUTF16));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PVERIFIERCACHEENTRY pCur = g_apVerifierCache[iHashTab];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (supR3HardenedWinVerifyCacheIsMatch(pCur->wszPath, pawcDir, cwcDir))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pCur->wszPath[cwcDir] == '\\' || pCur->wszPath[cwcDir] == '/')
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (RTUtf16ICmpAscii(&pCur->wszPath[cwcDir + 1], pszName))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Schedules the import DLLs for verification and entry into the cache.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param hLdrMod The loader module which imports should be
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * scheduled for verification.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * @param pwszName The full NT path of the module.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncDECLHIDDEN(void) supR3HardenedWinVerifyCacheScheduleImports(RTLDRMOD hLdrMod, PCRTUTF16 pwszName)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Any imports?
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync int rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_COUNT, NULL /*pvBits*/, &cImports, sizeof(cImports), NULL);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Figure out the DLL directory from pwszName.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ((wc == '\\' || wc == '/' || wc == ':') && cwcDir + 2 != i)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( g_System32NtPath.UniStr.Length / sizeof(WCHAR) == cwcDir
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && supR3HardenedWinVerifyCacheIsMatch(pawcDir, g_System32NtPath.UniStr.Buffer, cwcDir))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Enumerate the imports.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync for (i = 0; i < cImports; i++)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_IMPORT_MODULE, NULL /*pvBits*/, &uBuf, sizeof(uBuf), NULL);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Skip kernel32, ntdll and API set stuff.
ffb50166c9adb4ae583b914d405197035cf890advboxsync || RTStrNCmp(uBuf.szName, RT_STR_TUPLE("api-ms-win-")) == 0 )
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Skip to the next one if it's already in the cache.
ffb50166c9adb4ae583b914d405197035cf890advboxsync if (supR3HardenedWinVerifyCacheLookupImport(g_System32NtPath.UniStr.Buffer,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for system32\n", uBuf.szName));
ffb50166c9adb4ae583b914d405197035cf890advboxsync if (supR3HardenedWinVerifyCacheLookupImport(g_SupLibHardenedExeNtPath.UniStr.Buffer,
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for appdir\n", uBuf.szName));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (pawcDir && supR3HardenedWinVerifyCacheLookupImport(pawcDir, cwcDir, uBuf.szName) != NULL)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: '%s' cached for dll dir\n", uBuf.szName));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* We could skip already scheduled modules, but that'll require serialization and extra work... */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Add it to the todo list.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheScheduleImports: Import todo: #%u '%s'.\n", i, uBuf.szName));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync uint32_t cbName = (uint32_t)strlen(uBuf.szName) + 1;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t cbNameAligned = RT_ALIGN_32(cbName, sizeof(RTUTF16));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint32_t cbNeeded = RT_OFFSETOF(VERIFIERCACHEIMPORT, szName[cbNameAligned])
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PVERIFIERCACHEIMPORT pImport = (PVERIFIERCACHEIMPORT)RTMemAllocZ(cbNeeded);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Init it. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync pImport->pwszAltSearchDir = (PRTUTF16)&pImport->szName[cbNameAligned];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync memcpy(pImport->pwszAltSearchDir, pawcDir, cwcDir * sizeof(RTUTF16));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Insert it. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoImports, pImport, pImport->pNext));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("RTLDRPROP_IMPORT_MODULE failed with rc=%Rrc i=%#x on '%ls'\n", rc, i, pwszName));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("RTLDRPROP_IMPORT_COUNT failed with rc=%Rrc on '%ls'\n", rc, pwszName));
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync * Processes the list of import todos.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsyncstatic void supR3HardenedWinVerifyCacheProcessImportTodos(void)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Work until we've got nothing more todo.
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync PVERIFIERCACHEIMPORT pTodo = ASMAtomicXchgPtrT(&g_pVerifierCacheTodoImports, NULL, PVERIFIERCACHEIMPORT);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Not in the cached already?
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if ( !supR3HardenedWinVerifyCacheLookupImport(g_System32NtPath.UniStr.Buffer,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync && !supR3HardenedWinVerifyCacheLookupImport(g_SupLibHardenedExeNtPath.UniStr.Buffer,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync || !supR3HardenedWinVerifyCacheLookupImport(pCur->pwszAltSearchDir, pCur->cwcAltSearchDir, pCur->szName)) )
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Try locate the imported DLL and open it.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Processing '%s'...\n", pCur->szName));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync RTUTF16 wszPath[260 + 260]; /* Assumes we've limited the import name length to 256. */
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync AssertCompile(sizeof(wszPath) > sizeof(g_System32NtPath));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Check for DLL isolation / redirection / mapping.
0dd3967035b8a02985920baa57f948dc542b9388vboxsync int rc = RTStrToUtf16Ex(pCur->szName, RTSTR_MAX, &pwszName, cwcName, &cwcName);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync UniStrName.Length = (USHORT)cwcName * sizeof(WCHAR);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync UniStrName.MaximumLength = UniStrName.Length + sizeof(WCHAR);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync UniStrStatic.MaximumLength = (USHORT)(sizeof(wszPath) - cwcName * sizeof(WCHAR) - sizeof(WCHAR));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync static UNICODE_STRING const s_DefaultSuffix = RTNT_CONSTANT_UNISTR(L".dll");
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync rcNtRedir = RtlDosApplyFileIsolationRedirection_Ustr(1 /*fFlags*/,
0dd3967035b8a02985920baa57f948dc542b9388vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
0dd3967035b8a02985920baa57f948dc542b9388vboxsync InitializeObjectAttributes(&ObjAttr, pUniStrResult,
0dd3967035b8a02985920baa57f948dc542b9388vboxsync OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
0dd3967035b8a02985920baa57f948dc542b9388vboxsync FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync 0 /*EaLength*/);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /* For accurate logging. */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync size_t cwcCopy = RT_MIN(pUniStrResult->Length / sizeof(RTUTF16), RT_ELEMENTS(wszPath) - 1);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync memcpy(wszPath, pUniStrResult->Buffer, cwcCopy * sizeof(RTUTF16));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: RTStrToUtf16Ex #1 failed: %Rrc\n", rc));
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync * If not something that gets remapped, do the half normal searching we need.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync { g_System32NtPath.UniStr.Buffer, g_System32NtPath.UniStr.Length / sizeof(WCHAR) },
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync { g_SupLibHardenedExeNtPath.UniStr.Buffer, g_offSupLibHardenedExeNtName - 1 },
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync /* Search System32 first, unless it's a 'V*' or 'm*' name, the latter for msvcrt. */
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync if (aDirs[i].pawcDir && aDirs[i].cwcDir && aDirs[i].cwcDir < RT_ELEMENTS(wszPath) / 3 * 2)
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync memcpy(wszPath, aDirs[i].pawcDir, aDirs[i].cwcDir * sizeof(RTUTF16));
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync rc = RTStrToUtf16Ex(pCur->szName, RTSTR_MAX, &pwszName, cwcName, &cwcName);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync NtName.Length = (USHORT)((cwc + cwcName) * sizeof(WCHAR));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync NtName.MaximumLength = NtName.Length + sizeof(WCHAR);
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync 0 /*EaLength*/);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: RTStrToUtf16Ex #2 failed: %Rrc\n", rc));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * If we successfully opened it, verify it and cache the result.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' -> '%ls' [rcNtRedir=%#x]\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync bool fCallRealApi = false;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, false /*fIgnoreArch*/, &fAccess, &fProtect,
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync &fCallRealApi, "Imports", false /*fAvoidWinVerifyTrust*/, NULL /*pfQuiet*/);
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: Failed to locate '%s'\n", pCur->szName));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessImportTodos: '%s' is in the cache.\n", pCur->szName));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Processes the list of WinVerifyTrust todos.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsyncstatic void supR3HardenedWinVerifyCacheProcessWvtTodos(void)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync PVERIFIERCACHEENTRY volatile *ppReschedLastNext = NULL;
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Work until we've got nothing more todo.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync PVERIFIERCACHEENTRY pTodo = ASMAtomicXchgPtrT(&g_pVerifierCacheTodoWvt, NULL, PVERIFIERCACHEENTRY);
ffb50166c9adb4ae583b914d405197035cf890advboxsync int rc = supHardenedWinVerifyImageTrust(pCur->hFile, pCur->wszPath, pCur->fFlags, pCur->rc,
ffb50166c9adb4ae583b914d405197035cf890advboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessWvtTodos: %d (was %d) fWinVerifyTrust=%d for '%ls'\n",
3c6306a66deef467e3c13483dd6529e1e1c6b822vboxsync /* Retry it at a later time. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync SUP_DPRINTF(("supR3HardenedWinVerifyCacheProcessWvtTodos: %d (was %d) fWinVerifyTrust=%d for '%ls' [rescheduled]\n",
f75c6db919d277952ca03b7acf643e5e3ac96cafvboxsync /* else: already processed. */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Anything to reschedule.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync while (!ASMAtomicCmpXchgPtr(&g_pVerifierCacheTodoWvt, pReschedule, *ppReschedLastNext));
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Checks whether the path could be containing alternative 8.3 names generated
0dd3967035b8a02985920baa57f948dc542b9388vboxsync * by NTFS, FAT, or other similar file systems.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * @returns Pointer to the first component that might be an 8.3 name, NULL if
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * not 8.3 path.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * @param pwszPath The path to check.
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsyncstatic PRTUTF16 supR3HardenedWinIsPossible8dot3Path(PCRTUTF16 pwszPath)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync /* Could check more here before jumping to conclusions... */
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync else if (wc == 0)
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * Fixes up a path possibly containing one or more alternative 8-dot-3 style
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync * components.
ffb50166c9adb4ae583b914d405197035cf890advboxsync * The path is fixed up in place. Errors are ignored.
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync * @param hFile The handle to the file which path we're fixing up.
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync * @param pUniStr The path to fix up. MaximumLength is the max buffer
ffb50166c9adb4ae583b914d405197035cf890advboxsyncstatic void supR3HardenedWinFix8dot3Path(HANDLE hFile, PUNICODE_STRING pUniStr)
ffb50166c9adb4ae583b914d405197035cf890advboxsync * We could use FileNormalizedNameInformation here and slap the volume device
ffb50166c9adb4ae583b914d405197035cf890advboxsync * path in front of the result, but it's only supported since windows 8.0
ffb50166c9adb4ae583b914d405197035cf890advboxsync * according to some docs... So we expand all supicious names.
ffb50166c9adb4ae583b914d405197035cf890advboxsync pwszFix = supR3HardenedWinIsPossible8dot3Path(pwszFix);
ffb50166c9adb4ae583b914d405197035cf890advboxsync while ((wc = *pwszFixEnd) != '\0' && wc != '\\' && wc != '/')
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync NtDir.Length = NtDir.MaximumLength = (USHORT)((pwszFix - pUniStr->Buffer) * sizeof(WCHAR));
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
ffb50166c9adb4ae583b914d405197035cf890advboxsync InitializeObjectAttributes(&ObjAttr, &NtDir, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
c89333d3e41e439ed9e74768000edc399d3e72e6vboxsync 0 /*EaLength*/);
b4d7b4dbcc45b8bde7502aa129440d92d7ffd038vboxsync uint8_t abBuffer[sizeof(FILE_BOTH_DIR_INFORMATION) + 2048 * sizeof(WCHAR)];
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
ffb50166c9adb4ae583b914d405197035cf890advboxsync NtFilterStr.Length = (USHORT)((uintptr_t)pwszFixEnd - (uintptr_t)pwszFix);
ffb50166c9adb4ae583b914d405197035cf890advboxsync if (NT_SUCCESS(rcNt) && uBuf.Info.NextEntryOffset == 0) /* There shall only be one entry matching... */
ffb50166c9adb4ae583b914d405197035cf890advboxsync uint32_t offName = uBuf.Info.FileNameLength / sizeof(WCHAR);
ffb50166c9adb4ae583b914d405197035cf890advboxsync while (offName > 0 && uBuf.Info.FileName[offName - 1] != '\\' && uBuf.Info.FileName[offName - 1] != '/')
ffb50166c9adb4ae583b914d405197035cf890advboxsync uint32_t cwcNameNew = (uBuf.Info.FileNameLength / sizeof(WCHAR)) - offName;
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync memcpy(pwszFix, &uBuf.Info.FileName[offName], cwcNameNew * sizeof(WCHAR));
ffb50166c9adb4ae583b914d405197035cf890advboxsync else if ( pUniStr->Length + cwcNameNew * sizeof(WCHAR) - cwcNameOld * sizeof(WCHAR) + sizeof(WCHAR)
ffb50166c9adb4ae583b914d405197035cf890advboxsync size_t cwcLeft = pUniStr->Length - (pwszFixEnd - pUniStr->Buffer) * sizeof(WCHAR) + sizeof(WCHAR);
ffb50166c9adb4ae583b914d405197035cf890advboxsync memmove(&pwszFix[cwcNameNew], pwszFixEnd, cwcLeft * sizeof(WCHAR));
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync pUniStr->Length -= (USHORT)(cwcNameOld * sizeof(WCHAR));
ffb50166c9adb4ae583b914d405197035cf890advboxsync pUniStr->Length += (USHORT)(cwcNameNew * sizeof(WCHAR));
ffb50166c9adb4ae583b914d405197035cf890advboxsync memcpy(pwszFix, &uBuf.Info.FileName[offName], cwcNameNew * sizeof(WCHAR));
ffb50166c9adb4ae583b914d405197035cf890advboxsync /* else: ignore overflow. */
750df3fe104e01cadbc3d5bd20243055d283d4e5vboxsync /* else: ignore failure. */
ffb50166c9adb4ae583b914d405197035cf890advboxsync /* Advance */
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * Screens an image file or file mapped with execute access.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @returns NT status code.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param hFile The file handle.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param fImage Set if image file mapping being made
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * (NtCreateSection thing).
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param fIgnoreArch Using the DONT_RESOLVE_DLL_REFERENCES flag,
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * which also implies that DLL init / term code
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * isn't called, so the architecture should be
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param pfAccess Pointer to the NtCreateSection access flags,
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * so we can modify them if necessary.
ffb50166c9adb4ae583b914d405197035cf890advboxsync * @param pfProtect Pointer to the NtCreateSection protection
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * flags, so we can modify them if necessary.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param pfCallRealApi Whether it's ok to go on to the real API.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param pszCaller Who is calling (for debugging / logging).
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * @param fAvoidWinVerifyTrust Whether we should avoid WinVerifyTrust.
ffb50166c9adb4ae583b914d405197035cf890advboxsync * @param pfQuiet Where to return whether to be quiet about
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * this image in the log (i.e. we've seen it
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * lots of times already). Optional.
6475559a7e0e52892efbab4fbdedc879f6866109vboxsyncstatic NTSTATUS supR3HardenedScreenImage(HANDLE hFile, bool fImage, bool fIgnoreArch, PULONG pfAccess, PULONG pfProtect,
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync bool *pfCallRealApi, const char *pszCaller, bool fAvoidWinVerifyTrust, bool *pfQuiet)
6475559a7e0e52892efbab4fbdedc879f6866109vboxsync * Query the name of the file, making sure to zero terminator the
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * string. (2nd half of buffer is used for error info, see below.)
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync uint8_t abBuffer[sizeof(UNICODE_STRING) + 2048 * sizeof(WCHAR)];
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync NTSTATUS rcNt = NtQueryObject(hFile, ObjectNameInformation, &uBuf, sizeof(uBuf) - sizeof(WCHAR) - 128, &cbNameBuf);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync "supR3HardenedScreenImage/%s: NtQueryObject -> %#x (fImage=%d fProtect=%#x fAccess=%#x)\n",
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync if (supR3HardenedWinIsPossible8dot3Path(uBuf.UniStr.Buffer))
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync * Check the cache.
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync PVERIFIERCACHEENTRY pCacheHit = supR3HardenedWinVerifyCacheLookup(&uBuf.UniStr, hFile);
553a2f0d8ef91a6dad8de4eef206ff093af53a5dvboxsync /* Do hit accounting and figure whether we need to be quiet or not. */
if (pfQuiet)
if (!fAvoidWinVerifyTrust)
bool fWinVerifyTrust = false;
int rc = supHardenedWinVerifyImageTrust(pCacheHit->hFile, pCacheHit->wszPath, pCacheHit->fFlags, pCacheHit->rc,
pszCaller, pCacheHit->rc, pCacheHit->wszPath, pCacheHit->fWinVerifyTrust ? "" : " [lacks WinVerifyTrust]"));
*pfCallRealApi = true;
return STATUS_SUCCESS;
if (!fQuiet)
return STATUS_TRUST_FAILURE;
&hMyFile,
InitializeObjectAttributes(&ObjAttr, &uBuf.UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
return rcNt;
if ( fMyValid
return STATUS_TRUST_FAILURE;
#ifdef DEBUG
if ( !fImage
PRTUTF16 pwszName = &uBuf.UniStr.Buffer[(g_System32NtPath.UniStr.Length - sizeof(L"System32") + sizeof(WCHAR)) / sizeof(WCHAR)];
SUP_DPRINTF(("supR3HardenedScreenImage/%s: Applying the drop-exec-kludge for '%ls'\n", pszCaller, uBuf.UniStr.Buffer));
*pfCallRealApi = true;
return STATUS_SUCCESS;
#ifndef VBOX_PERMIT_EVEN_MORE
if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_System32NtPath.UniStr, true /*fCheckSlash*/))
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_WinSxSNtPath.UniStr, true /*fCheckSlash*/))
# ifdef VBOX_PERMIT_MORE
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesNtPath.UniStr, true /*fCheckSlash*/))
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesNtPath.UniStr, true /*fCheckSlash*/))
# ifdef RT_ARCH_AMD64
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_ProgramFilesX86NtPath.UniStr, true /*fCheckSlash*/))
else if (supHardViUniStrPathStartsWithUniStr(&uBuf.UniStr, &g_CommonFilesX86NtPath.UniStr, true /*fCheckSlash*/))
&& memcmp(uBuf.UniStr.Buffer + (uBuf.UniStr.Length - sizeof(L"\\SamplingRuntime.dll") + sizeof(WCHAR)) / sizeof(WCHAR),
*pfCallRealApi = true;
return STATUS_SUCCESS;
"supR3HardenedScreenImage/%s: Not a trusted location: '%ls' (fImage=%d fProtect=%#x fAccess=%#x)\n",
return STATUS_TRUST_FAILURE;
if (fIgnoreArch)
int rc;
bool fWinVerifyTrust = false;
rc = supHardenedWinVerifyImageByHandle(hMyFile, uBuf.UniStr.Buffer, fFlags, fAvoidWinVerifyTrust, &fWinVerifyTrust, &ErrInfo);
return STATUS_TRUST_FAILURE;
*pfCallRealApi = true;
return STATUS_SUCCESS;
InitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
bool fCallRealApi;
supR3HardenedScreenImage(hFile, false, false /*fIgnoreArch*/, &fAccess, &fProtect, &fCallRealApi, "preload",
supR3HardenedMonitor_NtCreateSection(PHANDLE phSection, ACCESS_MASK fAccess, POBJECT_ATTRIBUTES pObjAttribs,
bool const fExecProt = RT_BOOL(fProtect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_WRITECOPY
bool fCallRealApi;
NTSTATUS rcNt = supR3HardenedScreenImage(hFile, fImage, true /*fIgnoreArch*/, &fAccess, &fProtect, &fCallRealApi,
//SUP_DPRINTF(("supR3HardenedMonitor_NtCreateSection: 2 rcNt=%#x fCallRealApi=%#x\n", rcNt, fCallRealApi));
return rcNt;
if (!fCallRealApi)
return STATUS_TRUST_FAILURE;
return g_pfnNtCreateSectionReal(phSection, fAccess, pObjAttribs, pcbSection, fProtect, fAttribs, hFile);
static NTSTATUS supR3HardenedCopyRedirectionResult(WCHAR *pwszPath, size_t cwcPath, PUNICODE_STRING pUniStrResult,
"supR3HardenedMonitor_LdrLoadDll: Name too long: %.*ls -> %.*ls (RtlDosApplyFileIoslationRedirection_Ustr)\n",
return STATUS_NAME_TOO_LONG;
return STATUS_SUCCESS;
supR3HardenedMonitor_LdrLoadDll(PWSTR pwszSearchPath, PULONG pfFlags, PUNICODE_STRING pName, PHANDLE phMod)
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: name is NULL or have a zero length.\n");
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x (pName=%p)\n", STATUS_INVALID_PARAMETER, pName));
return STATUS_INVALID_PARAMETER;
(unsigned)pName->Length / sizeof(WCHAR), pName->Buffer, pfFlags ? *pfFlags : UINT32_MAX, pwszSearchPath,
!((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));*/
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: too long name: %#x bytes\n", pName->Length);
return STATUS_NAME_TOO_LONG;
bool fSkipValidation = false;
bool fCheckIfLoaded = false;
rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
return rcNt;
fSkipValidation = true;
switch (pawcName[i])
offLastSlash = i;
offLastDot = i;
cwcName--;
return STATUS_OBJECT_NAME_INVALID;
rcNt = supR3HardenedCopyRedirectionResult(wszPath, RT_ELEMENTS(wszPath), pUniStrResult, pName, &cwc);
return rcNt;
return STATUS_NAME_TOO_LONG;
if (!fNeedDllSuffix)
fCheckIfLoaded = true;
bool fQuiet = false;
if (!fSkipValidation)
return STATUS_OBJECT_NAME_INVALID;
InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
bool fCallRealApi = false;
rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, RT_VALID_PTR(pfFlags) && (*pfFlags & 0x2) /*fIgnoreArch*/,
if (!fQuiet)
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: rejecting '%ls': rcNt=%#x\n",
supR3HardenedError(VINF_SUCCESS, false, "supR3HardenedMonitor_LdrLoadDll: rejecting '%ls' (%.*ls): rcNt=%#x\n",
return rcNt;
if ( fCheckIfLoaded
return rcNtGetDll;
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: error opening '%ls': %u (NtPath=%.*ls; Input=%.*ls; rcNtGetDll=%#x\n",
if (!fQuiet)
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls (Input=%.*ls, rcNtResolve=%#x) *pfFlags=%#x pwszSearchPath=%p:%ls [calling]\n",
!((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: pName=%.*ls (rcNtResolve=%#x) *pfFlags=%#x pwszSearchPath=%p:%ls [calling]\n",
!((uintptr_t)pwszSearchPath & 1) && (uintptr_t)pwszSearchPath >= 0x2000U ? pwszSearchPath : L"<flags>"));
SUP_DPRINTF(("supR3HardenedMonitor_LdrLoadDll: returns rcNt=%#x hMod=%p '%ls'\n", rcNt, *phMod, wszPath));
return rcNt;
static VOID CALLBACK supR3HardenedDllNotificationCallback(ULONG ulReason, PCLDR_DLL_NOTIFICATION_DATA pData, PVOID pvUser)
supR3HardenedFatal("supR3HardenedDllNotificationCallback: RTNtPathFromWinUtf16Ex failed on '%.*ls': %Rrc\n",
InitializeObjectAttributes(&ObjAttr, &NtPathUniStr, OBJ_CASE_INSENSITIVE, hRootDir, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
supR3HardenedFatal("supR3HardenedDllNotificationCallback: NtCreateFile failed on '%.*ls' / '%.*ls': %#x\n",
bool fCallRealApi = false;
bool fQuietFailure = false;
rcNt = supR3HardenedScreenImage(hFile, true /*fImage*/, true /*fIgnoreArch*/, &fAccess, &fProtect, &fCallRealApi,
supR3HardenedFatal("supR3HardenedDllNotificationCallback: supR3HardenedScreenImage failed on '%.*ls' / '%.*ls': %#x\n",
static void supR3HardenedWinRegisterDllNotificationCallback(void)
&& g_cDllNotificationRegistered <= 0
NTSTATUS rcNt = LdrRegisterDllNotification(0, supR3HardenedDllNotificationCallback, NULL, &g_pvDllNotificationCookie);
#ifdef RT_ARCH_X86
NTSTATUS rcNt2 = NtQueryInformationProcess(hProcWait, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
SUP_DPRINTF(("supR3HardenedWinParentWatcherThread: Quitting: ExitCode=%#x rcNt=%#x\n", BasicInfo.ExitStatus, rcNt));
NTSTATUS rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
supR3HardenedFatal("supR3HardenedWinCreateParentWatcherThread: NtQueryInformationProcess failed: %#x\n", rcNt);
supR3HardenedFatalMsg("supR3HardenedWinCreateParentWatcherThread", kSupInitOp_Misc, VERR_GENERAL_FAILURE,
static bool supR3HardenedWinAmIAlone(void)
NTSTATUS rcNt = NtQueryInformationThread(NtCurrentThread(), ThreadAmILastThread, &fAmIAlone, sizeof(fAmIAlone), &cbIgn);
const char *pszName;
} const s_aPatches[] =
{ sizeof(g_abNtCreateSectionPatch), g_abNtCreateSectionPatch, &g_pbNtCreateSection, "NtCreateSection" },
s_cTimes++;
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READWRITE));
if (fAmIAlone)
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pbApi, s_aPatches[i].cbPatch, PAGE_EXECUTE_READ));
static void supR3HardenedWinInstallHooks(void)
rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr), NULL);
rcNt = NtSetInformationProcess(NtCurrentProcess(), ProcessDefaultHardErrorMode, &fHardErr, sizeof(fHardErr));
#ifdef RT_ARCH_AMD64
#ifdef RT_ARCH_AMD64
*(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = RT_ALIGN_32(offExecPage + 4, 8) - (offExecPage + 4);
*(uint32_t *)&g_abLdrLoadDllPatch[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(g_abSupHardReadWriteExecPage, PAGE_SIZE, PAGE_EXECUTE_READ));
static int supR3HardNtDisableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, void *pvNtTerminateThread,
SUP_DPRINTF(("supR3HardNtDisableThreadCreation: pvLdrInitThunk=%p pvNtTerminateThread=%p\n", pvLdrInitThunk, pvNtTerminateThread));
#ifdef RT_ARCH_AMD64
*(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
*(int32_t *)&abReplacement[5] = (int32_t)((uintptr_t)pvNtTerminateThread - ((uintptr_t)pvLdrInitThunk + 9));
rcNt = NtWriteVirtualMemory(hProcess, pvLdrInitThunk, abReplacement, sizeof(abReplacement), &cbIgnored);
"supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk/2 failed: %#x", rcNt);
return VINF_SUCCESS;
static int supR3HardNtEnableThreadCreationEx(HANDLE hProcess, void *pvLdrInitThunk, uint8_t const *pabBackup, size_t cbBackup,
NTSTATUS rcNt = NtProtectVirtualMemory(hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
"supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
rcNt);
"supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
rcNt);
return VINF_SUCCESS;
static void supR3HardenedWinDisableThreadCreation(void)
g_fSupInitThunkSelfPatched = false;
static bool supR3HardNtChildGetUserAndLogSids(PSID pSidUser, ULONG cbSidUser, PSID pSidLogin, ULONG cbSidLogin)
} uBuf;
SUPR3HARDENED_ASSERT_NT_SUCCESS(NtQueryInformationToken(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbRet));
bool fLoginSid = false;
fLoginSid = true;
return fLoginSid;
static void supR3HardNtChildInitSecAttrs(PSECURITY_ATTRIBUTES pSecAttrs, PMYSECURITYCLEANUP pCleanup, bool fProcess)
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateAcl(&pCleanup->Acl.AclHdr, sizeof(pCleanup->Acl), ACL_REVISION));
if (fProcess)
fDeny |= THREAD_SUSPEND_RESUME | THREAD_SET_CONTEXT | THREAD_SET_INFORMATION | THREAD_SET_THREAD_TOKEN
if (fHasLoginSid)
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION));
SUPR3HARDENED_ASSERT_NT_SUCCESS(RtlSetDaclSecurityDescriptor(pSecDesc, TRUE /*fDaclPresent*/, &pCleanup->Acl.AclHdr,
int fQuoted = false;
unsigned cSlashes = 0;
cSlashes++;
cwcArgs--;
pawcArgs++;
size_t cwcCmdLine = (sizeof(SUPR3_RESPAWN_1_ARG0) - 1) / sizeof(SUPR3_RESPAWN_1_ARG0[0]) /* Respawn exe name. */
for (const char *pszSrc = iWhich == 1 ? SUPR3_RESPAWN_1_ARG0 : SUPR3_RESPAWN_2_ARG0; *pszSrc; pszSrc++)
if (cwcArgs)
if (pString)
return pwszCmdLine;
static void supR3HardenedWinKillChild(HANDLE hProcess, const char *pszWhere, int rc, const char *pszFormat, ...)
NTSTATUS rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
if (!fExitOk)
rcNtExit = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
} while ( !fExitOk
if (fExitOk)
static void supR3HardNtChildProcessRequest(PSUPR3HARDNTCHILD pThis, SUPR3WINCHILDREQ enmExpectedRequest, const char *pszWhat)
supR3HardenedWinKillChild(pThis, "supR3HardNtChildProcessRequest", rcNt, "NtSetEvent failed: %#x\n", rcNt);
SUP_DPRINTF(("supR3HardNtChildProcessRequest: Child is taking too long to quit (rcWait=%#x), killing it...\n", rcNt));
static void supR3HardNtChildWaitFor(PSUPR3HARDNTCHILD pThis, SUPR3WINCHILDREQ enmExpectedRequest, RTMSINTERVAL cMsTimeout,
const char *pszWhat)
rcNtWait = NtWaitForMultipleObjects(cHandles, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, NULL /*Timeout*/);
rcNtWait = NtWaitForMultipleObjects(cHandles, &ahHandles[0], WaitAnyObject, TRUE /*Alertable*/, &Timeout);
NTSTATUS rcNt1 = NtQueryInformationProcess(pThis->hProcess, ProcessBasicInformation, &BasicInfo, sizeof(BasicInfo), NULL);
SUP_DPRINTF(("supR3HardNtChildWaitFor[%d]: Quitting: ExitCode=%#x (rcNtWait=%#x, rcNt1=%#x, rcNt2=%#x, rcNt3=%#x, %llu ms, %s);\n",
supR3HardenedWinKillChild(pThis, "supR3HardenedWinReSpawn", rcNt, "NtClose(hThread) failed: %#x", rcNt);
* There should not be any activation context, so if there is, we scratch the memory associated with it.
int rc = 0;
if (RT_SUCCESS(rc) && Peb.ActivationContextData && !((uintptr_t)Peb.ActivationContextData & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ActivationContextData, PAGE_SIZE, "ActivationContextData", pErrInfo);
if (RT_SUCCESS(rc) && Peb.ProcessAssemblyStorageMap && !((uintptr_t)Peb.ProcessAssemblyStorageMap & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "ProcessAssemblyStorageMap", pErrInfo);
if (RT_SUCCESS(rc) && Peb.SystemDefaultActivationContextData && !((uintptr_t)Peb.SystemDefaultActivationContextData & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.ProcessAssemblyStorageMap, PAGE_SIZE, "SystemDefaultActivationContextData", pErrInfo);
if (RT_SUCCESS(rc) && Peb.SystemAssemblyStorageMap && !((uintptr_t)Peb.SystemAssemblyStorageMap & PAGE_OFFSET_MASK))
rc = supR3HardenedWinScratchChildMemory(hProcess, Peb.SystemAssemblyStorageMap, PAGE_SIZE, "SystemAssemblyStorageMap", pErrInfo);
return rc;
/*Peb.Diff0.W6.IsProtectedProcess = 1;*/
NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
cSleeps++;
cFixes = 0;
int rc = supHardenedWinVerifyProcess(pThis->hProcess, pThis->hThread, SUPHARDNTVPKIND_CHILD_PURIFICATION,
if (cFixes == 0)
if (!g_fSupAdversaries)
SUP_DPRINTF(("supR3HardNtChildPurify: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
"Unable to purify child process! After 16 tries over %llu ms, we still %u fix(es) in the last pass.",
uintptr_t uChildAddr = uChildExeAddr + ((uintptr_t)&g_ProcParams - (uintptr_t)NtCurrentPeb()->ImageBaseAddress);
rc = supHardNtLdrCacheEntryGetBits(pLdrEntry, &pbChildNtDllBits, pThis->uNtDllAddr, NULL, NULL, NULL /*pErrInfo*/);
#ifdef RT_ARCH_AMD64
rcNt = NtProtectVirtualMemory(pThis->hProcess, &pvProt, &cbProt, PAGE_EXECUTE_READWRITE, &fOldProt);
#ifdef RT_ARCH_AMD64
NTSTATUS rcNt = NtWriteVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &Peb, pThis->cbPeb, &cbActualMem);
if (RTUtf16ICmpAscii(&pUniStr->Buffer[g_System32NtPath.UniStr.Length / sizeof(WCHAR) + 1], pszName) == 0)
SUPR3HARDENED_ASSERT(pThis->uNtDllParentAddr != 0 && !(pThis->uNtDllParentAddr & PAGE_OFFSET_MASK));
(void const *)uPtrWhere,
&MemInfo,
sizeof(MemInfo),
&cbActual);
} uBuf;
&uBuf,
&cbActual);
supR3HardenedWinKillChild(pThis, "supR3HardNtChildFindNtdll", VERR_MODULE_NOT_FOUND, "ntdll.dll not found in child process.");
rcNt = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &SelfInfo, sizeof(SelfInfo), &cbActual);
rcNt = NtOpenProcess(&pThis->hParent, SYNCHRONIZE | PROCESS_QUERY_INFORMATION, &ObjAttr, &ClientId);
#ifdef DEBUG
SUP_DPRINTF(("supR3HardNtChildGatherData: Failed to open parent process (%#p): %#x\n", ClientId.UniqueProcess, rcNt));
rcNt = NtReadVirtualMemory(pThis->hProcess, pThis->BasicInfo.PebBaseAddress, &pThis->Peb, sizeof(pThis->Peb), &cbActualMem);
InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&This.hEvtChild, EVENT_ALL_ACCESS, &ObjAttrs, SynchronizationEvent, FALSE));
InitializeObjectAttributes(&ObjAttrs, NULL /*pName*/, OBJ_INHERIT, NULL /*hRootDir*/, NULL /*pSecDesc*/);
SUPR3HARDENED_ASSERT_NT_SUCCESS(NtCreateEvent(&This.hEvtParent, EVENT_ALL_ACCESS, &ObjAttrs, SynchronizationEvent, FALSE));
W32ImageName.Buffer = g_wszSupLibHardenedExePath; /* Yes the windows name for the process parameters. */
&CmdLine,
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
SUP_DPRINTF(("supR3HardenedWinReSpawn: NtSetInformationThread/ThreadHideFromDebugger failed: %#x (harmless)\n", rcNt));
supR3HardenedWinKillChild(&This, "supR3HardenedWinDoReSpawn", rcNt, "NtResumeThread failed: %#x", rcNt);
supR3HardNtChildWaitFor(&This, kSupR3WinChildReq_PurifyChildAndCloseHandles, 2000 /*ms*/, "PurifyChildAndCloseHandles");
InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&cbActual);
SUP_DPRINTF(("supR3HardenedWinLogObjDir: NtQueryDirectoryObject => rcNt=%#x cbActual=%#x\n", rcNt, cbActual));
pObjDir++;
DECLHIDDEN(char *) supR3HardenedWinReadErrorInfoDevice(char *pszErrorInfo, size_t cbErrorInfo, const char *pszPrefix)
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
return pszErrorInfo;
InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef VBOX_STRICT
bool fFound = true;
&cbActual);
fFound = true;
pObjDir++;
} while (!fFound);
return fFound;
static void supR3HardenedWinOpenStubDevice(void)
if (g_fSupStubOpened)
InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
/** @todo Consider starting the VBoxdrv.sys service. Requires 2nd process
g_fSupStubOpened = true;
if (uSessionId == 0)
const char *pszDefine;
switch (rcNt)
/** @todo don't fail during early init, wait till later and try load the driver if missing or at least query the service manager for additional information. */
* support driver via /Devices/VBoxDrvStub. (We tried to do this
rc = supHardNtVpThread(NtCurrentProcess(), NtCurrentThread(), RTErrInfoInitStatic(&g_ErrInfoStatic));
supR3HardenedFatalMsg("supR3HardenedWinReSpawn", kSupInitOp_Integrity, rc, "%s", g_ErrInfoStatic.szMsg);
return RTEXITCODE_FAILURE;
#ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
InitializeObjectAttributes(&ObjAttrs, &UniStr, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error opening '%ls': %#x", UniStr.Buffer, rcNt);
supR3HardenedFatalMsg("supR3HardenedWinInit", kSupInitOp_Misc, rcNt, "Error querying '%ls': %#x", UniStr.Buffer, rcNt);
if (fAvastKludge)
cSleeps++;
cFixes = 0;
rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_SELF_PURIFICATION,
if (!g_fSupAdversaries)
/* Log the KiOpPrefetchPatchCount value if available, hoping it might sched some light on spider38's case. */
SUP_DPRINTF(("supR3HardenedWinInit: cFixes=%u g_fSupAdversaries=%#x\n", cFixes, g_fSupAdversaries));
#ifndef VBOX_WITH_VISTA_NO_SP
"Window Vista without any service pack installed is not supported. Please install the latest service pack.");
int cArgs = 0;
if (!ch)
bool fQuoted = false;
unsigned cSlashes = 0;
cSlashes++;
if (cSlashes)
pszSrc--;
while (cSlashes-- > 0)
if (!ch)
return papszArgs;
InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
&ObjAttr,
&Ios,
rcNt = NtQueryInformationFile(hFile, &Ios, &u.BasicInfo, sizeof(u.BasicInfo), FileBasicInformation);
SUP_DPRINTF((" CreationTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.CreationTime.QuadPart), szTmp, sizeof(szTmp))));
/*SUP_DPRINTF((" LastAccessTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastAccessTime.QuadPart), szTmp, sizeof(szTmp))));*/
SUP_DPRINTF((" LastWriteTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.LastWriteTime.QuadPart), szTmp, sizeof(szTmp))));
SUP_DPRINTF((" ChangeTime: %s\n", RTTimeSpecToString(RTTimeSpecSetNtTime(&TimeSpec, u.BasicInfo.ChangeTime.QuadPart), szTmp, sizeof(szTmp))));
RT_ZERO(u);
SUP_DPRINTF((" SizeOfImage: %#x (%u)\n", pNtHdrs64->OptionalHeader.SizeOfImage, pNtHdrs64->OptionalHeader.SizeOfImage));
RT_ZERO(u);
while (cwcLeft-- > 0)
if (*pwc)
pwc++;
const char *pszDriver;
} s_aDrivers[] =
} s_aFiles[] =
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ccsetx64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\ironx64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtsp64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\srtspx64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symds64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symefa64.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symelam.sys" },
{ SUPHARDNT_ADVERSARY_SYMANTEC_N360, L"\\SystemRoot\\System32\\drivers\\N360x64\\1505000.013\\symnets.sys" },
{ SUPHARDNT_ADVERSARY_TRENDMICRO_SAKFILE, L"\\SystemRoot\\System32\\drivers\\sakfile.sys" }, /* Data Loss Prevention, not officescan. */
{ SUPHARDNT_ADVERSARY_TRENDMICRO, L"\\SystemRoot\\System32\\drivers\\sakcd.sys" }, /* Data Loss Prevention, not officescan. */
InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
#ifdef VBOX_STRICT
&cbActual);
pObjDir++;
InitializeObjectAttributes(&ObjAttr, &UniStrName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
return fFound;
int cArgs;
char **papszArgs = suplibCommandLineToArgvWStub(pCmdLineStr->Buffer, pCmdLineStr->Length / sizeof(WCHAR), &cArgs);
HANDLE hFile = CreateFileW(g_wszSupLibHardenedExePath, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecurityAttributes*/,
supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromWin32(RtlGetLastWin32Error()),
supR3HardenedFatalMsg("suplibHardenedWindowsMain", kSupInitOp_Integrity, RTErrConvertFromNtStatus(rcNt),
DECLHIDDEN(void) supR3HardenedWinReportErrorToParent(const char *pszWhere, SUPINITOP enmWhat, int rc,
if (pszWhere)
NtTerminateThread(0, 0);
NtTerminateThread(0, 0);
NtTerminateThread(0, 0);
g_fSupEarlyProcessInit = true;
int cArgs;
char **papszArgs = suplibCommandLineToArgvWStub(CmdLineStr.Buffer, CmdLineStr.Length / sizeof(WCHAR), &cArgs);
rcNt = NtQueryVirtualMemory(NtCurrentProcess(), &g_ProcParams, MemorySectionName, &g_SupLibHardenedExeNtPath,
supR3HardenedFatal("NtQueryVirtualMemory/MemorySectionName failed in supR3HardenedVmProcessInit: %#x\n", rcNt);
supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheOpen failed on NTDLL: %Rrc\n", rc);
supR3HardenedFatal("supR3HardenedVmProcessInit: supHardNtLdrCacheEntryGetBits failed on NTDLL: %Rrc\n", rc);
rc = RTLdrGetSymbolEx(pLdrEntry->hLdrMod, pbBits, uNtDllAddr, UINT32_MAX, "LdrInitializeThunk", &uValue);
SUPR3HARDENED_ASSERT_NT_SUCCESS(supR3HardenedWinProtectMemory(pvLdrInitThunk, 16, PAGE_EXECUTE_READWRITE));