2017-05-16 3 views
1

Dites, si à un moment donné une plage de la mémoire virtuelle dans mon processus a été verrouillé en tant que tel:Comment savoir si une page de mémoire virtuelle a été verrouillée?

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

//... 

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

donc ayant une adresse arbitraire d'une page dans une mémoire virtuelle dans mon processus, puis-je savoir si était locked? En utilisant win32 api cela est impossible.

Répondre

3

mais si utiliser ZwQueryVirtualMemory avec non documentéMEMORY_INFORMATION_CLASS valeurs - c'est possible. pour la définition des structures de données - voir ntmmapi.h

nous devons utiliser MemoryWorkingSetExInformation avec MEMORY_WORKING_SET_EX_BLOCK et utiliser ULONG_PTR Locked : 1; membre

test de démonstration:

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); 
    } 
} 

et DbgPrint sortie

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

Très belle trouvaille. Je vous remercie. Je suis curieux cependant, pourquoi Microsoft n'a-t-il pas exposé une API officielle pour le faire? – c00000fd

+1

@ c00000fd - pense que c'est très rare quand on a besoin de savoir (exactement quand la page est verrouillée). 'VirtualQueryEx' existe seulement qui est un minuscule shell sur' ZwQueryVirtualMemory' avec une classe d'information codée en dur * MemoryBasicInformation * - et seulement cette classe et documentée. Cependant, un autre infoclass pour mon look est très utile dans le même cas - disons * MemoryMappedFilenameInformation * ou * MemoryWorkingSetInformation *. – RbMm

+0

Juste pour développer. J'ai confirmé expérimentalement que cette méthode fonctionne à partir de Windows Vista et de tout système d'exploitation ultérieur. (Donc, pas de support 'XP', si c'est important.) Aussi, si quelqu'un veut charger' ZwQueryVirtualMemory' dynamiquement, [voici un exemple] (http://www.rohitab.com/discuss/topic/41092-how-to- use-ntqueryvirtualmemory-to-get-loaded-dlls /? p = 10096341) comment. – c00000fd