A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #30098  by pwnslinger
 Tue Mar 14, 2017 12:01 pm
Hi,

Everything goes well before I decided to change IoCallDriver name to NULL and set device interface for my device driver. nonetheless, when i set interface state in irp-mn_start-device routine in iocalldriver i encounter with this exception:

STACK_TEXT:
807ff710 82ab2703 807ffc80 82afaccd 00000000 nt!ExWorkerQueue+0x3e
807ff728 82a72d58 82b66d20 00000000 00000001 nt!KiExitDispatcher+0x17c
807ff748 82ac5883 82b66d20 00000000 82ba2e88 nt!KiInsertQueue+0xf6
807ff780 82a50133 8625a5e8 8625a6eb 8625a5e8 nt!KeReleaseSemaphore+0x83
807ff798 82ab3933 00000000 8625a5e8 009ea3b0 nt!PnpDeviceCompletionRoutine+0xc4
807ff7d4 8dd0ef85 8625a6c4 864af0e0 8625a5e8 nt!IopfCompleteRequest+0x128
807ff7fc 8dd05bf3 864af028 8625a5e8 8625a6e0 usbhub!UsbhFdoPnp_StartDevice+0x11d
807ff820 8dcfebab 864af028 8625a5e8 864af028 usbhub!UsbhFdoPnp+0x6f
807ff834 82a72593 864af028 8625a5e8 8625a704 usbhub!UsbhGenDispatch+0x63
807ff84c 8cc55116 8625a70c 8648f7e0 00000000 nt!IofCallDriver+0x63
807ff888 82a72593 8648f7e0 8625a5e8 807ff910 USBlocker!USBlockerPnP+0x166 [e:\soc_payampardaz\hids-driver\usblocker\usblocker\usblocker.cpp @ 964]
807ff8a0 82bfa6f8 00000000 86436028 869ea3b0 nt!IofCallDriver+0x63
807ff8bc 82a4d28b 807ff8ec 82a5006f 869ea3b0 nt!PnpAsynchronousCall+0x92
807ff920 82bf1561 82a5006f 869ea3b0 86490008 nt!PnpStartDevice+0xe1
807ff97c 82bf142a 869ea3b0 00000017 00000000 nt!PnpStartDeviceNode+0x12c
807ff998 82bf8e3d 00000000 00000000 00000000 nt!PipProcessStartPhase1+0x62
807ffb94 82bc4e0c 84fcfc00 863ead10 807ffbc8 nt!PipProcessDevNodeTree+0x188
807ffbd4 82a4fcfd 863ead10 82ba0ec0 84fda4c0 nt!PiProcessStartSystemDevices+0x6d
807ffc00 82ab8aab 00000000 00000000 84fda4c0 nt!PnpDeviceActionWorker+0x241
807ffc50 82c44f5e 00000001 f36d5488 00000000 nt!ExpWorkerThread+0x10d
807ffc90 82aec219 82ab899e 00000001 00000000 nt!PspSystemThreadStartup+0x9e
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19

I guess it's related with the way i manage remove locks. my code for is as follows:
Code: Select all
case IRP_MN_START_DEVICE:
		KdPrint(("%S: IRP_MJ_PNP (IRP_MN_START_DEVICE) IRQL: %d\n", DRV_NAME,KeGetCurrentIrql()));
		DbgPrint("%S: IRP_MJ_PNP (IRP_MN_START_DEVICE) IRQL: %d\n", DRV_NAME,KeGetCurrentIrql());

		//active device interface
		IoSetDeviceInterfaceState(&pdx->DeviceInterface, TRUE);

		DbgPrint("Symbolic Link Name is %T",&pdx->DeviceInterface);

		IoCopyCurrentIrpStackLocationToNext(Irp);
		IoSetCompletionRoutine(Irp,(PIO_COMPLETION_ROUTINE)startDeviceCompletionRoutine,(PVOID)&startDevice,TRUE,TRUE,TRUE);
		status = IoCallDriver(pdx->lowerDeviceObject,Irp);
	
		if(status==STATUS_PENDING)
		{
			KdPrint(("%S: waiting for lower-level driver to complete request.\n",DRV_NAME));
			//wait if status returned from lower-driver is pending	
			//wait more to event get completed
			KeWaitForSingleObject(&startDevice,Executive,KernelMode,FALSE,NULL);
			status=Irp->IoStatus.Status;
		}

		if(!NT_SUCCESS(status))
		{	
			KdPrint(("%S: Lower driver cannot process this IRP.\n",DRV_NAME));
			return status;
		}

		//status = getDeviceDescriptor(DeviceObject,Irp);
		//IoReleaseRemoveLock(&pdx->RemoveLock,Irp);
		return status;
also my completion routine is as follows:
Code: Select all
NTSTATUS startDeviceCompletionRoutine(IN PDEVICE_OBJECT fdio, IN PIRP Irp, IN KEVENT Context)
{
	KEVENT eventStart = (KEVENT)Context;
	ASSERT(eventStart);
	PUSBlocker_DEVICE_EXTENSION pdx = (PUSBlocker_DEVICE_EXTENSION)fdio->DeviceExtension;
	//NTSTATUS status=STATUS_SUCCESS;
	KIRQL irql = KeGetCurrentIrql();

	KdPrint(("%S: Entering completionRoutine with %d IRQL.\n", DRV_NAME,irql));
	DbgPrint("%S: Entering completionRoutine with %d IRQL.\n", DRV_NAME,irql);
	
	if(Irp->PendingReturned)
	{
		IoMarkIrpPending(Irp);
	}
	IoReleaseRemoveLock(&pdx->RemoveLock,Irp);
	return STATUS_SUCCESS;
	

}
 #30105  by Vrtule
 Tue Mar 14, 2017 8:40 pm
