⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tdi_fw.c

📁 基于TDI驱动编写的个人防火墙程序。包括驱动模块、应用层规则配置及加载模块。
💻 C
📖 第 1 页 / 共 2 页
字号:
						g_tdi_ioctls[i].desc,
						irps->MinorFunction,
						irps->FileObject));
#endif

					if (g_tdi_ioctls[i].fn == NULL) {
						// send IRP to original driver
						status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW,
							NULL, NULL);
						break;
					}

					// call dispatch function

					result = g_tdi_ioctls[i].fn(irp, irps, &completion);

					// complete request
					status = tdi_dispatch_complete(DeviceObject, irp, result,
						completion.routine, completion.context);

					break;
				}
	
			// if dispatch function hasn't been found
			if (g_tdi_ioctls[i].MinorFunction == 0) {
				// send IRP to original driver
				status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);
			}

			break;
		}

		case IRP_MJ_CLEANUP:		/* cleanup fileobject */

			result = tdi_cleanup(irp, irps, &completion);

			status = tdi_dispatch_complete(DeviceObject, irp, result,
				completion.routine, completion.context);
			break;

		case IRP_MJ_CLOSE:
			KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_CLOSE fileobj 0x%x\n", irps->FileObject));

			// passthrough IRP
			status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW,
				completion.routine, completion.context);

			break;

		default:
			KdPrint(("[tdi_fw] DeviceDispatch: major 0x%x, minor 0x%x for 0x%x\n",
				irps->MajorFunction, irps->MinorFunction, irps->FileObject));

			// passthrough IRP
			status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW,
				completion.routine, completion.context);
		}

	} else if (DeviceObject == g_devcontrol) {

		/*
		 * this IRP is for control object
		 */

		// set default status
		status = STATUS_SUCCESS;

		if (irps->MajorFunction == IRP_MJ_CREATE) {

			// initialize for user-mode part (exclusive access - 1 user-mode part)
			filter_init_2();

			g_got_control = (ULONG)PsGetCurrentProcessId();

		} else if (irps->MajorFunction == IRP_MJ_CLOSE) {

			// cleanup for user-mode part
			filter_free_2();

			g_got_control = 0;

		} if (irps->MajorFunction == IRP_MJ_DEVICE_CONTROL) {

			/*
			 * control request
			 */

			ULONG ioctl = irps->Parameters.DeviceIoControl.IoControlCode,
				len = irps->Parameters.DeviceIoControl.InputBufferLength,
				size = irps->Parameters.DeviceIoControl.OutputBufferLength;
			char *out_buf;

			if (IOCTL_TRANSFER_TYPE(ioctl) == METHOD_NEITHER) {
				// this type of transfer unsupported
				out_buf = NULL;
			} else
				out_buf = (char *)irp->AssociatedIrp.SystemBuffer;

			// process control request
			status = process_request(ioctl, out_buf, &len, size);

			irp->IoStatus.Information = len;

		} else
			status = STATUS_SUCCESS;

		irp->IoStatus.Status = status;

		IoCompleteRequest(irp, IO_NO_INCREMENT);

	} else {

		KdPrint(("[tdi_fw] DeviceDispatch: ioctl for unknown DeviceObject 0x%x\n", DeviceObject));

#ifndef USE_TDI_HOOKING
		// ??? just complete IRP
		status = irp->IoStatus.Status = STATUS_SUCCESS;
		IoCompleteRequest(irp, IO_NO_INCREMENT);
#else
		// call original handler
		status = g_old_DriverObject.MajorFunction[irps->MajorFunction](
			DeviceObject, irp);
#endif
	}

	return status;
}

/*
 * Dispatch routines call this function to complete their processing.
 * They _MUST_ call this function anyway.
 */
