Hello all,
I posted here a few days ago asking for help with a TDI driver that would
let me observe all TCP/IP traffic on my system. Several people pointed
out that my initial approach – trying to register an event handler with
the lower level device – would not work, and suggested I go with a TDI
filter driver instead.
(I’ve also been advised to look into WinPcap or NetMon. But WinPcap is
too limited in that it can’t see localhost traffic, and NetMon doesn’t
give me the capability to manipulate traffic – something I’d like to look
into later. Also, before someone suggests that I buy the TDI samples from
PCAUSA, let me point out that I’m just doing this to learn more about Win2K
drivers, so it’s not something I really want to sink a lot of cash into.)
Anyway, based on those suggestions plus some other random postings, I
came up with the code at the end of this message. Right now it’s just a
passthrough – it intercepts all the IRPs for \Device\Tcp, prints out a
little message with DbgPrint(), and then passes the IRP down to the lower
level device.
This seems to work, sort of, in the sense that all networking-related
functionality is still intact. However, I notice that I don’t seem to be
intercepting ALL the traffic on the system. For example, when I upload or
download a huge file from somewhere, I expect to see a lot of TDI_SEND or
TDI_RECEIVE IRPs corresponding to the increase in traffic. With my driver
loaded, I don’t see any of that. I see a TDI_SEND or TDI_RECEIVE every
now and then but for the most part, those seem to be largely missing.
As an experiment, I compared the debug output of my driver side-by-side
with output from TDIMON (from SysInternals), and the IRPs that I do
intercept seem to be correct. I just seem to be missing a bunch of them.
I realize that I’m only hooking into TCP right now, but all my test
scenarios have been TCP-based traffic so that shouldn’t be a factor.
So, does anyone have some insight into this? It may have been discussed
here before, but I wasn’t able to find much in the archives.
One other question – is there a safe way to unload this type of driver?
I’m currently doing an IoDetachDevice() and IoDeleteDevice(), but soon
after unloading I get a BSOD (I think the message that comes up is IRQL_
NOT_LESS_OR_EQUAL or something like that). If I just start the driver
once and leave it running, it seems to be fine.
Thanks in advance for any suggestions.
-chris
— START CODE
#include “ntddk.h”
#include “tdikrnl.h”
#include “tdi_drv.h”
#define DEBUG 1
typedef struct _DEVICE_EXTENSION
{
// the top of the stack before this filter was added, a.k.a. the location
// to which all Irps should be directed
PDEVICE_OBJECT TopOfStack;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
// globals
PDEVICE_OBJECT ptcpfilterdevice;
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NTSTATUS status;
int i;
#if DEBUG
DbgPrint(“\n.\n.\nBeginning driver initialization\n”);
#endif
for (i=0; i<=IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = tdi_Dispatch;
DriverObject->DriverUnload = tdi_Unload;
status = tdi_InitializeAndAttach(DriverObject);
#if DEBUG
DbgPrint(“tdi_InitializeAndAttach() return code: %08X\n”, status);
#endif
return status;
}
NTSTATUS tdi_InitializeAndAttach(
IN PDRIVER_OBJECT DriverObject
)
{
NTSTATUS status;
PDEVICE_EXTENSION pdev_ext;
UNICODE_STRING u_name;
RtlInitUnicodeString(&u_name, L"\Device\Tcp");
// note: need same device type and characteristics as the thing we’re
// filtering.
// create the filter device
status = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
NULL, // no device name
FILE_DEVICE_NETWORK, // same as \Device\Tcp
FILE_DEVICE_SECURE_OPEN, // same as \Device\Tcp
FALSE, // non-exclusive
&ptcpfilterdevice);
#if DEBUG
DbgPrint(“IoCreateDevice() return code: %08X\n”, status);
DbgPrint(" ptcpfilterdevice: %08X\n", ptcpfilterdevice);
#endif
if (status) {
DbgPrint(“IoCreateDevice() failed\n”);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(ptcpfilterdevice->DeviceExtension, sizeof(DEVICE_EXTENSION));
pdev_ext = (PDEVICE_EXTENSION) ptcpfilterdevice->DeviceExtension;
// attach to the Tcp chain and put a pointer to \Device\Tcp in the device
// extension structure
status = IoAttachDevice(ptcpfilterdevice, &u_name, &pdev_ext->TopOfStack);
#if DEBUG
DbgPrint(“IoAttachDevice() return code: %08X\n”, status);
DbgPrint(" pdev_ext->TopOfStack = %08X\n", pdev_ext->TopOfStack);
#endif
if (status) {
DbgPrint(“IoAttachDevice() failed\n”);
IoDeleteDevice(ptcpfilterdevice);
return STATUS_INSUFFICIENT_RESOURCES;
}
return STATUS_SUCCESS;
}
VOID tdi_Unload(
IN PDRIVER_OBJECT DriverObject
)
{
#if DEBUG
DbgPrint(“Unloading driver\n”);
#endif
// detach from the Tcp chain
IoDetachDevice(((PDEVICE_EXTENSION)
ptcpfilterdevice->DeviceExtension)->TopOfStack);
// delete the filter device
IoDeleteDevice(ptcpfilterdevice);
}
NTSTATUS tdi_Dispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION pirp_stack;
pirp_stack = IoGetCurrentIrpStackLocation(Irp);
#if DEBUG
if (pirp_stack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)
DbgPrint(“tdi_Dispatch(): Passing %s->%s (major %02X, minor %02X)\n”,
XlatedIrpMajor[pirp_stack->MajorFunction],
XlatedMJInternal[pirp_stack->MinorFunction],
pirp_stack->MajorFunction, pirp_stack->MinorFunction);
else
DbgPrint(“tdi_Dispatch(): Passing %s (major %02X, minor %02X)\n”,
XlatedIrpMajor[pirp_stack->MajorFunction],
pirp_stack->MajorFunction, pirp_stack->MinorFunction);
#endif
//
// Pass the IRP to the target without touching the IRP
//
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(((PDEVICE_EXTENSION)
DeviceObject->DeviceExtension)->TopOfStack, Irp);
}
— END CODE
You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com