IRP_MN_START_DEVICE needs to be serviced from bottom to the top of the device stack. So, you should do this:

0) acquire the remove lock of your device,
1) register completion routine for the start IRP (IoCopyCurrentIrpStackLocationToNext, IoSetCompletionRoutine),
2) pass the IRP to the next lower driver (IoCallDriver),
3) if the lower driver returns STATUS_PENDING wait utnil the IRP is completed by it,
4) return STATUS_MORE_PROCESSING_REQUIRED from your completion routine (and possibly set the event object the dispatch routine is waiting for),
5) when the wait is complete, you can activate your device interface (in your dispatch routine),
6) complete the IRP (IoCompleteRequest),
7) release the remove lock,
8) return control to the next higher driver.
 #30166  by pwnslinger
 Sun Mar 26, 2017 8:14 pm
Thank you for your thoughtful and throughout comment. I did it like this:

in my dispatch routine I have this code for start device:
Code: Select all
status = IoAcquireRemoveLock(&pdx->RemoveLock,Irp);
	if(!NT_SUCCESS(status)) return CompleteRequest(Irp,status,0);

	//check for whether completion routine get completed or not
	KeInitializeEvent(&startDevice,NotificationEvent,FALSE);
	
	switch (irpSp->MinorFunction)
	{
	case IRP_MN_START_DEVICE:
		KdPrint(("%S: IRP_MJ_PNP (IRP_MN_START_DEVICE) IRQL: %d\n", DRV_NAME,KeGetCurrentIrql()));
		DbgPrint("%S: IRP_MJ_PNP (IRP_MN_START_DEVICE) IRQL: %d\n", DRV_NAME,KeGetCurrentIrql());

		IoCopyCurrentIrpStackLocationToNext(Irp);
		IoSetCompletionRoutine(Irp,(PIO_COMPLETION_ROUTINE)startDeviceCompletionRoutine,(PVOID)&startDevice,TRUE,TRUE,TRUE);
		status = IoCallDriver(pdx->lowerDeviceObject,Irp);
	
		if(status==STATUS_PENDING)
		{
			KdPrint(("%S: waiting for lower-level driver to complete request.\n",DRV_NAME));
			//wait if status returned from lower-driver is pending	
			//wait more to event get completed
			KeWaitForSingleObject(&startDevice,Executive,KernelMode,FALSE,NULL);
			//completion routine always reclaim IRP by returning STATUS_MORE_PROCESSING_REQUIRED by signaling to kernel event we set in completion routine
			status=Irp->IoStatus.Status;
		}

		if(!NT_SUCCESS(status))
		{	
			KdPrint(("%S: Lower driver cannot process this IRP.\n",DRV_NAME));
			return status;
		}

		Irp->IoStatus.Status=status;
		Irp->IoStatus.Information=0;
		IoSetDeviceInterfaceState(&pdx->DeviceInterface,TRUE);
		DbgPrint("Symbolic Link Name is %T",&pdx->DeviceInterface);
		IoCompleteRequest(Irp,IO_NO_INCREMENT); //should be called from dispatcher routine not from completion routine
		//status = getDeviceDescriptor(DeviceObject,Irp);
		IoReleaseRemoveLock(&pdx->RemoveLock,Irp);
		return status;
also here is my io completion routine:
Code: Select all
NTSTATUS startDeviceCompletionRoutine(IN PDEVICE_OBJECT fdio, IN PIRP Irp, IN PVOID Context)
{
	PKEVENT eventStart = (PKEVENT)Context;
	ASSERT(eventStart);
	//PUSBlocker_DEVICE_EXTENSION pdx = (PUSBlocker_DEVICE_EXTENSION)fdio->DeviceExtension;
	//NTSTATUS status=STATUS_SUCCESS;
	KIRQL irql = KeGetCurrentIrql();

	KdPrint(("%S: Entering completionRoutine with %d IRQL.\n", DRV_NAME,irql));
	DbgPrint("%S: Entering completionRoutine with %d IRQL.\n", DRV_NAME, (irql>0) ? PASSIVE_LEVEL : DISPATCH_LEVEL);
	
	if(Irp->PendingReturned)
	{
		//IoMarkIrpPending(Irp);
		KeSetEvent(eventStart,IO_NO_INCREMENT,FALSE); //set event in which dispatch routine is waiting for that
	}
	
	return STATUS_MORE_PROCESSING_REQUIRED;
}
nonetheless, I never return from completion routine.
 #30170  by Vrtule
 Mon Mar 27, 2017 10:26 am
Try setting the event object in your completion routine in all cases, not only when the Irp->PendingReturned is TRUE. It is true that your dispatch routine is not waiting for the event when the IRP is not marked as pending but setting the event also in that case does no harm. Actually, it may help in case a lower driver registered a completion routine and did not propagate the Irp->PendingReturned flag (that must be done if you register a completion routine and do not plan to make the IRP request synchronous... which you are exactly doing).

Also, activate your device interface only when the start device request is completed successfully by the lower driver.
 #30171  by pwnslinger
 Mon Mar 27, 2017 12:29 pm
I highly appreciate your help. Thank you i think the previous problem has successfully been addressed. however, final goal of my filter driver was to be able to detect when a usb_mass_storage class device plugged-in one of my usb hub interfaces and deny access to it. so, I make a callback for irp_mj_internal_device_control. nonetheless, i'm not able to monitor usb urb packets. actually, when i attach usb devices i will never enter to this callback.