My user mode program allocates memory for a communication struct UM_Msg
(which contains a data member like this : BYTE data[256];
) using the new
operator like this:
UM_Msg* ToDriver = new UM_Msg();
And then I copy it to a shared section between the driver and this program using RtlCopyMemory()
.
When the driver accesses any member from the struct except the data
buffer, nothing happens. When it accesses the data
buffer, a BSOD happens.
But, when I copy the data (from the driver with RtlCopyMemory()
) to that data
member of the struct, nothing happens.
I guess it's because the data
buffer still points to user mode memory which is paged and causes the BSOD when accessed from the driver? Even if that's true, I still don't understand. I thought RtlCopyMemory()
copies the content of the struct like what's inside the data
buffer and not a pointer to the user mode program heap?
I don't understand what's happening, please help.
EDIT:
I think the problem is from the MmCopyMemory()
function, which requires the target buffer that data will be copied to must be in non-pageable memory. The target buffer that I'm providing is the data
buffer from the UM_Msg
struct, but I copy that struct to the shared section, which should be non-paged, right?
Here is how I created it:
status = ZwCreateSection(&g_SectionHandle, SECTION_ALL_ACCESS, &OA, &MaxSize, // change to MmCreateSection - optional
PAGE_READWRITE,
SEC_COMMIT| SEC_NOCACHE,
NULL);
I even mapped the section with MmMapViewInSystemSpace()
.
Is my section created in non-paged memory?
user mode program :
VOID* read_address(PVOID addr, SIZE_T InSize)
{
auto msg = InitMsg(ToDriver);
msg->address = addr;
msg->opType = OPERATION_TYPE::OP_READ;
msg->dataSize = InSize;
if (read_view)
{
UnmapViewOfFile(read_view);
}
read_view = (UM_Msg*)MapViewOfFile(h_write, FILE_MAP_WRITE, 0, 0, DestSize);
if (read_view == NULL)
{
printf("[-] failed to get ViewBase: %X\n", GetLastError());
return NULL;
}
size_t len = sizeof(UM_Msg);
if (read_view != NULL && msg != NULL && len <= DestSize)
{
msg->ready = 0;
RtlCopyMemory(read_view, msg, len);
MemoryBarrier();
read_view->ready = 1;
}
else
{
printf("[-] didnt copy memory , conditions not verified\n");
return NULL;
}
UnmapViewOfFile(read_view);
do
{
if (read_view)
{
UnmapViewOfFile(read_view);
}
read_view = (UM_Msg*)MapViewOfFile(h_read, FILE_MAP_READ, 0, 0, DestSize);
if (read_view == NULL)
{
printf("[-] failed to get ReadMap: %X\n", GetLastError());
return NULL;
}
MemoryBarrier();
Sleep(10);
} while (read_view->magic != MAGIC || read_view->ready == 1);
return read_view->data;
}
UM_Msg* InitMsg(UM_Msg* msg)
{
msg->address = NULL;
RtlZeroMemory(msg->data, sizeof(msg->data));
msg->dataSize = 0;
return msg;
}
the structure allocated:
UM_Msg* ToDriver = new UM_Msg();
and the read function from the driver which reads physical address :
NTSTATUS ReadPhysicalAddress(PVOID TargetAddress, PVOID lpBuffer, SIZE_T Size, SIZE_T* BytesRead)
{
MM_COPY_ADDRESS AddrToRead = { 0 };
if (TargetAddress == NULL)
{
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL,
"[-] %s : TargetAddress is NULL\n",__FUNCTION__));
return STATUS_UNSUCCESSFUL;
}
AddrToRead.PhysicalAddress.QuadPart = (ULONGLONG)TargetAddress;
return MmCopyMemory(lpBuffer, AddrToRead, Size, MM_COPY_MEMORY_PHYSICAL, BytesRead);
}
PVOID lpBuffer
is where i pass the data buffer from the communication struct between the driver and the user mode program :
struct UM_Msg
{
ULONG ProcId;
PVOID address;
volatile LONG ready;
OPERATION_TYPE opType;
SIZE_T dataSize;
UINT32 magic = MAGIC;
BYTE data[256];
};
i hope this is enough clarification