Example #1
0
/// <summary>
/// Enumerate committed, accessible, non-guarded memory regions
/// </summary>
/// <param name="pList">Region list</param>
/// <param name="start">Region start</param>
/// <param name="end">Region end</param>
/// <param name="mapSections">If set to FALSE, section objects will be excluded from list</param>
/// <returns>Status code</returns>
NTSTATUS BBBuildProcessRegionListForRange( IN PLIST_ENTRY pList, IN ULONG_PTR start, IN ULONG_PTR end, IN BOOLEAN mapSections )
{
    NTSTATUS status = STATUS_SUCCESS;
    MEMORY_BASIC_INFORMATION mbi = { 0 };
    SIZE_T length = 0;
    ULONG_PTR memptr = 0;
    PMAP_ENTRY pEntry = NULL;

    for (memptr = start; memptr < end; memptr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize)
    {
        status = ZwQueryVirtualMemory( ZwCurrentProcess(), (PVOID)memptr, MemoryBasicInformationEx, &mbi, sizeof( mbi ), &length );

        if (!NT_SUCCESS( status ))
        {
            DPRINT( "BlackBone: %s: ZwQueryVirtualMemory for address 0x%p returned status 0x%X\n", __FUNCTION__, memptr, status );

            // STATUS_INVALID_PARAMETER is a normal status for last secured VAD under Win7
            return status == STATUS_INVALID_PARAMETER ? STATUS_SUCCESS : status;
        }
        // Skip non-committed, no-access and guard pages
        else if (mbi.State == MEM_COMMIT &&  mbi.Protect != PAGE_NOACCESS && !(mbi.Protect & PAGE_GUARD))
        {
            // Ignore shared memory if required
            if (mbi.Type != MEM_PRIVATE && !mapSections)
                continue;

            pEntry = ExAllocatePoolWithTag( PagedPool, sizeof( MAP_ENTRY ), BB_POOL_TAG );
            if (pEntry == NULL)
            {
                DPRINT( "BlackBone: %s: Failed to allocate memory for Remap descriptor\n", __FUNCTION__ );
                BBCleanupPageList( FALSE, pList );
                return STATUS_NO_MEMORY;
            }

            pEntry->originalPtr = (ULONG_PTR)mbi.BaseAddress;
            pEntry->size = mbi.RegionSize;
            pEntry->newPtr = 0;
            pEntry->pMdl = NULL;
            pEntry->locked = FALSE;
            pEntry->shared = mbi.Type != MEM_PRIVATE;

            InsertTailList( pList, &pEntry->link );
        }
    }

    //if (NT_SUCCESS( status ))
        //status = BBConsolidateRegionList( pList );

    return status;
}
Example #2
0
HANDLE NTAPI
RtlDebugCreateHeap(ULONG Flags,
                   PVOID Addr,
                   SIZE_T ReserveSize,
                   SIZE_T CommitSize,
                   PVOID Lock,
                   PRTL_HEAP_PARAMETERS Parameters)
{
    MEMORY_BASIC_INFORMATION MemoryInfo;
    NTSTATUS Status;
    PHEAP Heap;

    /* Validate parameters */
    if (ReserveSize <= HEAP_ENTRY_SIZE)
    {
        DPRINT1("HEAP: Incorrect ReserveSize %x\n", ReserveSize);
        return NULL;
    }

    if (ReserveSize < CommitSize)
    {
        DPRINT1("HEAP: Incorrect CommitSize %x\n", CommitSize);
        return NULL;
    }

    if (Flags & HEAP_NO_SERIALIZE && Lock)
    {
        DPRINT1("HEAP: Can't specify Lock routine and have HEAP_NO_SERIALIZE flag set\n");
        return NULL;
    }

    /* If the address is specified, check it's virtual memory */
    if (Addr)
    {
        Status = ZwQueryVirtualMemory(NtCurrentProcess(),
                                      Addr,
                                      MemoryBasicInformation,
                                      &MemoryInfo,
                                      sizeof(MemoryInfo),
                                      NULL);

        if (!NT_SUCCESS(Status))
        {
            DPRINT1("HEAP: Specified heap base address %p is invalid, Status 0x%08X\n", Addr, Status);
            return NULL;
        }

        if (MemoryInfo.BaseAddress != Addr)
        {
            DPRINT1("HEAP: Specified heap base address %p is not really a base one %p\n", Addr, MemoryInfo.BaseAddress);
            return NULL;
        }

        if (MemoryInfo.State == MEM_FREE)
        {
            DPRINT1("HEAP: Specified heap base address %p is free\n", Addr);
            return NULL;
        }
    }

    /* All validation performed, now call the real routine with skip validation check flag */
    Flags |= HEAP_SKIP_VALIDATION_CHECKS |
             HEAP_TAIL_CHECKING_ENABLED |
             HEAP_FREE_CHECKING_ENABLED;

    Heap = RtlCreateHeap(Flags, Addr, ReserveSize, CommitSize, Lock, Parameters);
    if (!Heap) return NULL;

    // FIXME: Capture stack backtrace

    RtlpValidateHeapHeaders(Heap, TRUE);

    return Heap;
}
Example #3
0
/// <summary>
/// Process section object pages
/// Function will attempt to trigger copy-on-write for underlying pages to convert them into private
/// If copy-on-write fails, region will be then mapped as read-only
/// </summary>
/// <param name="pEntry">Region data</param>
/// <returns>Status code</returns>
NTSTATUS BBHandleSharedRegion( IN PMAP_ENTRY pEntry )
{
    NTSTATUS status = STATUS_SUCCESS;

    MEMORY_BASIC_INFORMATION mbi = { 0 };
    SIZE_T length = 0;
    ULONG_PTR memptr = 0;

    // Iterate underlying memory regions
    for (memptr = pEntry->originalPtr; memptr < pEntry->originalPtr + pEntry->size; memptr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize)
    {
        PVOID pBase = NULL;
        SIZE_T size = 0;
        MEMORY_WORKING_SET_EX_INFORMATION wsInfo = { 0 };
        ULONG oldProt = 0;
        BOOLEAN writable = FALSE;

        status = ZwQueryVirtualMemory( ZwCurrentProcess(), (PVOID)memptr, MemoryBasicInformation, &mbi, sizeof( mbi ), &length );
        if (!NT_SUCCESS( status ))
        {
            DPRINT( "BlackBone: %s: ZwQueryVirtualMemory for address 0x%p failed\n", __FUNCTION__, memptr );
            return status;
        }

        writable = (mbi.Protect & (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE));
        pBase = mbi.BaseAddress;
        size = (SIZE_T)mbi.RegionSize;

        // Make readonly pages writable
        if (writable || NT_SUCCESS( ZwProtectVirtualMemory( ZwCurrentProcess(), &pBase, &size, PAGE_EXECUTE_READWRITE, &oldProt ) ))
        {
            BOOLEAN failed = FALSE;

            // Touch pages to trigger copy-on-write and create private copies
            // This is crucial to prevent changes on section pages
            __try
            {
                ProbeForWrite( mbi.BaseAddress, mbi.RegionSize, PAGE_SIZE );
            }
            __except (EXCEPTION_EXECUTE_HANDLER)
            {
                DPRINT( "BlackBone: %s: Exception while touching address 0x%p\n", __FUNCTION__, mbi.BaseAddress );
                failed = TRUE;
            }

            // Restore protection
            if (writable == FALSE)
                ZwProtectVirtualMemory( ZwCurrentProcess(), &pBase, &size, oldProt, &oldProt );

            if (failed)
                return STATUS_SHARING_VIOLATION;

            // If region was writable, it's safe to map shared pages
            if (writable)
                continue;

            //
            // Ensure pages were made private
            //
            for (ULONG_PTR pPage = (ULONG_PTR)mbi.BaseAddress; pPage < (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize; pPage += PAGE_SIZE)
            {
                RtlZeroMemory( &wsInfo, sizeof( wsInfo ) );

                wsInfo.VirtualAddress = (PVOID)pPage;

                // Check page 'shared' flag
                if (NT_SUCCESS( ZwQueryVirtualMemory( ZwCurrentProcess(), NULL, MemoryWorkingSetExInformation, &wsInfo, sizeof( wsInfo ), &length ) ) &&
                     wsInfo.VirtualAttributes.Shared)
                {
                    DPRINT( "BlackBone: %s: Page at address 0x%p is still shared!", __FUNCTION__, pPage );
                    return STATUS_SHARING_VIOLATION;
                }
            }
        }
        else
        {