/nt!MmCopyVirtualMemory - VAD iteration - Windows 10 (15063.0.amd64fre.rs2_release.170317-1834).cpp Secret
Last active Jul 20, 2017
// Get the process that we are currently executing in. | |
CurrentProcess = CurrentThread->Tcb.ApcState.Process; | |
// Is the current process the one we're reading memory from? | |
if ( CurrentProcess == FromProcess ) | |
{ | |
ApcState_FromProcess.Process = NULL; | |
} | |
else | |
{ | |
// It's not, so we will swap to that process context. | |
KiStackAttachProcess(FromProcess, 0, &ApcState_FromProcess); | |
} | |
EnclaveVad = NULL; | |
// Is there a valid pointer here? If not, we skip VAD iteration. | |
if ( !FromProcess->Vm.Instance.VmWorkingSetList[3].LastAccessClearingRemainder ) | |
{ | |
NumberOfBytesIntoFromAddress = BufferLength; | |
goto SkipVadIteration; | |
} | |
// Acquire a lock on the "FromProcess"' address space. This'll disallow memory | |
// allocations, frees, and more. | |
LOCK_ADDRESS_SPACE(CurrentThread, FromProcess); | |
// Start at the root node. | |
CurrentVadEntry = (_MMVAD *)FromProcess->VadRoot.Root; | |
bStoppedOnRightNode = FALSE; | |
bFoundVadEntry = FALSE; | |
// Do we have a root node? If not, skip this logic. | |
if ( !CurrentVadEntry ) | |
goto VadNoRoot; | |
// Find the VAD entry corresponding to the address we're copying from. | |
VirtualPageFrameNumber = (FromAddress >> 12) /* This strips off the offset from the address. */; | |
// Walk the right nodes. | |
while ( VirtualPageFrameNumber > | |
/* This will take into consideration the "High" byte that's saved in the VAD when using the "Virtual Page Number" | |
* (Vpn) address. */ | |
(CurrentVadEntry->Core.EndingVpn | ((unsigned __int64)CurrentVadEntry->Core.EndingVpnHigh << 32)) ) | |
{ | |
// Walk the right nodes. | |
NewVadEntry = (_MMVAD *)CurrentVadEntry->Core.VadNode.Right; | |
// The right node doesn't exist. | |
if ( !NewVadEntry ) | |
{ | |
// Signal that we stopped during a walk of the right nodes. | |
bStoppedOnRightNode = TRUE; | |
goto VadNoRoot; | |
} | |
WalkRight: | |
// Keep iterating. | |
CurrentVadEntry = NewVadEntry; | |
} | |
// Walk a left node (this isn't a loop). | |
if ( VirtualPageFrameNumber < | |
(CurrentVadEntry->Core.StartingVpn | ((unsigned __int64)CurrentVadEntry->Core.StartingVpnHigh << 32)) ) | |
{ | |
NewVadEntry = (_MMVAD *)CurrentVadEntry->Core.VadNode.Left; | |
if ( !NewVadEntry ) | |
{ | |
// Signal that we stopped during a walk of the left nodes. | |
bStoppedOnRightNode = FALSE; | |
goto VadNoRoot; | |
} | |
// Go back to iterating the right nodes. | |
goto WalkRight; | |
} | |
// At this point we're done walking both the left nodes and the right nodes. | |
bFoundVadEntry = TRUE; | |
VadNoRoot: | |
// Did we find a VAD entry corresponding to the target VirtualPageFrameNumber? | |
if ( bFoundVadEntry ) | |
{ | |
if ( CurrentVadEntry->Core.u.VadFlags.VadType != VadAwe /* 3 */ ) | |
goto NotVadAwe_Or_NotEnclave; | |
VadFlags = CurrentVadEntry->Core.u.VadFlags; | |
// Is the Enclave bit set? | |
if (!_bittest((const signed int *)&VadFlags, 18u)) | |
goto NotVadAwe_Or_NotEnclave; | |
EnclaveVad = CurrentVadEntry; | |
// If bit 1 is set of the LastContiguousPte, it means it's not the appropriate | |
// type. | |
if ( CurrentVadEntry->LastContiguousPte & 2 ) | |
goto NotVadAwe_Or_NotEnclave; | |
EnclaveVad = NULL; | |
} | |
else /* We didn't find a VAD entry. */ | |
{ | |
// Did we stop on the right-node walk? | |
if ( bStoppedOnRightNode ) | |
{ | |
OriginalVadEntry = CurrentVadEntry; | |
RightVadChildEntry = CurrentVadEntry->Core.VadNode.Right; | |
// I don't think this will ever be true. | |
if ( RightVadChildEntry ) | |
{ | |
CurrentVadEntry = (_MMVAD *)CurrentVadEntry->Core.VadNode.Right; | |
for ( i = (_MMVAD *)RightVadChildEntry->Left; i; i = (_MMVAD *)i->Core.VadNode.Left ) | |
CurrentVadEntry = i; | |
} | |
} | |
else | |
{ | |
for ( CurrentVadEntry = (_MMVAD *)(CurrentVadEntry->Core.VadNode.ParentValue & 0xFFFFFFFFFFFFFFFCui64); | |
CurrentVadEntry; | |
CurrentVadEntry = (_MMVAD *)(CurrentVadEntry->Core.VadNode.ParentValue & 0xFFFFFFFFFFFFFFFCui64) ) | |
{ | |
if ( (_MMVAD *)CurrentVadEntry->Core.VadNode.Left == OriginalVadEntry ) | |
break; | |
OriginalVadEntry = CurrentVadEntry; | |
} | |
} | |
NotVadAwe_Or_NotEnclave: | |
if ( EnclaveVad ) | |
{ | |
NumberOfBytesIntoFromAddress = (((EnclaveVad->Core.EndingVpn | ((unsigned __int64)(unsigned __int8)EnclaveVad->Core.EndingVpnHigh << 32)) << 12) | 0xFFF) | |
- FromAddress | |
+ 1; | |
goto DoneWithVadIteration; | |
} | |
} | |
// Did we find a valid Vad node now? | |
if ( !CurrentVadEntry ) | |
goto NoVadRootNode; | |
do | |
{ | |
VadEntry = CurrentVadEntry; | |
// This logic is similar to the one above, so it will not be documented as | |
// thoroughly. It's important to note that this is most likely a function that | |
// has been inlined multiple times. | |
if ( CurrentVadEntry->Core.u.VadFlags.VadType == VadAwe ) | |
{ | |
VadFlags = CurrentVadEntry->Core.u.LongFlags; | |
// Enclave bit check again. | |
if ( _bittest((const signed int *)&VadFlags, 18u) ) | |
{ | |
EnclaveVad = CurrentVadEntry; | |
if ( CurrentVadEntry->LastContiguousPte & 2 ) | |
break; | |
EnclaveVad = NULL; | |
} | |
} | |
if ((CurrentVadEntry->Core.EndingVpn | ((unsigned __int64)(unsigned __int8)CurrentVadEntry->Core.EndingVpnHigh << 32)) >= (FromAddress + BufferLength - 1) >> 12 ) | |
goto NoVadRootNode; | |
TemporaryEntry = CurrentVadEntry; | |
RightVadChildEntry = CurrentVadEntry->Core.VadNode.Right; | |
if ( RightVadChildEntry ) | |
{ | |
CurrentVadEntry = (_MMVAD *)CurrentVadEntry->Core.VadNode.Right; | |
for ( j = (_MMVAD *)RightVadChildEntry->Left; j; j = (_MMVAD *)j->Core.VadNode.Left ) | |
CurrentVadEntry = j; | |
} | |
else | |
{ | |
for ( CurrentVadEntry = (_MMVAD *)(CurrentVadEntry->Core.VadNode.ParentValue & 0xFFFFFFFFFFFFFFFCui64); | |
CurrentVadEntry; | |
CurrentVadEntry = (_MMVAD *)(CurrentVadEntry->Core.VadNode.ParentValue & 0xFFFFFFFFFFFFFFFCui64) ) | |
{ | |
if ( (_MMVAD *)CurrentVadEntry->Core.VadNode.Left == TemporaryEntry ) | |
break; | |
TemporaryEntry = CurrentVadEntry; | |
} | |
} | |
} while ( CurrentVadEntry ); | |
if ( CurrentVadEntry ) | |
{ | |
NumberOfBytesIntoFromAddress = ((VadEntry->Core.StartingVpn | ((unsigned __int64)(unsigned __int8)VadEntry->Core.StartingVpnHigh << 32)) << 12) - FromAddress; | |
} | |
else | |
{ | |
NoVadRootNode: | |
NumberOfBytesIntoFromAddress = BufferLength; | |
} | |
DoneWithVadIteration: | |
// Release lock. | |
UNLOCK_ADDRESS_SPACE(CurrentThread, FromProcess); | |
SkipVadIteration: | |
// Detach from process context, if needed. | |
if ( CurrentProcess != FromProcess ) | |
KiUnstackDetachProcess(&ApcState_FromProcess, 0i64); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment