VirtualBox

Ignore:
Timestamp:
Aug 9, 2019 1:11:21 PM (5 years ago)
Author:
vboxsync
Message:

SUPHardNt: Hack for fending off unwanted APCs during early process initialization, preventing them from tripping over when we're evicted code they need (executable memory allocations). We only allow the LdrInitializeThunk APC to go thru. bugdbref:29744598

Location:
trunk/src/VBox/HostDrivers/Support/win
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/win/SUPHardenedVerifyProcess-win.cpp

    r77816 r80212  
    873873     */
    874874    uint32_t         cSkipAreas = 0;
    875     SUPHNTVPSKIPAREA aSkipAreas[5];
     875    SUPHNTVPSKIPAREA aSkipAreas[6];
    876876    if (pImage->fNtCreateSectionPatch)
    877877    {
     
    898898        if (RT_FAILURE(rc))
    899899            return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'LdrInitializeThunk': %Rrc", pImage->pszName, rc);
     900        aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
     901        aSkipAreas[cSkipAreas++].cb = 14;
     902
     903        /* Ignore our patched KiUserApcDispatcher hack. */
     904        rc = RTLdrGetSymbolEx(pImage->pCacheEntry->hLdrMod, pbBits, 0, UINT32_MAX, "KiUserApcDispatcher", &uValue);
     905        if (RT_FAILURE(rc))
     906            return supHardNtVpSetInfo2(pThis, rc, "%s: Failed to find 'KiUserApcDispatcher': %Rrc", pImage->pszName, rc);
    900907        aSkipAreas[cSkipAreas].uRva = (uint32_t)uValue;
    901908        aSkipAreas[cSkipAreas++].cb = 14;
     
    15191526    /*
    15201527     * In the BSOD workaround mode, we need to make a copy of the memory before
    1521      * freeing it.
     1528     * freeing it.  Bird abuses this code for logging purposes too.
    15221529     */
    15231530    uintptr_t   uCopySrc  = (uintptr_t)pvFree;
    15241531    size_t      cbCopy    = 0;
    15251532    void       *pvCopy    = NULL;
    1526     if (pThis->fFlags & SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW)
     1533    //if (pThis->fFlags & SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW)
    15271534    {
    15281535        cbCopy = cbFree;
     
    15381545            supHardNtVpSetInfo2(pThis, VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED,
    15391546                                "Error reading data from original alloc: %#x (%p LB %#zx)", rcNt, uCopySrc, cbCopy, rcNt);
    1540         supR3HardenedLogFlush();
     1547        for (size_t off = 0; off < cbCopy; off += 256)
     1548        {
     1549            size_t const cbChunk = RT_MIN(256, cbCopy - off);
     1550            void const  *pvChunk = (uint8_t const *)pvCopy + off;
     1551            if (!ASMMemIsZero(pvChunk, cbChunk))
     1552                SUP_DPRINTF(("%.*RhxD\n", cbChunk, pvChunk));
     1553        }
     1554        if (pThis->fFlags & SUPHARDNTVP_F_EXEC_ALLOC_REPLACE_WITH_RW)
     1555            supR3HardenedLogFlush();
    15411556    }
    15421557
  • trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMain-win.cpp

    r79642 r80212  
    292292/** Pointer to the bit of assembly code that will perform the original
    293293 *  NtCreateSection operation. */
    294 static NTSTATUS (NTAPI *    g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
     294static NTSTATUS     (NTAPI *g_pfnNtCreateSectionReal)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
    295295                                                      PLARGE_INTEGER, ULONG, ULONG, HANDLE);
    296296/** Pointer to the NtCreateSection function in NtDll (for patching purposes). */
     
    300300/** Pointer to the bit of assembly code that will perform the original
    301301 *  LdrLoadDll operation. */
    302 static NTSTATUS (NTAPI *    g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE);
     302static NTSTATUS     (NTAPI *g_pfnLdrLoadDllReal)(PWSTR, PULONG, PUNICODE_STRING, PHANDLE);
    303303/** Pointer to the LdrLoadDll function in NtDll (for patching purposes). */
    304304static uint8_t             *g_pbLdrLoadDll;
    305305/** The patched LdrLoadDll bytes (for restoring). */
    306306static uint8_t              g_abLdrLoadDllPatch[16];
     307
     308/** Pointer to the bit of assembly code that will perform the original
     309 *  KiUserApcDispatcher operation. */
     310static VOID        (NTAPI *g_pfnKiUserApcDispatcherReal)(void);
     311/** Pointer to the KiUserApcDispatcher function in NtDll (for patching
     312 *  purposes). */
     313static uint8_t             *g_pbKiUserApcDispatcher;
     314/** The patched KiUserApcDispatcher bytes (for restoring). */
     315static uint8_t              g_abKiUserApcDispatcherPatch[16];
     316/** Pointer to the LdrInitializeThunk function in NtDll for
     317 *  supR3HardenedMonitor_KiUserApcDispatcher_C() to use for APC vetting. */
     318static uintptr_t            g_pfnLdrInitializeThunk;
    307319
    308320/** The hash table of verifier cache . */
     
    379391/** Sophos Endpoint Defense. */
    380392#define SUPHARDNT_ADVERSARY_SOPHOS                  RT_BIT_32(18)
     393/** VMware horizon view agent. */
     394#define SUPHARDNT_ADVERSARY_HORIZON_VIEW_AGENT      RT_BIT_32(19)
    381395/** Unknown adversary detected while waiting on child. */
    382396#define SUPHARDNT_ADVERSARY_UNKNOWN                 RT_BIT_32(31)
     
    393407static void     supR3HardenedWinReInstallHooks(bool fFirst);
    394408DECLASM(void)   supR3HardenedEarlyProcessInitThunk(void);
     409DECLASM(void)   supR3HardenedMonitor_KiUserApcDispatcher(void);
    395410
    396411
     
    24612476
    24622477
     2478/**
     2479 * Dummy replacement routine we use for passifying unwanted user APC
     2480 * callbacks during early process initialization.
     2481 *
     2482 * @sa supR3HardenedMonitor_KiUserApcDispatcher_C
     2483 */
     2484static VOID NTAPI supR3HardenedWinDummyApcRoutine(PVOID pvArg1, PVOID pvArg2, PVOID pvArg3)
     2485{
     2486    SUP_DPRINTF(("supR3HardenedWinDummyApcRoutine: pvArg1=%p pvArg2=%p pvArg3=%p\n", pvArg1, pvArg2, pvArg3));
     2487    RT_NOREF(pvArg1, pvArg2, pvArg3);
     2488}
     2489
     2490
     2491/**
     2492 * This is called when ntdll!KiUserApcDispatcher is invoked (via
     2493 * supR3HardenedMonitor_KiUserApcDispatcher).
     2494 *
     2495 * The parent process hooks KiUserApcDispatcher before the guest starts
     2496 * executing. There should only be one APC request dispatched while the process
     2497 * is being initialized, and that's the one calling ntdll!LdrInitializeThunk.
     2498 *
     2499 * @returns Where to go to run the original code.
     2500 * @param   pvApcArgs   The APC dispatcher arguments.
     2501 */
     2502DECLASM(uintptr_t) supR3HardenedMonitor_KiUserApcDispatcher_C(void *pvApcArgs)
     2503{
     2504#ifdef RT_ARCH_AMD64
     2505    PCONTEXT   pCtx        = (PCONTEXT)pvApcArgs;
     2506    uintptr_t *ppfnRoutine = (uintptr_t *)&pCtx->P4Home;
     2507#else
     2508    struct X86APCCTX
     2509    {
     2510        uintptr_t   pfnRoutine;
     2511        uintptr_t   pvCtx;
     2512        uintptr_t   pvUser1;
     2513        uintptr_t   pvUser2;
     2514        CONTEXT     Ctx;
     2515    } *pCtx = (struct X86APCCTX *)pvApcArgs;
     2516    uintptr_t *ppfnRoutine = &pCtx->pfnRoutine;
     2517#endif
     2518    uintptr_t  pfnRoutine = *ppfnRoutine;
     2519
     2520    if (g_enmSupR3HardenedMainState < SUPR3HARDENEDMAINSTATE_HARDENED_MAIN_CALLED)
     2521    {
     2522        if (pfnRoutine == g_pfnLdrInitializeThunk) /* Note! we could use this to detect thread creation too. */
     2523            SUP_DPRINTF(("supR3HardenedMonitor_KiUserApcDispatcher_C: pfnRoutine=%p enmState=%d - okay\n",
     2524                         pfnRoutine, g_enmSupR3HardenedMainState));
     2525        else
     2526        {
     2527            *ppfnRoutine = (uintptr_t)supR3HardenedWinDummyApcRoutine;
     2528            SUP_DPRINTF(("supR3HardenedMonitor_KiUserApcDispatcher_C: pfnRoutine=%p enmState=%d -> supR3HardenedWinDummyApcRoutine\n",
     2529                         pfnRoutine, g_enmSupR3HardenedMainState));
     2530        }
     2531    }
     2532    return (uintptr_t)g_pfnKiUserApcDispatcherReal;
     2533}
     2534
     2535
    24632536static void supR3HardenedWinHookFailed(const char *pszWhich, uint8_t const *pbPrologue)
    24642537{
     
    26222695    } const s_aPatches[] =
    26232696    {
    2624         { sizeof(g_abNtCreateSectionPatch), g_abNtCreateSectionPatch, &g_pbNtCreateSection, "NtCreateSection" },
    2625         { sizeof(g_abLdrLoadDllPatch),      g_abLdrLoadDllPatch,      &g_pbLdrLoadDll,      "LdrLoadDll"      },
     2697        { sizeof(g_abNtCreateSectionPatch),     g_abNtCreateSectionPatch,     &g_pbNtCreateSection,     "NtCreateSection"     },
     2698        { sizeof(g_abLdrLoadDllPatch),          g_abLdrLoadDllPatch,          &g_pbLdrLoadDll,          "LdrLoadDll"          },
     2699        { sizeof(g_abKiUserApcDispatcherPatch), g_abKiUserApcDispatcherPatch, &g_pbKiUserApcDispatcher, "KiUserApcDispatcher" },
    26262700    };
    26272701
     
    27322806    //SUPR3HARDENED_ASSERT(pfnLdrLoadDll == (FARPROC)LdrLoadDll);
    27332807
     2808    PFNRT pfnKiUserApcDispatcher = supR3HardenedWinGetRealDllSymbol("ntdll.dll", "KiUserApcDispatcher");
     2809    SUPR3HARDENED_ASSERT(pfnKiUserApcDispatcher != NULL);
     2810    g_pfnLdrInitializeThunk = (uintptr_t)supR3HardenedWinGetRealDllSymbol("ntdll.dll", "LdrInitializeThunk");
     2811    SUPR3HARDENED_ASSERT(g_pfnLdrInitializeThunk != NULL);
     2812
    27342813    /*
    27352814     * Exec page setup & management.
     
    28872966    g_abLdrLoadDllPatch[0] = 0xe9;
    28882967    *(uint32_t *)&g_abLdrLoadDllPatch[1] = (uintptr_t)supR3HardenedMonitor_LdrLoadDll - (uintptr_t)&pbLdrLoadDll[1+4];
     2968#endif
     2969
     2970    /*
     2971     * Hook #3 - KiUserApcDispatcher
     2972     * Purpose: Prevent user APC to memory we (or our parent) has freed from
     2973     *          crashing the process.  Also ensures no code injection via user
     2974     *          APC during process init given the way we're vetting the APCs.
     2975     *
     2976     * This differs from the first function in that is no a system call and
     2977     * we're at the mercy of the handwritten assembly.
     2978     */
     2979    uint8_t * const pbKiUserApcDispatcher = (uint8_t *)(uintptr_t)pfnKiUserApcDispatcher;
     2980    g_pbKiUserApcDispatcher = pbKiUserApcDispatcher;
     2981    memcpy(g_abKiUserApcDispatcherPatch, pbKiUserApcDispatcher, sizeof(g_abKiUserApcDispatcherPatch));
     2982
     2983#ifdef RT_ARCH_AMD64
     2984    /*
     2985     * Patch 64-bit hosts.
     2986     */
     2987    /* Just use the disassembler to skip 12 bytes or more. */
     2988    offJmpBack = 0;
     2989    while (offJmpBack < 12)
     2990    {
     2991        cbInstr = 1;
     2992        int rc = DISInstr(pbKiUserApcDispatcher + offJmpBack, DISCPUMODE_64BIT, &Dis, &cbInstr);
     2993        if (   RT_FAILURE(rc)
     2994            || (Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW))
     2995            || (Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */) )
     2996            supR3HardenedWinHookFailed("KiUserApcDispatcher", pbKiUserApcDispatcher);
     2997        offJmpBack += cbInstr;
     2998    }
     2999
     3000    /* Assemble the code for resuming the call.*/
     3001    *(PFNRT *)&g_pfnKiUserApcDispatcherReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage];
     3002
     3003    memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbKiUserApcDispatcher, offJmpBack);
     3004    offExecPage += offJmpBack;
     3005
     3006    g_abSupHardReadWriteExecPage[offExecPage++] = 0xff; /* jmp qword [$+8 wrt RIP] */
     3007    g_abSupHardReadWriteExecPage[offExecPage++] = 0x25;
     3008    *(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = RT_ALIGN_32(offExecPage + 4, 8) - (offExecPage + 4);
     3009    offExecPage = RT_ALIGN_32(offExecPage + 4, 8);
     3010    *(uint64_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbKiUserApcDispatcher[offJmpBack];
     3011    offExecPage = RT_ALIGN_32(offExecPage + 8, 16);
     3012
     3013    /* Assemble the KiUserApcDispatcher patch. */
     3014    Assert(offJmpBack >= 12);
     3015    g_abKiUserApcDispatcherPatch[0]  = 0x48; /* mov rax, qword */
     3016    g_abKiUserApcDispatcherPatch[1]  = 0xb8;
     3017    *(uint64_t *)&g_abKiUserApcDispatcherPatch[2] = (uint64_t)supR3HardenedMonitor_KiUserApcDispatcher;
     3018    g_abKiUserApcDispatcherPatch[10] = 0xff; /* jmp rax */
     3019    g_abKiUserApcDispatcherPatch[11] = 0xe0;
     3020
     3021#else
     3022    /*
     3023     * Patch 32-bit hosts.
     3024     */
     3025    /* Just use the disassembler to skip 5 bytes or more. */
     3026    offJmpBack = 0;
     3027    while (offJmpBack < 5)
     3028    {
     3029        cbInstr = 1;
     3030        int rc = DISInstr(pbKiUserApcDispatcher + offJmpBack, DISCPUMODE_32BIT, &Dis, &cbInstr);
     3031        if (   RT_FAILURE(rc)
     3032            || (Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW)) )
     3033            supR3HardenedWinHookFailed("KiUserApcDispatcher", pbKiUserApcDispatcher);
     3034        offJmpBack += cbInstr;
     3035    }
     3036
     3037    /* Assemble the code for resuming the call.*/
     3038    *(PFNRT *)&g_pfnKiUserApcDispatcherReal = (PFNRT)(uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage];
     3039
     3040    memcpy(&g_abSupHardReadWriteExecPage[offExecPage], pbKiUserApcDispatcher, offJmpBack);
     3041    offExecPage += offJmpBack;
     3042
     3043    g_abSupHardReadWriteExecPage[offExecPage++] = 0xe9; /* jmp rel32 */
     3044    *(uint32_t *)&g_abSupHardReadWriteExecPage[offExecPage] = (uintptr_t)&pbKiUserApcDispatcher[offJmpBack]
     3045                                                            - (uintptr_t)&g_abSupHardReadWriteExecPage[offExecPage + 4];
     3046    offExecPage = RT_ALIGN_32(offExecPage + 4, 16);
     3047
     3048    /* Assemble the KiUserApcDispatcher patch. */
     3049    memcpy(g_abKiUserApcDispatcherPatch, pbKiUserApcDispatcher, sizeof(g_abKiUserApcDispatcherPatch));
     3050    Assert(offJmpBack >= 5);
     3051    g_abKiUserApcDispatcherPatch[0] = 0xe9;
     3052    *(uint32_t *)&g_abKiUserApcDispatcherPatch[1] = (uintptr_t)supR3HardenedMonitor_KiUserApcDispatcher - (uintptr_t)&pbKiUserApcDispatcher[1+4];
    28893053#endif
    28903054
     
    30183182                                             PRTERRINFO pErrInfo)
    30193183{
    3020     SUP_DPRINTF(("supR3HardNtEnableThreadCreation:\n"));
     3184    SUP_DPRINTF(("supR3HardNtEnableThreadCreationEx:\n"));
    30213185    SUPR3HARDENED_ASSERT(cbBackup == 16);
    30223186
     
    30273191    if (!NT_SUCCESS(rcNt))
    30283192        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
    3029                              "supR3HardNtDisableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
     3193                             "supR3HardNtEnableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk failed: %#x", rcNt);
    30303194
    30313195    SIZE_T cbIgnored;
     
    30333197    if (!NT_SUCCESS(rcNt))
    30343198        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
    3035                              "supR3HardNtEnableThreadCreation: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
     3199                             "supR3HardNtEnableThreadCreationEx: NtWriteVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
    30363200                             rcNt);
    30373201
     
    30413205    if (!NT_SUCCESS(rcNt))
    30423206        return RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
    3043                              "supR3HardNtEnableThreadCreation: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
     3207                             "supR3HardNtEnableThreadCreationEx: NtProtectVirtualMemory/LdrInitializeThunk[restore] failed: %#x",
    30443208                             rcNt);
    30453209
     
    58145978
    58155979        { SUPHARDNT_ADVERSARY_SOPHOS,               "SophosED" }, /* Not verified. */
     5980
     5981        { SUPHARDNT_ADVERSARY_HORIZON_VIEW_AGENT,   "vmwicpdr" },
    58165982    };
    58175983
     
    59406106
    59416107        { SUPHARDNT_ADVERSARY_SOPHOS, L"\\SystemRoot\\System32\\drivers\\SophosED.sys" }, // not verified
     6108
     6109        { SUPHARDNT_ADVERSARY_HORIZON_VIEW_AGENT, L"\\SystemRoot\\System32\\drivers\\vmwicpdr.sys" },
     6110        { SUPHARDNT_ADVERSARY_HORIZON_VIEW_AGENT, L"\\SystemRoot\\System32\\drivers\\ftsjail.sys" },
    59426111    };
    59436112
     
    62086377        supR3HardenedWinRegisterDllNotificationCallback();
    62096378        supR3HardenedWinReInstallHooks(false /*fFirstCall */);
     6379
     6380        /*
     6381         * Flush user APCs before the g_enmSupR3HardenedMainState changes
     6382         * and disables the APC restrictions.
     6383         */
     6384        NtTestAlert();
    62106385    }
    62116386
     
    63276502    LARGE_INTEGER Timeout;
    63286503    Timeout.QuadPart = -1200000000; /* 120 second */
    6329     rcNt = pfnNtWaitForSingleObject(hEvtChild, FALSE /*Alertable*/, &Timeout);
     6504    rcNt = pfnNtWaitForSingleObject(hEvtChild, FALSE /*Alertable (never alertable before hooking!) */, &Timeout);
    63306505    if (rcNt != STATUS_SUCCESS)
    63316506        return 0x34; /* crash */
  • trunk/src/VBox/HostDrivers/Support/win/SUPR3HardenedMainA-win.asm

    r76553 r80212  
    3434; External code.
    3535extern NAME(supR3HardenedEarlyProcessInit)
     36extern NAME(supR3HardenedMonitor_KiUserApcDispatcher_C)
    3637
    3738
     
    107108ENDPROC   supR3HardenedEarlyProcessInitThunk
    108109
     110
     111;;
     112; Hook for KiUserApcDispatcher that validates user APC calls during early process
     113; init to prevent calls going to or referring to executable memory we've freed
     114; already.
     115;
     116; We just call C code here, just like supR3HardenedEarlyProcessInitThunk does.
     117;
     118; @sa supR3HardenedMonitor_KiUserApcDispatcher_C
     119;
     120BEGINPROC supR3HardenedMonitor_KiUserApcDispatcher
     121        ;
     122        ; Prologue.
     123        ;
     124
     125        ; Reserve space for the "return" address.
     126        push    0
     127
     128        ; Create a stack frame, saving xBP.
     129        push    xBP
     130        SEH64_PUSH_xBP
     131        mov     xBP, xSP
     132        SEH64_SET_FRAME_xBP 0 ; probably wrong...
     133
     134        ; Save all volatile registers.
     135        push    xAX
     136        push    xCX
     137        push    xDX
     138%ifdef RT_ARCH_AMD64
     139        push    r8
     140        push    r9
     141        push    r10
     142        push    r11
     143%endif
     144
     145        ; Reserve spill space and align the stack.
     146        sub     xSP, 20h
     147        and     xSP, ~0fh
     148        SEH64_END_PROLOGUE
     149
     150        ;
     151        ; Call the C/C++ code that does the actual work.  This returns the
     152        ; resume address in xAX, which we put in the "return" stack position.
     153        ;
     154        ; On AMD64, a CONTEXT structure is found at our RSP address when we're called.
     155        ; On x86, there a 16 byte structure containing the two routines and their
     156        ; arguments followed by a CONTEXT structure.
     157        ;
     158        lea     xCX, [xBP + xCB + xCB]
     159%ifdef RT_ARCH_X86
     160        mov     [xSP], xCX
     161%endif
     162        call    NAME(supR3HardenedMonitor_KiUserApcDispatcher_C)
     163        mov     [xBP + xCB], xAX
     164
     165        ;
     166        ; Restore volatile registers.
     167        ;
     168        mov     xAX, [xBP - xCB*1]
     169        mov     xCX, [xBP - xCB*2]
     170        mov     xDX, [xBP - xCB*3]
     171%ifdef RT_ARCH_AMD64
     172        mov     r8,  [xBP - xCB*4]
     173        mov     r9,  [xBP - xCB*5]
     174        mov     r10, [xBP - xCB*6]
     175        mov     r11, [xBP - xCB*7]
     176%endif
     177        ;
     178        ; Use the leave instruction to restore xBP and set up xSP to point at
     179        ; the resume address. Then use the 'ret' instruction to execute the
     180        ; original KiUserApcDispatcher code as if we've never been here...
     181        ;
     182        leave
     183        ret
     184ENDPROC   supR3HardenedMonitor_KiUserApcDispatcher
    109185
    110186
  • trunk/src/VBox/HostDrivers/Support/win/import-template-ntdll.h

    r67979 r80212  
    5151SUPHARNT_IMPORT_SYSCALL(NtTerminateProcess, 8)
    5252SUPHARNT_IMPORT_SYSCALL(NtTerminateThread, 8)
     53SUPHARNT_IMPORT_SYSCALL(NtTestAlert, 0)
    5354SUPHARNT_IMPORT_SYSCALL(NtUnmapViewOfSection, 8)
    5455SUPHARNT_IMPORT_SYSCALL(NtWaitForMultipleObjects, 20)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette