Hey Carl,
The vad.u.VadFlags.Protection is just the *original* protection applied to all pages in the range allocated with VirtualAlloc. For example, you can VirtualAlloc(addr, size, MEM_RESERVE, PAGE_NOACCESS) and the corresponding vad.u.VadFlags.Protection will show PAGE_NOACCESS. But later you can use VirtualAlloc again with MEM_COMMIT to commit one or more pages in the range, specifying different protections for each page, or you can just use VirtualProtect() to change a protection (which does not update vad.u.VadFlags.Protection). So vad.u.VadFlags.Protection is just the original protection for all pages in the range when initially reserved or committed, not the current protection. For the current protection of each page, check the PTE like you're already doing.
MHL