MmProbeAndLockPages() failed while coding windows driver - windows

I am coding a windows driver.
I try to probes a Virtual Memory Page using MmProbeAndLockPages() https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-mmprobeandlockpages
First I allocate the MDL using IoAllocateMdl(). Then I probes the virtual memory page. The code is like :
PMDL pMdl = IoAllocateMdl(Dest, (ULONG)Size, FALSE, FALSE, NULL);
if (pMdl) {
__try {
MmProbeAndLockPages(pMdl, KernelMode, IoModifyAccess);
MmUnlockPages(pMdl);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
IoFreeMdl(pMdl);
}
I also tried to attach to the process using KeStackAttachProcess() but it has no effect.
The Dest variable is a PVOID to a userland process' address. The address is valid because I can read from it.
Do you have an idea why MmProbeAndLockPages() failed and my code goes into the except branch?
The exception code is 0xC0000005 (which is an access violation) but I specified IoModifyAccess/IoWriteAccess and I should be able to write to a userland process from kernelland, right?
Even when I unset the WP bit of cr0, it doesn't work ... hum something weird is happening
I am using a windows 10.0.19044
Thanks
regards

I have to change IoModifyAccess to IoReadAccess.
Then to call MmProtectMdlSystemAddress() with PAGE_READWRITE.

Related

Injecting a DLL from LoadImageNotifyRoutine, hangs on ZwMapViewOfSection

So I'm making a crackme and one of the parts is to hook a certain function and wait for a certain combination a params to happen, then the challenge is done.
For that, I'm creating a driver to inject a DLL into processes that have a specific DLL and hook a certain function.
I'm doing it by
Getting a handle for the DLL to inject
ZwCreateFile(
&DeviceExtension->HookDllHandle,
GENERIC_ALL,
&Attributes,
&StatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
)
Then, registering a LoadImageNotifyRoutine inside driver main
PsSetLoadImageNotifyRoutine(ImageCBK);
What's supposed to happen:
I check the if the needed DLL (that will export my function) is loaded.
By being inside the context of the process that invoked the callback, I create a section with ZwCreateSection, then map the dll into that section and call the DLL's entry point by creating a new thread.
After that, the hooking should be no problem.
Even though the IRQL for ZwCreateSection and ZwMapViewOfSection allows their use inside a notify routine, still ZwMapViewOfSection hangs every time I try to use it.
I've been using some code from Beholder
status = ObOpenObjectByPointer(PsGetCurrentProcess(), OBJ_KERNEL_HANDLE, NULL, STANDARD_RIGHTS_ALL, NULL, KernelMode, &ProcessHandle);
if (!NT_SUCCESS(status))
{
DbgPrint("Unable to get process handle\n");
return STATUS_SEVERITY_ERROR;
}
// Create a new section for DLL mapping
InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateSection(&DllSectionHandle, SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_QUERY, &Attributes, NULL, PAGE_EXECUTE_READ, SEC_IMAGE, DeviceExtension->HookDllHandle);
if (!NT_SUCCESS(status))
{
ZwClose(ProcessHandle);
DbgPrint("Section creation failed %08X\n", status);
return status;
}
DbgPrint("Section created %08X\n", DllSectionHandle);
// Map DLL on the section
status = ZwMapViewOfSection(DllSectionHandle, ProcessHandle, &DllBaseAddress, 0, 0, NULL, &DllViewSize, ViewUnmap, 0, PAGE_EXECUTE_READ);
if (!NT_SUCCESS(status))
{
ZwClose(ProcessHandle);
ZwClose(DllSectionHandle);
DbgPrint("Unable to map section %08X\n", status);
return status;
}
DbgPrint("Mapped DLL: %08X\n", DllBaseAddress);
Sadly, it never shows the last DbgPrint with the DllBaseAddress
simply read documentation
The operating system calls the driver's load-image notify routine at
PASSIVE_LEVEL inside a critical region with normal kernel APCs always
disabled
and
To avoid deadlocks, load-image notify routines must not call system
routines that map, allocate, query, free, or perform other operations
on user-space virtual memory.
you ignore this and call routine ZwMapViewOfSection that map. and got deadlock
solution is simply and elegant - insert normal kernel mode APC to current thread inside ImageCBK. because this APC is disabled here - it executed already after you return from ImageCBK -just system exit from critical region and enable APC. at this point your apc KernelRoutine/NormalRoutine will be called. and exactly inside NormalRoutine you must map

Windows crash in ChangeServiceConfig2

I'm having a problem with ChangeServiceConfig2(...SERVICE_CONFIG_TRIGGER_INFO...)
Relevant code:
WCHAR test[] = L"TEST12";
SERVICE_TRIGGER_SPECIFIC_DATA_ITEM stdata {
SERVICE_TRIGGER_DATA_TYPE_STRING,
wcslen(test)*sizeof(WCHAR),
reinterpret_cast<BYTE*>(test)
};
SERVICE_TRIGGER st {
SERVICE_TRIGGER_TYPE_NETWORK_ENDPOINT,
SERVICE_TRIGGER_ACTION_SERVICE_START,
const_cast<GUID*>(&NAMED_PIPE_EVENT_GUID),
1, &stdata
};
ChangeServiceConfig2(Service, SERVICE_CONFIG_TRIGGER_INFO, &st);
This causes an Access Violation on address 00000009, so clearly an unchecked null pointer. And it's not a null pointer in st or stdata. The address 00000009 does not depend on the length of test[].
Stack dump:
rpcrt4.dll!NdrpEmbeddedRepeatPointerBufferSize()
rpcrt4.dll!NdrConformantArrayBufferSize()
rpcrt4.dll!NdrSimpleStructBufferSize()
rpcrt4.dll!NdrpUnionBufferSize()
rpcrt4.dll!_NdrNonEncapsulatedUnionBufferSize#12()
rpcrt4.dll!NdrComplexStructBufferSize()
rpcrt4.dll!NdrClientCall2() rpcrt4.dll!_NdrClientCall4()
sechost.dll!ChangeServiceConfig2W()
The Service member is not the problem, or ChangeServiceConfig2 itself: I can set the service description via ChangeServiceConfig2(Service, SERVICE_CONFIG_DESCRIPTION, &desc);. The problem appears to be in the parsing of SERVICE_TRIGGER. Named Pipe service triggers apparently work for the Remote Registry service, so it's not fundamentally broken.
Q: which part of my SERVICE_TRIGGER is wrong?
Obviously there is at least one bug in Windows; at the very least it fails in parameter validation.
The SERVICE_TRIGGER object is correct, but ChangeServiceConfig2 wants a SERVICE_TRIGGER_INFO. Simple solution: wrap st using SERVICE_TRIGGER_INFO sti{ 1, &st, NULL };

blk_cleanup_queue() doesn't return on block device deregistration

I'm writing a block device driver for a hot-pluggable PCI memory device on 2.6.43.2-6.fc15 (so LDD3 is out of date with respect to a lot of functions) and I'm having trouble getting the block device de-registration to go smoothly. When the device is removed, I go to tear down the gendisk and request_queue, but it hangs on blk_cleanup_queue(). Presumably there's some queue-related process I have neglected to carry out before that, but I can't see any major consistent differences with other block drivers from that kernel tree that i am using for reference (memstick, cciss, etc). What are the steps I should carry out before going to tidy up the queue and gendisk?
I am implementing .open, .release, .ioctl in the block_ops as well as a mydev_request(struct request_queue *q) attached with blk_init_queue(mydev_request, &mydev->lock), but I'm not sure exactly how to tidy the queue either when requests occur or when de-registering the block device.
This is caused by not ending the requests that you fetch off the queue. To fix it, end the request as follows:
while ((req = blk_fetch_request(q)) != NULL )
{
res = mydev_submit_request_sg(mydev, req);
if (res)
__blk_end_request_all(req, res);
else
__blk_end_request_cur (req, res);
}

What is Target Device of IOCTL_USB_GET_ROOT_HUB_NAME (USB driver specific IOCTL IRQ)

I am a bit confused by the USB IOCTL IOCTL_USB_GET_ROOT_HUB_NAME. What is the target device of it? Although the MSDN WDK doc clearly indicates the target device, I am still confused by the USBVIEW sample provided by the WDK. The reason I'm confused is as follows:
I am new to kernel mode and USB driver writing in Windows and is now studying the USBVIEW sample from the windows driver kit http://msdn.microsoft.com/en-us/library/ff558728(v=vs.85).aspx. The MSDN describes the first step the USBVIEW sample performs as:
Enumerate host controllers and root
hubs. Host controllers have symbolic
link names of the form "HCDx", where x
starts at 0.
Use CreateFile() to open each host
controller symbolic link.
Create a node in the tree view to
represent each host controller.
After a host controller has been
opened, send the host controller an
IOCTL_USB_GET_ROOT_HUB_NAME request to
get the symbolic link name of the root
hub that is part of the host
controller
But, I double checked the usage of IOCTL_USB_GET_ROOT_HUB_NAME in MSDN http://msdn.microsoft.com/en-us/library/ff537326(v=VS.85).aspx
which says:
IOCTL_USB_GET_ROOT_HUB_NAME is a
user-mode I/O control request. This
request targets the USB hub FDO.
Note that the target of the IOCTL_USB_GET_ROOT_HUB_NAME IRP is a USB Hub FDO. However, as described by the USBVIEW sample, we just retreived the host controller symbolic link which means the device object is a host controller device object. How could we send it a IOCTL_USB_GET_ROOT_HUB_NAME IRP? Should we retreive a USB hub FDO somehow first?
I would guess it's an unfortunate copy-paste error. IOCTL_USB_GET_ROOT_HUB_NAME is indeed sent to the host controller and therefore handled by the USB Host Controller FDO.
By the way, just to put you in context:
The term "FDO" only loosely concerns user mode -- it's not like you can access any other "xDO" anyway. If you were to send this IOCTL in kernel mode, then sure, you can send an IOCTL to any specific device object in the device stack ("can" doesn't mean "should", mind you). However, a DeviceIoControl from a user mode application always sends IOCTLs to the top of the device stack (therefore it passes all the filters, the FDO and down to the PDO).
This question was asked on March 28, so I really hope you've solved it by now :)
As the documentation states you will need a handle to the USB host controller but it is not very clear on how you are supposed to get such a handle. In USBView something similar to this function is used to get the device path name by passing GUID_DEVINTERFACE_USB_HOST_CONTROLLER (include initguid.h and usbiodef.h):
vector<wstring> EnumDevices(
_In_ const GUID Guid
)
{
vector<wstring> r;
int index = 0;
HDEVINFO hDevInfo = SetupDiGetClassDevs(&Guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVINFO_DATA DevInfoData;
memset(&DevInfoData, 0, sizeof(SP_DEVINFO_DATA));
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
while (SetupDiEnumDeviceInfo(hDevInfo, index, &DevInfoData)) {
index++;
int jndex = 0;
SP_DEVICE_INTERFACE_DATA DevIntData;
memset(&DevIntData, 0, sizeof(SP_DEVICE_INTERFACE_DATA));
DevIntData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
while (SetupDiEnumDeviceInterfaces(
hDevInfo,
&DevInfoData, &Guid, jndex, &DevIntData
)) {
jndex++;
// Get the size required for the structure.
DWORD RequiredSize;
SetupDiGetDeviceInterfaceDetail(
hDevInfo, &DevIntData, NULL, NULL, &RequiredSize, NULL
);
PSP_DEVICE_INTERFACE_DETAIL_DATA pDevIntDetData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + RequiredSize
);
memset(pDevIntDetData, 0, sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + RequiredSize);
pDevIntDetData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
SetupDiGetDeviceInterfaceDetail(
hDevInfo,
&DevIntData,
pDevIntDetData, RequiredSize,
NULL,
&DevInfoData
);
r.push_back(wstring(pDevIntDetData->DevicePath));
free(pDevIntDetData);
}
}
return r;
}
Keep in mind using the above function you can also request devices of type GUID_DEVINTERFACE_USB_HUB and GUID_DEVINTERFACE_USB_DEVICE which may eliminate any need to interact with the host controller or hubs directly.

