c00000fd
c00000fd

Reputation: 22327

How to tell if a virtual memory page has been locked?

Say, if at some point a range of the virtual memory in my process was locked as such:

//Memory was reserved & committed as such
void* pMem = ::VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

//...

//And then
::VirtualLock(pMem, 4096);

So having an arbitrary address of a page in a virtual memory in my process, can I tell if it was locked?

Upvotes: 2

Views: 1650

Answers (2)

Djof
Djof

Reputation: 603

For anyone looking at this in the future, XP and later now include APIs that do this: QueryWorkingSet and QueryWorkingSetEx.

Look for the Locked bit in the PSAPI_WORKING_SET_EX_BLOCK structure, similar to the answer relying on ZwQueryVirtualMemory.

Upvotes: 0

RbMm
RbMm

Reputation: 33804

by using win32 api this is impossible. but if use ZwQueryVirtualMemory with undocumented MEMORY_INFORMATION_CLASS values - this is possible. for data structures definition - see ntmmapi.h

we need use MemoryWorkingSetExInformation with MEMORY_WORKING_SET_EX_BLOCK and use ULONG_PTR Locked : 1; member

demo test:

NTSTATUS IsPageLocked(PVOID BaseAddress, BOOLEAN& Locked)
{
    MEMORY_WORKING_SET_EX_INFORMATION mwsei = { BaseAddress };

    NTSTATUS status = ZwQueryVirtualMemory(NtCurrentProcess(), 0, MemoryWorkingSetExInformation, &mwsei, sizeof(mwsei), 0);

    if (0 <= status)
    {
        if (mwsei.VirtualAttributes.Valid)
        {
            Locked = mwsei.VirtualAttributes.Locked;
        }
        else
        {
            status = STATUS_INVALID_ADDRESS;
        }
    }

    return status;
}

NTSTATUS IsPageLockedEx(PVOID BaseAddress, BOOLEAN& Locked)
{
    NTSTATUS status = IsPageLocked(BaseAddress, Locked);
    if (0 > status)
    {
        DbgPrint("IsPageLocked - error %x\n", status);
    }
    else
    {
        DbgPrint("IsPageLocked = %x\n", Locked);
    }
    return status;
}

void CheckVA()
{
    if (PVOID pv = VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))
    {
        BOOLEAN Locked;
        NTSTATUS status = IsPageLockedEx(pv, Locked);

        if (status == STATUS_INVALID_ADDRESS)
        {
            // at this point  physical memory for pv not yet committed. reference memory for commit physical page
            if (*(PBYTE)pv) __nop();

            status = IsPageLockedEx(pv, Locked);
        }

        if (VirtualLock(pv, PAGE_SIZE))
        {
            IsPageLockedEx(pv, Locked);

            if (VirtualUnlock(pv, PAGE_SIZE))
            {
                IsPageLockedEx(pv, Locked);
            }
            else
            {
                __debugbreak();
            }
        }

        VirtualFree(pv, 0, MEM_RELEASE);
    }
}

and DbgPrint output

IsPageLocked - error c0000141
IsPageLocked = 0
IsPageLocked = 1
IsPageLocked = 0

Upvotes: 3

Related Questions