Author: Axt Müller
If you are engaged in Windows driver development for many years, I guess you have a nightmare: how to read an unknown address in an absolutely safe way. We all know that, it is useless to test the validity of the address by MmIsAddressValid, even if this function return TRUE, the address may still be invalid. Read address in SEH (I mean put "memcpy" in "try...except") is only valid for user-mode address, only if you read an invalid address of user-mode, you can catch an exception. Some guys on the internet said: you can use IoAllocateMdl, MmProbeAndLockPages and MmGetSystemAddressForMdlSafe to read any kernel address, but this method still crashes system when you read some invalid addresses. Doubt my word? You can write a program to read address from 0x80000000 to 0xFFFFFFFF (32-bit), or from 0xFFFFF800`00000000 to 0xFFFFFFFF`00000000 (64-bit), I think your system will crash in 2 minutes. This problem has plagued me for many years, but I already got 3 good solutions now, let me share to all of you.
On Windows 2000, Windows XP and Windows 2003, you can use NtSystemDebugControl to read any address without crashing system. Code show as below:
If you are engaged in Windows driver development for many years, I guess you have a nightmare: how to read an unknown address in an absolutely safe way. We all know that, it is useless to test the validity of the address by MmIsAddressValid, even if this function return TRUE, the address may still be invalid. Read address in SEH (I mean put "memcpy" in "try...except") is only valid for user-mode address, only if you read an invalid address of user-mode, you can catch an exception. Some guys on the internet said: you can use IoAllocateMdl, MmProbeAndLockPages and MmGetSystemAddressForMdlSafe to read any kernel address, but this method still crashes system when you read some invalid addresses. Doubt my word? You can write a program to read address from 0x80000000 to 0xFFFFFFFF (32-bit), or from 0xFFFFF800`00000000 to 0xFFFFFFFF`00000000 (64-bit), I think your system will crash in 2 minutes. This problem has plagued me for many years, but I already got 3 good solutions now, let me share to all of you.
On Windows 2000, Windows XP and Windows 2003, you can use NtSystemDebugControl to read any address without crashing system. Code show as below:
Code: Select all
But unfortunately, the above method is invalid since Windows Vista, So we need to use another method to read kernel memory after Windows Vista. We all knows that, we can get physical address of virtual address by MmGetPhysicalAddress, and we can map physical address by MmMapIoSpace. So the solution is clear now: get physical address of a virtual address, then map it to a new virtual address to read. Code show as below:typedef struct _MEMORY_CHUNKS
{
PVOID Address;
PVOID Data;
ULONG Length;
}MEMORY_CHUNKS, *PMEMORY_CHUNKS;
const ULONG SysDbgCopyMemoryChunks_0 = 8
typedef NTSTATUS (_stdcall *NTSYSTEMDEBUGCONTROL)
(
IN ULONG Command,
IN PVOID InputBuffer,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
OUT PULONG ReturnLength
);
NTSYSTEMDEBUGCONTROL ZwSystemDebugControl = FUNCTION_ADDRESS;
NTSTATUS SafeReadKrnlAddr(PVOID TargetAddress, PVOID AllocatedBuffer, ULONG LengthYouWantToRead)
{
MEMORY_CHUNKS mc;
mc.Address = TargetAddress;
mc.Length = LengthYouWantToRead;
mc.Data = AllocatedBuffer;
return ZwSystemDebugControl(SysDbgCopyMemoryChunks_0, &mc, sizeof(mc), NULL, 0, &NumberOfBytesRead);
}
Code: Select all
After Windows 8.1, Microsoft finally provided a function that can read kernel memory safely: MmCopyMemory. This function is easy to use, the only thing to note is that you must use NonPagedPool memory as the buffer address. Code show as below:BOOL SafeReadKrnlAddr(PVOID TargetAddress, PVOID AllocatedBuffer, ULONG LengthYouWantToRead)
{
BOOL b = FALSE;
PHYSICAL_ADDRESS PA;
PA = MmGetPhysicalAddress(TargetAddress);
if(PA.QuadPart)
{
NewVA = MmMapIoSpace(PA, LengthYouWantToRead, MmNonCached);
if(NewVA)
{
memcpy(AllocatedBuffer, NewVA, LengthYouWantToRead);
MmUnmapIoSpace(NewVA, LengthYouWantToRead);
b = TRUE;
}
}
return b;
}
Code: Select all
In my project Windows Kernel Explorer (https://github.com/AxtMueller/Windows-Kernel-Explorer), I used Method 2 and Method 3 to read kernel memory for scanning kernel mode hooks. You can use my tool to scan hooks and let me know if it will crash the system when scanning hooks.NTSTATUS SafeReadKrnlAddr(PVOID TargetAddress, PVOID AllocatedBuffer, ULONG LengthYouWantToRead)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID NonPagedBuffer = ExAllocatePool(NonPagedPool, LengthYouWantToRead);
if(NonPagedBuffer)
{
SIZE_T NumberOfBytesTransferred = 0;
MM_COPY_ADDRESS AddrToRead;
AddrToRead.VirtualAddress = TargetAddress;
status = MmCopyMemory(NonPagedBuffer, AddrToRead, LengthYouWantToRead, MM_COPY_MEMORY_VIRTUAL, &NumberOfBytesTransferred);
if(STATUS_SUCCESS == status)
{
memcpy(AllocatedBuffer, NonPagedBuffer, NumberOfBytesTransferred);
}
ExFreePool(NonPagedBuffer);
}
return status;
}