What could cause "The MDL is being inserted twice on the same process list"?

We are developing an NDIS protocol and miniport driver. When the driver is in-use and the system hibernates we get a bug check (blue screen) with the following error:
LOCKED_PAGES_TRACKER_CORRUPTION (d9)
Arguments:
Arg1: 00000001, The MDL is being inserted twice on the same process list.
Arg2: 875da420, Address of internal lock tracking structure.
Arg3: 87785728, Address of memory descriptor list.
Arg4: 00000013, Number of pages locked for the current process.
The stack trace is not especially helpful as our driver does not appear in the listing:
nt!RtlpBreakWithStatusInstruction
nt!KiBugCheckDebugBreak+0x19
nt!KeBugCheck2+0x574
nt!KeBugCheckEx+0x1b
nt!MiAddMdlTracker+0xd8
nt!MmProbeAndLockPages+0x629
nt!NtWriteFile+0x55c
nt!KiFastCallEntry+0xfc
ntdll!KiFastSystemCallRet
ntdll!ZwWriteFile+0xc
kernel32!WriteFile+0xa9
What types of issues could cause this MDL error?
It turns out the problem was related to this code in our IRP_MJ_WRITE handler:
/* If not in D0 state, don't attempt transmits */
if (ndisProtocolOpenContext &&
ndisProtocolOpenContext->powerState > NetDeviceStateD0)
{
DEBUG_PRINT(("NPD: system in sleep mode, so no TX\n"));
return STATUS_UNSUCCESSFUL;
}
This meant that we weren't fully completing the IRP and NDIS was likely doing something funny as a result. The addition of a call to IoCompleteRequest fixed the issue.
/* If not in D0 state, don't attempt transmits */
if (ndisProtocolOpenContext &&
ndisProtocolOpenContext->powerState > NetDeviceStateD0)
{
DEBUG_PRINT(("NPD: system in sleep mode, so no TX\n"));
pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}

Resources