Пример #1
0
PPH_SYMBOL_PROVIDER PhCreateSymbolProvider(
    _In_opt_ HANDLE ProcessId
    )
{
    PPH_SYMBOL_PROVIDER symbolProvider;

    if (!NT_SUCCESS(PhCreateObject(
        &symbolProvider,
        sizeof(PH_SYMBOL_PROVIDER),
        0,
        PhSymbolProviderType
        )))
        return NULL;

    InitializeListHead(&symbolProvider->ModulesListHead);
    PhInitializeQueuedLock(&symbolProvider->ModulesListLock);
    PhInitializeAvlTree(&symbolProvider->ModulesSet, PhpSymbolModuleCompareFunction);
    PhInitializeCallback(&symbolProvider->EventCallback);

    if (ProcessId)
    {
        static ACCESS_MASK accesses[] =
        {
            STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access
            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE,
            PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
            MAXIMUM_ALLOWED
        };

        ULONG i;

        symbolProvider->IsRealHandle = FALSE;

        // Try to open the process with many different accesses.
        // This handle will be re-used when walking stacks, and doing
        // various other things.
        for (i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++)
        {
            if (NT_SUCCESS(PhOpenProcess(&symbolProvider->ProcessHandle, accesses[i], ProcessId)))
            {
                symbolProvider->IsRealHandle = TRUE;
                break;
            }
        }
    }
    else
    {
        symbolProvider->IsRealHandle = FALSE;
    }

    if (!symbolProvider->IsRealHandle)
    {
        HANDLE fakeHandle;

        // Just generate a fake handle.
        fakeHandle = (HANDLE)_InterlockedExchangeAddPointer((PLONG_PTR)&PhNextFakeHandle, 4);

        // Add one to make sure it isn't divisible
        // by 4 (so it can't be mistaken for a real
        // handle).
        fakeHandle = (HANDLE)((ULONG_PTR)fakeHandle + 1);

        symbolProvider->ProcessHandle = fakeHandle;
    }

    symbolProvider->IsRegistered = FALSE;

#ifdef PH_SYMBOL_PROVIDER_DELAY_INIT
    PhInitializeInitOnce(&symbolProvider->InitOnce);
#else
    PhpRegisterSymbolProvider(symbolProvider);
#endif

    return symbolProvider;
}
Пример #2
0
/**
 * Dequeues the appropriate number of wait blocks in
 * a queued lock.
 *
 * \param QueuedLock A queued lock.
 * \param Value The current value of the queued lock.
 * \param IgnoreOwned TRUE to ignore lock state, FALSE
 * to conduct normal checks.
 * \param WakeAll TRUE to remove all wait blocks, FALSE
 * to decide based on the wait block type.
 */
FORCEINLINE PPH_QUEUED_WAIT_BLOCK PhpPrepareToWakeQueuedLock(
    __inout PPH_QUEUED_LOCK QueuedLock,
    __in ULONG_PTR Value,
    __in BOOLEAN IgnoreOwned,
    __in BOOLEAN WakeAll
    )
{
    ULONG_PTR value;
    ULONG_PTR newValue;
    PPH_QUEUED_WAIT_BLOCK waitBlock;
    PPH_QUEUED_WAIT_BLOCK firstWaitBlock;
    PPH_QUEUED_WAIT_BLOCK lastWaitBlock;
    PPH_QUEUED_WAIT_BLOCK previousWaitBlock;

    value = Value;

    while (TRUE)
    {
        // If there are multiple shared owners, no one is going
        // to wake waiters since the lock would still be owned.
        // Also if there are multiple shared owners they may be
        // traversing the list. While that is safe when
        // done concurrently with list optimization, we may be
        // removing and waking waiters.
        assert(!(value & PH_QUEUED_LOCK_MULTIPLE_SHARED));
        assert(IgnoreOwned || (value & PH_QUEUED_LOCK_TRAVERSING));

        // There's no point in waking a waiter if the lock
        // is owned. Clear the traversing bit.
        while (!IgnoreOwned && (value & PH_QUEUED_LOCK_OWNED))
        {
            newValue = value - PH_QUEUED_LOCK_TRAVERSING;

            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(
                (PPVOID)&QueuedLock->Value,
                (PVOID)newValue,
                (PVOID)value
                )) == value)
                return NULL;

            value = newValue;
        }

        // Finish up any needed optimization (setting the
        // Previous pointers) while finding the last wait
        // block.

        waitBlock = PhGetQueuedLockWaitBlock(value);
        firstWaitBlock = waitBlock;

        while (TRUE)
        {
            lastWaitBlock = waitBlock->Last;

            if (lastWaitBlock)
            {
                waitBlock = lastWaitBlock;
                break;
            }

            previousWaitBlock = waitBlock;
            waitBlock = waitBlock->Next;
            waitBlock->Previous = previousWaitBlock;
        }

        // Unlink the relevant wait blocks and clear the
        // traversing bit before we wake waiters.

        if (
            !WakeAll &&
            (waitBlock->Flags & PH_QUEUED_WAITER_EXCLUSIVE) &&
            (previousWaitBlock = waitBlock->Previous)
            )
        {
            // We have an exclusive waiter and there are
            // multiple waiters.
            // We'll only be waking this waiter.

            // Unlink the wait block from the list.
            // Although other wait blocks may have their
            // Last pointers set to this wait block,
            // the algorithm to find the last wait block
            // will stop here. Likewise the Next pointers
            // are never followed beyond this point, so
            // we don't need to clear those.
            firstWaitBlock->Last = previousWaitBlock;

            // Make sure we only wake this waiter.
            waitBlock->Previous = NULL;

            if (!IgnoreOwned)
            {
                // Clear the traversing bit.
                _InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_TRAVERSING);
            }

            break;
        }
        else
        {
            // We're waking an exclusive waiter and there
            // is only one waiter, or we are waking
            // a shared waiter and possibly others.

            newValue = 0;

            if ((newValue = (ULONG_PTR)_InterlockedCompareExchangePointer(
                (PPVOID)&QueuedLock->Value,
                (PVOID)newValue,
                (PVOID)value
                )) == value)
                break;

            // Someone changed the lock (acquired it or
            // pushed a wait block).

            value = newValue;
        }
    }

    return waitBlock;
}