📄 tdi_fw.c
字号:
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 device
*/
// set default status
status = STATUS_SUCCESS;
if (irps->MajorFunction == IRP_MJ_CREATE)
{
// initialize for user-mode part (exclusive access - 1 user-mode logging part)
filter_init_2();
g_got_log = TRUE;
}
else if (irps->MajorFunction == IRP_MJ_CLOSE)
{
// cleanup for user-mode logging part
filter_free_2();
g_got_log = FALSE;
}
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;
}
irp->IoStatus.Status = status;
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
else if (DeviceObject == g_devnfo)
{
/*
* this IRP is for information device
*/
// set default status
status = STATUS_SUCCESS;
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_nfo_request(ioctl, out_buf, &len, size);
irp->IoStatus.Information = len;
}
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));
if (irp->IoStatus.Status == STATUS_SUCCESS)
{
// change status
status = irp->IoStatus.Status = STATUS_ACCESS_DENIED;
}
else {
// set IRP status unchanged
status = irp->IoStatus.Status;
}
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 = irps->Control;
IoSetCompletionRoutine(irp, tdi_skip_complete, ctx, TRUE, TRUE, TRUE);
}
#ifndef USE_TDI_HOOKING
}
else {
PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp),
next_irps = IoGetNextIrpStackLocation(irp);
//memcpy(next_irps, irps, sizeof(*irps));
IoCopyCurrentIrpStackLocationToNext(irp);
if (cr != NULL)
{
/*
* this way for completion is more quicker than 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 (and even control!)
irps->CompletionRoutine = ctx->old_cr;
irps->Context = ctx->old_context;
irps->Control = ctx->old_control;
// 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));
ipproto = IPPROTO_IP; // what else?
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));
ipproto = IPPROTO_IP; // what else?
flt_devobj = 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;
}
/*
* for IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER
*/
NTSTATUS new_TCPSendData(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp)
{
struct completion completion;
int result;
KdPrint(("[tdi_fw] new_TCPSendData\n"));
#if 1
memset(&completion, 0, sizeof(completion));
result = tdi_send(Irp, IrpSp, &completion);
// complete request
return tdi_dispatch_complete(IrpSp->DeviceObject, Irp, result,
completion.routine, completion.context);
#else
return g_TCPSendData(Irp, IrpSp);
#endif
}
/*
* deny stub for dispatch table
*/
int tdi_deny_stub(PIRP irp, PIO_STACK_LOCATION irps, struct completion *completion)
{
KdPrint(("[tdi_fw] tdi_deny_stub!\n"));
return FILTER_DENY;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -