A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #9955  by whitepanda
 Mon Nov 28, 2011 12:34 pm
hello,

i'm trying to read kernelmemory and as i'm aware of windows memory management and paging im using the following code to access the memory in a safe manner:
Code: Select all
NTSTATUS ReadKernelMemory(LPVOID address, DWORD Size, LPVOID lpOutBuffer, DWORD* lpBytesWritten)
{
	NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
	
	if(MmIsAddressValid(address) && MmIsAddressValid(lpOutBuffer))
	{
		PMDL Model = IoAllocateMdl(address, Size, FALSE, FALSE, NULL);
		if(Model)
		{
			__try
			{
				MmProbeAndLockPages(Model, KernelMode, IoReadAccess);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				IoFreeMdl(Model);
				return NtStatus;
			}

			address = MmGetSystemAddressForMdlSafe(Model, NormalPagePriority);
			if(address)
			{
				RtlCopyMemory(lpOutBuffer, address, Size);
				*lpBytesWritten = Size;
				NtStatus = STATUS_SUCCESS;
			}

			MmUnlockPages(Model);
			IoFreeMdl(Model);
		}
	}
	
	return NtStatus;
}
using the function above on some drivers i get a pfn list corrupted bsod, however on most drivers it works.

bsod happens on MmUnlockPages(Model);

i already found a thread concerning this issue (http://forum.cheatengine.org/viewtopic. ... ac944c8871) but the provided "solution" isn't satisfying in my opinion.

whats wrong with my code?

best regards

whitepanda
 #10124  by EP_X0FF
 Sun Dec 04, 2011 1:49 am
Try googling eXtremeDumper plugin for PETools from Ms-Rem, it comes with full source code and does what you need.
 #10134  by whitepanda
 Sun Dec 04, 2011 8:28 pm
EP_X0FF wrote:Try googling eXtremeDumper plugin for PETools from Ms-Rem, it comes with full source code and does what you need.
thanks, that did the job :)

though i don't understand why it locks the destinationbuffer using MmProbeAndLockPages.

from my understanding its necessary to ensure the src buffer doesn't become invalid while reading and not the dest buffer?

for the src buffer he just uses IoAllocateMdl -> MmBuildMdlForNonPagedPool -> MmGetSystemAddressForMdlSafe

i have already read msdn/osr description of those apis/maros above but i'm still not sure how to use those apis properly :/
 #10138  by Dmitry Varshavsky
 Sun Dec 04, 2011 9:49 pm
whitepanda wrote: though i don't understand why it locks the destinationbuffer using MmProbeAndLockPages.
Can you show the part of the code?
To my mind this make sense if destinationbuffer is user-mode buffer, in this case MmProbeAndLockPages is the must.
 #10139  by whitepanda
 Sun Dec 04, 2011 10:13 pm
Code: Select all
NTSTATUS DumpKernelMemory(PDriverQuery Query)
{
	PMDL  pSrcMdl, pDstMdl;
	PUCHAR pAddress, pDstDddress;
	NTSTATUS st = STATUS_UNSUCCESSFUL;
	ULONG r;

	pSrcMdl = IoAllocateMdl((PVOID)Query->Param1, Query->Param2, FALSE, FALSE, NULL);

	if (pSrcMdl)
	{
		MmBuildMdlForNonPagedPool(pSrcMdl);

		pAddress = MmGetSystemAddressForMdlSafe(pSrcMdl, NormalPagePriority);

		if (pAddress)
		{
			pDstMdl = IoAllocateMdl((PVOID)Query->Param3, Query->Param2, FALSE, FALSE, NULL);

			if (pDstMdl)
			{
				__try
				{
					MmProbeAndLockPages(pDstMdl, UserMode, IoWriteAccess);

					pDstDddress = MmGetSystemAddressForMdlSafe(pDstMdl, NormalPagePriority);

					if (pDstDddress)
					{
						memset(pDstDddress, 0, Query->Param2);

						for (r = 1; r < Query->Param2; r++)
						{
							if (MmIsAddressValid(pAddress)) *pDstDddress = *pAddress;
							pAddress++;
							pDstDddress++;
						}

						st = STATUS_SUCCESS;
					}
					
					MmUnlockPages(pDstMdl);
				}

				__except(EXCEPTION_EXECUTE_HANDLER)
				{					
				}

				IoFreeMdl(pDstMdl);
			}
		}			

		IoFreeMdl(pSrcMdl);
	}

	return st;
}
you are right but my point is why the src isn't locked?memory can be paged out anytime, even when i raise irql to dispatch lvl its possible on smp systems,right?
 #10143  by Vrtule
 Mon Dec 05, 2011 10:05 am
Code: Select all
MmBuildMdlForNonPagedPool(pSrcMdl);
This call does not lock the memory described by the MDL in physical memory. The kernel assumes, that virtual addresses described by the MDL, reside in nonpaged memory. The routine only go through these addresses ("virtual pages") and writes their corresponding physical addresses to structure of the MDL.

So, after this call, the MDL describe range of virtual addresses together with their physical mappings. However, the described memory is not locked. If it is not actually nonpaged, it can be paged out and than paged in to different physical addresses. After this operation, which is invisible to your code, your MDL is not valid from the point of view of physical mappings.

Raising IRQL to DISPATCH_LEVEL does not lock down any memory range. It only prevents current processor form scheduling, waiting for devices (including hard disk) etc.
 #10148  by whitepanda
 Mon Dec 05, 2011 12:27 pm
thx for the explanation.

i still don't understand whats the benefit of


pSrcMdl = IoAllocateMdl((PVOID)Query->Param1, Query->Param2, FALSE, FALSE, NULL);

if (pSrcMdl)
{
MmBuildMdlForNonPagedPool(pSrcMdl);

over doing a simple memcpy()?

memory can be paged anytime since theres no lock, so theres no guarantee that memory stays accessible?
 #10198  by Vrtule
 Tue Dec 06, 2011 9:57 pm
memory can be paged anytime since theres no lock, so theres no guarantee that memory stays accessible?
If I am correct, MDLs do not guarantee anything. They are just a way of describing memory region, both virtual pages and corresponding physical frames. Some routines use them to identify a block of memory. For example, MmProbeAndLockPages reads part of the MDL that describe virtual memory region, finds correspoonding physical frames (and if some pages are not present in RAM, they are reloaded or an exception occurs) and locks them down. This menas that the system will not reuse these frames until MmUnlockPages is called (PFNs of the frames are written to the MDL, so there is no problem to find them when needed). However, MmProbeAndLockPages does not protect the virtual memory region in any way; it can be deleted, or its protection changed.

However, I saw that line with MmBuildMdlForNonPagedPool used on pageable memory that was not locked, multiple times. Maybe, the authors think that nothing happens during that short time interval they work with the MDL.