nt!MiDispatchFault函数分析之nt!MiCompleteProtoPteFault函数的作用
nt!MiDispatchFault函数分析之nt!MiCompleteProtoPteFault函数的作用
第一部分:
//
// PTE is still in transition state, same protection, etc.
//
ASSERT (Pfn1->u4.InPageError == 0);
if (Pfn1->u2.ShareCount == 0) {
MI_REMOVE_LOCKED_PAGE_CHARGE (Pfn1, 9);
}
Pfn1->u2.ShareCount += 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
Pfn1->u3.e1.CacheAttribute = MiCached;
MI_MAKE_TRANSITION_PTE_VALID (TempPte, ReadPte);
if (StoreInstruction && TempPte.u.Hard.Write) {
MI_SET_PTE_DIRTY (TempPte);
}
MI_WRITE_VALID_PTE (ReadPte, TempPte);
if (PointerProtoPte != NULL) {
//
// The prototype PTE has been made valid, now make the
// original PTE valid. The original PTE must still be invalid
// otherwise MiWaitForInPageComplete would have returned
// a collision status.
//
ASSERT (PointerPte->u.Hard.Valid == 0);
//
// PTE is not valid, continue with operation.
//
status = MiCompleteProtoPteFault (StoreInstruction,
VirtualAddress,
PointerPte,
PointerProtoPte,
OldIrql,
&LockedProtoPfn);
第二部分:
//
// This is the thread which owns the event, clear the event field
// in the PFN database.
//
Pfn1 = ReadBlock->Pfn;
Page = &ReadBlock->Page[0];
NumberOfBytes = (LONG)ReadBlock->Mdl.ByteCount;
CheckPte = ReadBlock->BasePte;
dv
ReadPte = 0xe1009c00
ReadBlock = 0x8962de10
1: kd> dx -r1 ((ntkrnlmp!_MMINPAGE_SUPPORT *)0x8962de10)
((ntkrnlmp!_MMINPAGE_SUPPORT *)0x8962de10) : 0x8962de10 [Type: _MMINPAGE_SUPPORT *]
[+0x000] Event [Type: _KEVENT]
[+0x010] IoStatus [Type: _IO_STATUS_BLOCK]
[+0x018] ReadOffset : {0} [Type: _LARGE_INTEGER]
[+0x020] WaitCount : 1 [Type: long]
[+0x024] Thread : 0x8999d020 [Type: _ETHREAD *]
[+0x028] FilePointer : 0x899abb00 [Type: _FILE_OBJECT *]
[+0x02c] BasePte : 0xe1009c00 [Type: _MMPTE *]
[+0x030] Pfn : 0x810f1650 [Type: _MMPFN *]
[+0x034] u1 [Type: __unnamed]
[+0x038] Mdl [Type: _MDL]
[+0x054] Page [Type: unsigned long [16]]
[+0x094] ListEntry [Type: _SINGLE_LIST_ENTRY]
1: kd> dx -r1 (*((ntkrnlmp!_MDL *)0x8962de48))
(*((ntkrnlmp!_MDL *)0x8962de48)) [Type: _MDL]
[+0x000] Next : 0x0 [Type: _MDL *]
[+0x004] Size : 32 [Type: short]
[+0x006] MdlFlags : 66 [Type: short]
[+0x008] Process : 0x20202020 [Type: _EPROCESS *]
[+0x00c] MappedSystemVa : 0x80402020 [Type: void *]
[+0x010] StartVa : 0x2700000 [Type: void *]
[+0x014] ByteCount : 0x1000 [Type: unsigned long]
[+0x018] ByteOffset : 0x0 [Type: unsigned long]
1: kd> dx -r1 (*((ntkrnlmp!unsigned long (*)[16])0x8962de64))
(*((ntkrnlmp!unsigned long (*)[16])0x8962de64)) [Type: unsigned long [16]]
[0] : 0xa0ee [Type: unsigned long]
dv
ReadPte = 0xe1009c00
IoCompleteTime = {0}
ProtoProtect = struct _MMWSLE
PfnHeld = 0
StoreInstruction = 0
Flags = 0xc1080000
OldIrql = 0x01 ''
CheckPte = 0xe1009c00
Page = 0x8962de64
1: kd> dx -r1 ((ntkrnlmp!unsigned long *)0x8962de64)
((ntkrnlmp!unsigned long *)0x8962de64) : 0x8962de64 : 0xa0ee [Type: unsigned long *]
0xa0ee [Type: unsigned long]
1: kd> dd 0xe1009c00
e1009c00 0a0ee8c0 fcf194c6 fcf194c6 fcf194c6
e1009c10 fcf194c6 fcf194c6 fcf194c6 fcf194c6
e1009c20 fcf194c6 fcf194c6 fcf194c6 fcf194c6
else {
PageFrameIndex = *Page;
MI_SNAP_DATA (MI_PFN_ELEMENT (PageFrameIndex),
MI_PFN_ELEMENT (PageFrameIndex)->PteAddress,
0xC);
}
#define MI_SNAP_DATA(_Pfn, _Pte, _CallerId) MiSnapData(_Pfn, _Pte, _CallerId)
CheckPte += 1;
Page += 1;
NumberOfBytes -= PAGE_SIZE;
第三部分:
//
// PTE is still in transition state, same protection, etc.
//
ASSERT (Pfn1->u4.InPageError == 0);
if (Pfn1->u2.ShareCount == 0) {
MI_REMOVE_LOCKED_PAGE_CHARGE (Pfn1, 9);
}
Pfn1->u2.ShareCount += 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
Pfn1->u3.e1.CacheAttribute = MiCached;
MI_MAKE_TRANSITION_PTE_VALID (TempPte, ReadPte);
dv
Pfn1 = 0x810f1650
第四部分:
1: kd> dd 810f1650
810f1650 00000000 e1009c00 00000000 00011008
810f1660 fcf194c6 2000a1cd
Pfn1->u2.ShareCount += 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
Pfn1->u3.e1.CacheAttribute = MiCached;
1: kd> dd 810f1650
810f1650 00000000 e1009c00 00000001 00011608
810f1660 fcf194c6 0000a1cd
第五部分:修改 e1009c00 ,先构造一个TempPte
MI_MAKE_TRANSITION_PTE_VALID (TempPte, ReadPte); //关键代码1:构造TempPte=0a0ee921
#define MI_MAKE_TRANSITION_PTE_VALID(OUTPTE,PPTE) \
ASSERT (((PPTE)->u.Hard.Valid == 0) && \
((PPTE)->u.Trans.Prototype == 0) && \
((PPTE)->u.Trans.Transition == 1)); \
(OUTPTE).u.Long = (((PPTE)->u.Long & ~0xFFF) | \
(MmProtectToPteMask[(PPTE)->u.Trans.Protection]) | \
MiDetermineUserGlobalPteMask ((PMMPTE)PPTE));
1: kd> p
nt!MiDispatchFault+0x29fa:
80a93016 e88fc30300 call nt!MiDetermineUserGlobalPteMask (80acf3aa)
1: kd> p
nt!MiDispatchFault+0x29ff:
80a9301b 8bd8 mov ebx,eax
1: kd> r
eax=00000121
1: kd> p
nt!MiDispatchFault+0x2a19:
80a93035 0bd8 or ebx,eax
1: kd> r
eax=0a0ee000 ebx=00000921
第六部分:修改 e1009c00 ,使用TempPte
MI_WRITE_VALID_PTE (ReadPte, TempPte); 0a0ee921 //关键代码2:赋值给ReadPte
1: kd> p
nt!MiDispatchFault+0x2b32:
80a9314e 8918 mov dword ptr [eax],ebx
1: kd> r
eax=e1009c00 ebx=0a0ee921
1: kd> dd e1009c00
e1009c00 0a0ee921 fcf194c6 fcf194c6 fcf194c6
e1009c10 fcf194c6 fcf194c6 fcf194c6 fcf194c6
e1009c20 fcf194c6 fcf194c6 fcf194c6 fcf194c6
e1009c30 fcf194c6 fcf194c6 fcf194c6 fcf194c6
第七部分:现在还是无效的not valid,需要修改C0304200
1: kd> !pte c1080000
VA c1080000
PDE at C0300C10 PTE at C0304200
contains 0A03F963 contains 00027400
pfn a03f -G-DA--KWEV not valid
Proto: E1009C00
1: kd> dd 0xc0304200
c0304200 00027400 00027402 00027404 00027406
c0304210 00027408 0002740a 0002740c 0002740e
c0304220 00027410 00027412 00027414 00027416
c0304230 00027418 0002741a 0002741c 0002741e
//关键代码3:改变 00027400
//
// PTE is not valid, continue with operation.
//
status = MiCompleteProtoPteFault (StoreInstruction,
VirtualAddress,
PointerPte,
PointerProtoPte,
OldIrql,
&LockedProtoPfn);
第八部分:
1: kd> p
nt!MiDispatchFault+0x2b64:
80a93180 e8df4fffff call nt!MiCompleteProtoPteFault (80a88164)
1: kd> t
nt!MiCompleteProtoPteFault:
80a88164 55 push ebp
1: kd> kc
#
00 nt!MiCompleteProtoPteFault
01 nt!MiDispatchFault
02 nt!MmAccessFault
03 nt!_KiTrap0E
04 nt!CcMapData
05 Ntfs!NtfsMapStream
06 Ntfs!NtfsReadBootSector
07 Ntfs!NtfsMountVolume
08 Ntfs!NtfsCommonFileSystemControl
09 Ntfs!NtfsFspDispatch
0a nt!ExpWorkerThread
0b nt!PspSystemThreadStartup
0c nt!KiThreadStartup
1: kd> dv
StoreInstruction = 0
FaultingAddress = 0xc1080000
PointerPte = 0xc0304200
PointerProtoPte = 0xe1009c00
OldIrql = 0x01 ''
LockedProtoPfn = 0xf78d68e0
FileOffset = 0n48
OriginalPte = struct _MMPTE
ProtoProtect = struct _MMWSLE
Status = 0n1
MarkPageDirty = 0xa0ee921
Pfn1 = 0x80a88164
第九部分:
NTSTATUS
MiCompleteProtoPteFault (
IN ULONG_PTR StoreInstruction,
IN PVOID FaultingAddress,
IN PMMPTE PointerPte,
IN PMMPTE PointerProtoPte,
IN KIRQL OldIrql,
IN OUT PMMPFN *LockedProtoPfn
)
/*++
Routine Description:
This routine completes a prototype PTE fault. It is invoked
after a read operation has completed bringing the data into
memory.
第十部分:
ProtoPteContents.u.Long = PointerProtoPte->u.Long;
1: kd> p
nt!MiCompleteProtoPteFault+0x50:
80a881b4 8b3f mov edi,dword ptr [edi]
1: kd> r
eax=00000002 ebx=0a0ee921 ecx=f78d6910 edx=e80e369c esi=c0304200 edi=e1009c00
PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (&ProtoPteContents);
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
Pfn1->u3.e1.PrototypePte = 1;
1: kd> p
nt!MiCompleteProtoPteFault+0x52:
80a881b6 8b0dd805bf80 mov ecx,dword ptr [nt!MmPfnDatabase (80bf05d8)]
1: kd> p
nt!MiCompleteProtoPteFault+0x58:
80a881bc c1ef0c shr edi,0Ch
1: kd> p
nt!MiCompleteProtoPteFault+0x5b:
80a881bf 8d047f lea eax,[edi+edi*2]
1: kd> r
eax=00000002 ebx=0a0ee921 ecx=81000000 edx=e80e369c esi=c0304200 edi=0000a0ee
eip=80a881bf esp=f78d682c ebp=f78d6858 iopl=0 nv up ei pl nz na pe cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000207
nt!MiCompleteProtoPteFault+0x5b:
80a881bf 8d047f lea eax,[edi+edi*2]
1: kd> dd 810f1650
810f1650 00000000 e1009c00 00000001 00011608
810f1660 fcf194c6 0000a1cd
+0x00c u3 : __unnamed
+0x000 e1 : _MMPFNENTRY
+0x000 Modified : Pos 0, 1 Bit
+0x000 ReadInProgress : Pos 1, 1 Bit
+0x000 WriteInProgress : Pos 2, 1 Bit
+0x000 PrototypePte : Pos 3, 1 Bit 1
//
// Capture prefetch fault information.
//
OriginalPte = Pfn1->OriginalPte;
第十一部分:
ContainingPageTablePointer = MiGetPteAddress (PointerPte); C0300C10
PointerPte = 0xc0304200
#define MiGetPteAddress(va) ((PMMPTE)(((((ULONG)(va)) >> 12) << 2) + PTE_BASE))
1: kd> !pte 0xc0304200
VA c1080000
PDE at C0300C10 PTE at C0304200
contains 0A03F963 contains 00027400
pfn a03f -G-DA--KWEV not valid
Proto: E1009C00
C0304200
1100 0000 0011 0000 0100 0010 0000 0000
11 00 00 00 00 11 00 00 01 00 00
300c10
第十二部分:
eax=0a03f963
0a03f
Pfn2 = MI_PFN_ELEMENT (ContainingPageTablePointer->u.Hard.PageFrameNumber); 81000000+0a03f*18
1: kd> dd 81000000+0a03f*18
810f05e8 00000000 c0300c10 00000025 00011601
810f05f8 00000080 00000039
1: kd> p
nt!MiCompleteProtoPteFault+0x87:
80a881eb 8d04c2 lea eax,[edx+eax*8]
1: kd> p
nt!MiCompleteProtoPteFault+0x8a:
80a881ee ff4008 inc dword ptr [eax+8]
1: kd> r
eax=810f05e8
dv
ProtoProtect = struct _MMWSLE
1: kd> dx -r1 (*((ntkrnlmp!_MMWSLE *)0xf78d6854))
(*((ntkrnlmp!_MMWSLE *)0xf78d6854)) [Type: _MMWSLE]
[+0x000] u1 [Type: __unnamed]
1: kd> dd 0xf78d6854
f78d6854 00000346
ProtoProtect.u1.Long = 0;
ProtoProtect.u1.e1.Protection = MI_GET_PROTECTION_FROM_SOFT_PTE(&OriginalPte);
ProtoProtect.u1.e1.SameProtectAsProto = 1;
#define MI_GET_PROTECTION_FROM_SOFT_PTE(PTE) ((PTE)->u.Soft.Protection)
fcf194c6
+0x000 Soft : _MMPTE_SOFTWARE
+0x000 Valid : Pos 0, 1 Bit
+0x000 PageFileLow : Pos 1, 4 Bits
+0x000 Protection : Pos 5, 5 Bits 00 110=0x6
0100 1100 0110
第十三部分:
MI_MAKE_VALID_PTE (TempPte,
PageFrameIndex,
ProtoProtect.u1.e1.Protection,
PointerPte); //TempPte=ebx=0a0ee921
#define MI_MAKE_VALID_PTE(OUTPTE,FRAME,PMASK,PPTE) \
(OUTPTE).u.Long = ((FRAME << 12) | \
(MmProtectToPteMask[PMASK]) | \
MiDetermineUserGlobalPteMask ((PMMPTE)PPTE));
1: kd> p
nt!MiCompleteProtoPteFault+0x4e2:
80a88646 e85f6d0400 call nt!MiDetermineUserGlobalPteMask (80acf3aa)
1: kd> p
nt!MiCompleteProtoPteFault+0x4e7:
80a8864b 8bd8 mov ebx,eax
1: kd> r
eax=00000121
1: kd> p
nt!MiCompleteProtoPteFault+0x4f0:
80a88654 c1e70c shl edi,0Ch
1: kd> p
nt!MiCompleteProtoPteFault+0x4f3:
80a88657 0bdf or ebx,edi
1: kd> p
nt!MiCompleteProtoPteFault+0x4f5:
80a88659 837dec00 cmp dword ptr [ebp-14h],0
1: kd> r
eax=00000121 ebx=0a0ee921
MI_WRITE_VALID_PTE (PointerPte, TempPte);
1: kd> dd 0xc0304200
c0304200 00027400 00027402 00027404 00027406
c0304210 00027408 0002740a 0002740c 0002740e
c0304220 00027410 00027412 00027414 00027416
改为
1: kd> dd 0xc0304200
c0304200 0a0ee921 00027402 00027404 00027406
c0304210 00027408 0002740a 0002740c 0002740e
c0304220 00027410 00027412 00027414 00027416
1: kd> p
nt!MiCompleteProtoPteFault+0x60f:
80a88773 8918 mov dword ptr [eax],ebx
1: kd> r
eax=c0304200 ebx=0a0ee921
1: kd> dd 0xc0304200
c0304200 0a0ee921 00027402 00027404 00027406
c0304210 00027408 0002740a 0002740c 0002740e
c0304220 00027410 00027412 00027414 00027416
1: kd> !pte c1080000
VA c1080000
PDE at C0300C10 PTE at C0304200
contains 0A03F963 contains 0A0EE921
pfn a03f -G-DA--KWEV pfn a0ee -G--A--KREV
第十四部分:
WorkingSetIndex = MiAddValidPageToWorkingSet (FaultingAddress,
PointerPte,
Pfn1,
(ULONG) ProtoProtect.u1.Long);
1: kd> x nt!MmSystemCacheWs
80bf03c0 nt!MmSystemCacheWs = struct _MMSUPPORT
1: kd> dx -r1 (*((ntkrnlmp!_MMSUPPORT *)0x80bf03c0))
(*((ntkrnlmp!_MMSUPPORT *)0x80bf03c0)) [Type: _MMSUPPORT]
[+0x000] WorkingSetExpansionLinks [Type: _LIST_ENTRY]
[+0x008] LastTrimTime : {0} [Type: _LARGE_INTEGER]
[+0x010] Flags [Type: _MMSUPPORT_FLAGS]
[+0x014] PageFaultCount : 0x378 [Type: unsigned long]
[+0x018] PeakWorkingSetSize : 0x342 [Type: unsigned long]
[+0x01c] GrowthSinceLastEstimate : 0x378 [Type: unsigned long]
[+0x020] MinimumWorkingSetSize : 0x3f1 [Type: unsigned long]
[+0x024] MaximumWorkingSetSize : 0x20000 [Type: unsigned long]
[+0x028] VmWorkingSetList : 0xc0c00000 [Type: _MMWSL *]
[+0x02c] Claim : 0x0 [Type: unsigned long]
[+0x030] NextEstimationSlot : 0x0 [Type: unsigned long]
[+0x034] NextAgingSlot : 0x0 [Type: unsigned long]
[+0x038] EstimatedAvailable : 0x0 [Type: unsigned long]
[+0x03c] WorkingSetSize : 0x342 [Type: unsigned long]
[+0x040] WorkingSetMutex [Type: _KGUARDED_MUTEX]
1: kd> dx -r1 ((ntkrnlmp!_MMWSL *)0xc0c00000)
((ntkrnlmp!_MMWSL *)0xc0c00000) : 0xc0c00000 [Type: _MMWSL *]
[+0x000] FirstFree : 0x343 [Type: unsigned long]
[+0x004] FirstDynamic : 0x1 [Type: unsigned long]
[+0x008] LastEntry : 0x3f1 [Type: unsigned long]
[+0x00c] NextSlot : 0x1 [Type: unsigned long]
[+0x010] Wsle : 0xc0c00038 [Type: _MMWSLE *]
[+0x014] LastInitializedWsle : 0x3f1 [Type: unsigned long]
[+0x018] NonDirectCount : 0x1d [Type: unsigned long]
[+0x01c] HashTable : 0x0 [Type: _MMWSLE_HASH *]
[+0x020] HashTableSize : 0x0 [Type: unsigned long]
[+0x024] NumberOfCommittedPageTables : 0x0 [Type: unsigned long]
[+0x028] HashTableStart : 0xc0df1000 [Type: void *]
[+0x02c] HighestPermittedHashAddress : 0xc1000000 [Type: void *]
[+0x030] NumberOfImageWaiters : 0x0 [Type: unsigned long]
[+0x034] VadBitMapHint : 0x0 [Type: unsigned long]
[+0x038] UsedPageTableEntries [Type: unsigned short [768]]
[+0x638] CommittedPageTables [Type: unsigned long [24]]
结果:
Wsle[WorkingSetIndex] = WsleContents;
1: kd> dd 0xc0c00038+343*4
c0c00d44 c1080201 00003450 00003460 00003470
c0c00d54 00003480 00003490 000034a0 000034b0
if (WsleMask != 0) {
Wsle[WorkingSetIndex].u1.Long |= WsleMask;
}
1: kd> dd 0xc0c00038+343*4
c0c00d44 c1080331 00003450 00003460 00003470
c0c00d54 00003480 00003490 000034a0 000034b0
c0c00d64 000034c0 000034d0 000034e0 000034f0
c0c00d74 00003500 00003510 00003520 00003530
第十五部分:最终结果0xc0304200和e1009c00地址处的内容都修改为0a0ee921
1: kd> dd 0xc0304200
c0304200 0a0ee921 00027402 00027404 00027406
c0304210 00027408 0002740a 0002740c 0002740e
c0304220 00027410 00027412 00027414 00027416
c0304230 00027418 0002741a 0002741c 0002741e
c0304240 00027420 00027422 00027424 00027426
c0304250 00027428 0002742a 0002742c 0002742e
c0304260 00027430 00027432 00027434 00027436
c0304270 00027438 0002743a 0002743c 0002743e
1: kd> dd e1009c00
e1009c00 0a0ee921 fcf194c6 fcf194c6 fcf194c6
e1009c10 fcf194c6 fcf194c6 fcf194c6 fcf194c6