NTSTATUS
tdi_dispatch_complete(PDEVICE_OBJECT devobj, PIRP irp, int filter,
					  PIO_COMPLETION_ROUTINE cr, PVOID context)
{
	PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp);
	NTSTATUS status;

	if (filter == FILTER_DENY) {
		
		/*
		 * DENY: complete request with status "Access violation"
		 */

		KdPrint(("[tdi_fw] tdi_dispatch_complete: [DROP!]"
			" major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n",
			irps->MajorFunction,
			irps->MinorFunction,
			devobj,
			irps->FileObject));

		status = irp->IoStatus.Status = STATUS_ACCESS_VIOLATION;
		IoCompleteRequest (irp, IO_NO_INCREMENT);
		
	} else if (filter == FILTER_ALLOW) {

		/*
		 * ALLOW: pass IRP to the next driver
		 */

#ifndef USE_TDI_HOOKING

		PDEVICE_OBJECT old_devobj = get_original_devobj(devobj, NULL);

		if (old_devobj == NULL) {
			KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: Unknown DeviceObject 0x%x!\n", devobj));
	
			status = irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
			IoCompleteRequest (irp, IO_NO_INCREMENT);
			
			return status;
		}

#endif

		KdPrint(("[tdi_fw] tdi_dispatch_complete: [ALLOW.]"
			" major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n",
			irps->MajorFunction,
			irps->MinorFunction,
			devobj,
			irps->FileObject));

#ifndef USE_TDI_HOOKING

		if (cr == NULL || irp->CurrentLocation <= 1) {
			/*
			 * we use _THIS_ way of sending IRP to old driver
			 * a) to avoid NO_MORE_STACK_LOCATIONS
			 * b) and if we haven't our completions - no need to copy stack locations!
			 */

			// stay on this location after IoCallDriver
			IoSkipCurrentIrpStackLocation(irp);

#endif

			if (cr != NULL) {
				/*
				 * set completion routine (this way is slow)
				 */

				// save old completion routine and context
				TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)malloc_np(sizeof(*ctx));
				if (ctx == NULL) {
					KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: malloc_np\n"));
					
					status = irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
					IoCompleteRequest(irp, IO_NO_INCREMENT);
					
					return status;
				}

				ctx->old_cr = irps->CompletionRoutine;
				ctx->old_context = irps->Context;
				ctx->new_cr = cr;
				ctx->new_context = context;
				ctx->fileobj = irps->FileObject;
				ctx->new_devobj = devobj;
				ctx->old_control = IoGetNextIrpStackLocation(irp)->Control;

#ifndef USE_TDI_HOOKING
				IoSetCompletionRoutine(irp, tdi_skip_complete, ctx, TRUE, TRUE, TRUE);
#else
				// set completion for current irps
				irps->CompletionRoutine = tdi_skip_complete;
				irps->Context = ctx;
				irps->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
#endif
			}

#ifndef USE_TDI_HOOKING			
		} else {
			PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp),
				next_irps = IoGetNextIrpStackLocation(irp);
			
			memcpy(next_irps, irps, sizeof(*irps));

			if (cr != NULL) {
				/*
				 * this way for completion is more quicker then used above
				 */

				IoSetCompletionRoutine(irp, cr, context, TRUE, TRUE, TRUE);
			} else
				IoSetCompletionRoutine(irp, tdi_generic_complete, NULL, TRUE, TRUE, TRUE);
		}
#endif

		/* call original driver */

#ifndef USE_TDI_HOOKING
		status = IoCallDriver(old_devobj, irp);
#else
		status = g_old_DriverObject.MajorFunction[irps->MajorFunction](devobj, irp);
#endif

	} else {	/* FILTER_UNKNOWN */

		/*
		 * UNKNOWN: just complete the request
		 */

		status = irp->IoStatus.Status = STATUS_SUCCESS;	// ???
		IoCompleteRequest (irp, IO_NO_INCREMENT);
	}

	return status;
}

/*
 * completion routine for case if we use IoSkipCurrentIrpStackLocation way
 * or we USE_TDI_HOOKING
 */
