/nt!MmCopyVirtualMemory - VAD iteration - Windows 10 (15063.0.amd64fre.rs2_release.170317-1834).cpp Secret
Last active
July 20, 2017 21:16
-
-
Save nmulasmajic/56007f5dfd92a4c78b3a904add5a18f9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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