NTSTATUS
tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
	TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)Context;
	NTSTATUS status;
	PIO_STACK_LOCATION irps;

	if (Irp->IoStatus.Status != STATUS_SUCCESS)
		KdPrint(("[tdi_fw] tdi_skip_complete: status 0x%x\n", Irp->IoStatus.Status));

	// restore IRP for using in our completion

	Irp->CurrentLocation--;
	Irp->Tail.Overlay.CurrentStackLocation--;

	irps = IoGetCurrentIrpStackLocation(Irp);

	KdPrint(("[tdi_fw] tdi_skip_complete: DeviceObject = 0x%x; FileObject = 0x%x\n",
		DeviceObject, irps->FileObject));

	DeviceObject = irps->DeviceObject;

	if (ctx->new_cr != NULL) {
		// restore fileobject (it's NULL)
		irps->FileObject = ctx->fileobj;
		// set new device object in irps
		irps->DeviceObject = ctx->new_devobj;
		
		// call new completion 
		status = ctx->new_cr(ctx->new_devobj, Irp, ctx->new_context);

	} else
		status = STATUS_SUCCESS;

	/* patch IRP back */

	// restore routine and context
	irps->CompletionRoutine = ctx->old_cr;
	irps->Context = ctx->old_context;

	// restore device object
	irps->DeviceObject = DeviceObject;

	Irp->CurrentLocation++;
	Irp->Tail.Overlay.CurrentStackLocation++;

	if (ctx->old_cr != NULL) {

		if (status != STATUS_MORE_PROCESSING_REQUIRED) {
			// call old completion (see the old control)
			BOOLEAN b_call = FALSE;

			if (Irp->Cancel) {
				// cancel
				if (ctx->old_control & SL_INVOKE_ON_CANCEL)
					b_call = TRUE;
			} else {
				if (Irp->IoStatus.Status >= STATUS_SUCCESS) {
					// success
					if (ctx->old_control & SL_INVOKE_ON_SUCCESS)
						b_call = TRUE;
				} else {
					// error
					if (ctx->old_control & SL_INVOKE_ON_ERROR)
						b_call = TRUE;
				}
			}

			if (b_call)
				status = ctx->old_cr(DeviceObject, Irp, ctx->old_context);
		
		} else {

			/*
			 * patch IRP to set IoManager to call completion next time
			 */

			// restore Control
			irps->Control = ctx->old_control;

		}
	}

	free(ctx);

	return status;
}


/* get original device object by filtered */
PDEVICE_OBJECT
get_original_devobj(PDEVICE_OBJECT flt_devobj, int *proto)
{
#ifndef USE_TDI_HOOKING
	PDEVICE_OBJECT result;
	int ipproto;

	if (flt_devobj == g_tcpfltobj) {
		result = g_tcpoldobj;
		ipproto = IPPROTO_TCP;
	} else if (flt_devobj == g_udpfltobj) {
		result = g_udpoldobj;
		ipproto = IPPROTO_UDP;
	} else if (flt_devobj == g_ipfltobj) {
		result = g_ipoldobj;
		ipproto = IPPROTO_IP;
	} else {
		KdPrint(("[tdi_fw] get_original_devobj: Unknown DeviceObject 0x%x!\n",
			flt_devobj));
		result = NULL;
	}

	if (result != NULL && proto != NULL)
		*proto = ipproto;

	return result;

#else	/* USE_TDI_HOOKING */

	// just stub for original devobj; return proto by devobj
	int ipproto;

	if (flt_devobj == g_tcpfltobj)
		ipproto = IPPROTO_TCP;
	else if (flt_devobj == g_udpfltobj)
		ipproto = IPPROTO_UDP;
	else if (flt_devobj == g_ipfltobj)
		ipproto = IPPROTO_IP;
	else {
		KdPrint(("[tdi_fw] get_original_devobj: Unknown DeviceObject 0x%x!\n",
			flt_devobj));
		return NULL;
	}

	if (proto != NULL)
		*proto = ipproto;

	return flt_devobj;

#endif
}

/*
 * Completion routines must call this function at the end of their execution
 */
NTSTATUS
tdi_generic_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
	KdPrint(("[tdi_fw] tdi_generic_complete: STATUS = 0x%x\n", Irp->IoStatus.Status));

	if (Irp->PendingReturned) {
		KdPrint(("[tdi_fw] tdi_generic_complete: PENDING\n"));
		IoMarkIrpPending(Irp);
	}

	return STATUS_SUCCESS;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -