最近看了一下TDI的网络过滤驱动,在Vista之后就不支持了,但是据说windows7还是能用,于是想试试在win10上还能不能玩。需要注意的是在win10上的TCP和UDP设备对象的驱动对象变成了tdx,于是有了下面的代码。
#include <Ntifs.h>
#include <ntimage.h>
#include <ntstrsafe.h>
#include <Tdikrnl.h>
#define MEM_TAG 'YCAI'
#define malloc_np(size) ExAllocatePoolWithTag(NonPagedPool, (size), MEM_TAG)
#define free(ptr) ExFreePool(ptr)
#define TDI_ADDRESS_MAX_LENGTH TDI_ADDRESS_LENGTH_OSI_TSAP
#define TA_ADDRESS_MAX (sizeof(TA_ADDRESS) - 1 + TDI_ADDRESS_MAX_LENGTH)
#define TDI_ADDRESS_INFO_MAX (sizeof(TDI_ADDRESS_INFO) - 1 + TDI_ADDRESS_MAX_LENGTH)
/* filter result */
enum {
FILTER_ALLOW = 1,
FILTER_DENY,
FILTER_PACKET_LOG,
FILTER_PACKET_BAD,
FILTER_DISCONNECT
};
typedef struct {
PIO_COMPLETION_ROUTINE old_cr; /* old (original) completion routine */
PVOID old_context; /* old (original) parameter for old_cr */
PIO_COMPLETION_ROUTINE new_cr; /* new (replaced) completion routine */
PVOID new_context; /* new (replaced) parameter for new_cr */
PFILE_OBJECT fileobj; /* FileObject from IO_STACK_LOCATION */
PDEVICE_OBJECT new_devobj; /* filter device object */
UCHAR old_control; /* old (original) irps->Control */
} TDI_SKIP_CTX;
struct completion {
PIO_COMPLETION_ROUTINE routine;
PVOID context;
};
typedef struct {
TDI_ADDRESS_INFO *tai; /* address info -- result of TDI_QUERY_ADDRESS_INFO */
PFILE_OBJECT fileobj; /* FileObject from IO_STACK_LOCATION */
} TDI_CREATE_ADDROBJ2_CTX;
struct tdi_obj {
PFILE_OBJECT fileobj, associate_obj;
UCHAR local_addr[TA_ADDRESS_MAX];
};
NTKERNELAPI NTSTATUS ObReferenceObjectByName(IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN PACCESS_STATE PassedAccessState OPTIONAL, IN ACCESS_MASK DesiredAccess OPTIONAL, IN POBJECT_TYPE ObjectType OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, OUT PVOID *Object);
extern PVOID *IoDriverObjectType;
PDEVICE_OBJECT g_tcpfltobj = NULL;
PDEVICE_OBJECT g_udpfltobj = NULL;
PDEVICE_OBJECT g_tcpfltobj6 = NULL;
PDEVICE_OBJECT g_udpfltobj6 = NULL;
DRIVER_OBJECT g_old_DriverObject;
PDRIVER_OBJECT new_DriverObject;
unsigned long ntohl(unsigned long netlong)
{
unsigned long result = 0;
((char *)&result)[0] = ((char *)&netlong)[3];
((char *)&result)[1] = ((char *)&netlong)[2];
((char *)&result)[2] = ((char *)&netlong)[1];
((char *)&result)[3] = ((char *)&netlong)[0];
return result;
}
unsigned short ntohs(unsigned short netshort)
{
unsigned short result = 0;
((char *)&result)[0] = ((char *)&netshort)[1];
((char *)&result)[1] = ((char *)&netshort)[0];
return result;
}
NTSTATUS get_device_object(wchar_t *name, PDEVICE_OBJECT *devobj) {
UNICODE_STRING str;
NTSTATUS status;
PFILE_OBJECT fileobj;
RtlInitUnicodeString(&str, name);
status = IoGetDeviceObjectPointer(&str, FILE_ALL_ACCESS, &fileobj, devobj);
if (status == STATUS_SUCCESS)
ObDereferenceObject(fileobj);
return status;
}
NTSTATUS tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {
TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)Context;
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irps;
if (Irp->IoStatus.Status != STATUS_SUCCESS)
DbgPrint("tdi_skip_complete: status 0x%x\n", Irp->IoStatus.Status);
//这里是回到之前的那一层
Irp->CurrentLocation--;
Irp->Tail.Overlay.CurrentStackLocation--;
irps = IoGetCurrentIrpStackLocation(Irp);
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);//这里是到tdi_create_addrobj_complete 去执行
}
else
status = STATUS_SUCCESS;
// 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) {
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);//之前老的complete如果有的话
}
else {
irps->Control = ctx->old_control;
}
}
free(ctx);
return status;
}
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) {
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) {
if (cr != NULL) {
// save old completion routine and context
TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)malloc_np(sizeof(*ctx));
if (ctx == NULL) {
DbgPrint("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;
//手动模拟setcomplete
irps->Context = ctx;
irps->CompletionRoutine = (PIO_COMPLETION_ROUTINE)tdi_skip_complete;
irps->Control = SL_INVOKE_ON_ERROR | SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_CANCEL;
//IoSetCompletionRoutine(irp, tdi_skip_complete, ctx, TRUE, TRUE, TRUE);
}
/* call original driver */
status = g_old_DriverObject.MajorFunction[irps->MajorFunction](devobj, irp);
}
else { /* FILTER_UNKNOWN */
status = irp->IoStatus.Status = STATUS_SUCCESS; // ???
IoCompleteRequest(irp, IO_NO_INCREMENT);
}
return status;
}
NTSTATUS tdi_create_addrobj_complete2(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {
NTSTATUS status;
TDI_CREATE_ADDROBJ2_CTX *ctx = (TDI_CREATE_ADDROBJ2_CTX *)Context;
TA_ADDRESS *addr = ctx->tai->Address.Address;
struct tdi_obj* obj_item = NULL;
unsigned long Ip= ntohl(((TDI_ADDRESS_IP *)(addr->Address))->in_addr);//得到地址
unsigned long * IpAddress =&Ip;
//打印一下ip地址和端口
DbgPrint("tdi_create_addrobj_complete2: IPaddress : %d.%d.%d.%d:%u fileobj0x%llX\n",((UCHAR *)IpAddress)[3], ((UCHAR *)IpAddress)[2], ((UCHAR *)IpAddress)[1], ((UCHAR *)IpAddress)[0], ntohs(((TDI_ADDRESS_IP *)(addr->Address))->sin_port), ctx->fileobj);
status = STATUS_SUCCESS;
if (Irp->MdlAddress != NULL) {
IoFreeMdl(Irp->MdlAddress);
Irp->MdlAddress = NULL;
}
free(ctx->tai);
free(ctx);
return STATUS_SUCCESS;
}
NTSTATUS tdi_generic_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {
if (Irp->PendingReturned) {
DbgPrint("tdi_generic_complete: PENDING\n");
IoMarkIrpPending(Irp);
}
return STATUS_SUCCESS;
}
NTSTATUS tdi_create_addrobj_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) {
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(Irp);
PIRP query_irp = (PIRP)Context;
PDEVICE_OBJECT devobj;
TDI_CREATE_ADDROBJ2_CTX *ctx = NULL;
PMDL mdl = NULL;
if (Irp->IoStatus.Status != STATUS_SUCCESS) {
DbgPrint("tdi_create_addrobj_complete: status 0x%x\n", Irp->IoStatus.Status);
status = Irp->IoStatus.Status;
goto done;
}
// query addrobj address:port
ctx = (TDI_CREATE_ADDROBJ2_CTX *)malloc_np(sizeof(TDI_CREATE_ADDROBJ2_CTX));
if (ctx == NULL) {
DbgPrint("tdi_create_addrobj_complete: malloc_np\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
ctx->fileobj = irps->FileObject;
ctx->tai = (TDI_ADDRESS_INFO *)malloc_np(TDI_ADDRESS_INFO_MAX);
if (ctx->tai == NULL) {
DbgPrint("tdi_create_addrobj_complete: malloc_np!\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
mdl = IoAllocateMdl(ctx->tai, TDI_ADDRESS_INFO_MAX, FALSE, FALSE, NULL);
if (mdl == NULL) {
DbgPrint("tdi_create_addrobj_complete: IoAllocateMdl!\n");
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
MmBuildMdlForNonPagedPool(mdl);
devobj = DeviceObject;
if (devobj == NULL) {
DbgPrint("tdi_create_addrobj_complete: get_original_devobj!\n");
status = STATUS_INVALID_PARAMETER;
goto done;
}
TdiBuildQueryInformation(query_irp, devobj, irps->FileObject, tdi_create_addrobj_complete2, ctx, TDI_QUERY_ADDRESS_INFO, mdl);
status = IoCallDriver(devobj, query_irp);//这里需要继续往下传
query_irp = NULL;
mdl = NULL;
ctx = NULL;
if (status != STATUS_SUCCESS) {//STATUS_PENDING
DbgPrint("tdi_create_addrobj_complete: IoCallDriver: 0x%x STATUS_PENDING==0x103\n", status);
goto done;
}
status = STATUS_SUCCESS;
done:
// cleanup
if (mdl != NULL)
IoFreeMdl(mdl);
if (ctx != NULL) {
if (ctx->tai != NULL)
free(ctx->tai);
free(ctx);
}
if (query_irp != NULL)
IoCompleteRequest(query_irp, IO_NO_INCREMENT);
Irp->IoStatus.Status = status;
return tdi_generic_complete(DeviceObject, Irp, Context);
}
int tdi_create(PIRP irp, PIO_STACK_LOCATION irps, struct completion *completion) {
FILE_FULL_EA_INFORMATION *ea = (FILE_FULL_EA_INFORMATION *)irp->AssociatedIrp.SystemBuffer;
if (ea != NULL) {
PDEVICE_OBJECT devobj;
devobj = irps->DeviceObject;
if (devobj == NULL) {
DbgPrint("tdi_create: unknown device object 0x%llX!\n", irps->DeviceObject);
return FILTER_DENY;
}
if (ea->EaNameLength == TDI_TRANSPORT_ADDRESS_LENGTH && memcmp(ea->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH) == 0) {//传输
PIRP query_irp;
//搞一个空的irp
query_irp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION, devobj, irps->FileObject, NULL, NULL);
if (query_irp == NULL) {
DbgPrint("tdi_create: TdiBuildInternalDeviceControlIrp\n");
return FILTER_DENY;
}
completion->routine = tdi_create_addrobj_complete;//这里是设置完成的回调
completion->context = query_irp;
}
else if (ea->EaNameLength == TDI_CONNECTION_CONTEXT_LENGTH && memcmp(ea->EaName, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH) == 0) {//连接
CONNECTION_CONTEXT conn_ctx = *(CONNECTION_CONTEXT *)(ea->EaName + ea->EaNameLength + 1);//这个是链接上下文
}
}
return FILTER_ALLOW;
}
int tdi_connect(PIRP irp, PIO_STACK_LOCATION irps, struct completion *completion){
PTDI_REQUEST_KERNEL_CONNECT param = (PTDI_REQUEST_KERNEL_CONNECT)(&irps->Parameters);
TA_ADDRESS *remote_addr = ((TRANSPORT_ADDRESS *)(param->RequestConnectionInformation->RemoteAddress))->Address;
unsigned long Ip = ntohl(((TDI_ADDRESS_IP *)(remote_addr->Address))->in_addr);//得到地址
unsigned long * IpAddress = &Ip;
// 监控TCP外连参数 ---在这里处理
DbgPrint("pid:%d tdi_connect: connobj 0x%llX, remote:%d.%d.%d.%d:%u\n",
PsGetCurrentProcessId(),
irps->FileObject,
((UCHAR *)IpAddress)[3], ((UCHAR *)IpAddress)[2], ((UCHAR *)IpAddress)[1], ((UCHAR *)IpAddress)[0],
ntohs(((TDI_ADDRESS_IP *)(remote_addr->Address))->sin_port));
return FILTER_ALLOW;
}
int tdi_associate_address(PIRP irp, PIO_STACK_LOCATION irps, struct completion *completion){
HANDLE addr_handle = ((TDI_REQUEST_KERNEL_ASSOCIATE *)(&irps->Parameters))->AddressHandle;
PFILE_OBJECT addrobj = NULL;
NTSTATUS status;
int result = FILTER_DENY;
status = ObReferenceObjectByHandle(addr_handle, GENERIC_READ, NULL, KernelMode, &addrobj, NULL);
if (status != STATUS_SUCCESS) {
DbgPrint("[tdi_fw] tdi_associate_address: ObReferenceObjectByHandle: 0x%x\n", status);
}
DbgPrint("tdi_associate_address: connobj = 0x%llX ---> addrobj = 0x%llX\n",irps->FileObject, addrobj);//这里是绑定本地的transport,只打印不记录
result = FILTER_ALLOW;
if (addrobj != NULL)
ObDereferenceObject(addrobj);
return result;
}
NTSTATUS TdiHookDeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp) {
PIO_STACK_LOCATION irps;
NTSTATUS status;
int result;
struct completion completion = { 0 };
//假装检查一下
if (irp == NULL)
return STATUS_SUCCESS;
irps = IoGetCurrentIrpStackLocation(irp);
if (DeviceObject == g_tcpfltobj || DeviceObject == g_udpfltobj) {//这里过滤TCP和UDP
switch (irps->MajorFunction) {
case IRP_MJ_CREATE:
result = tdi_create(irp, irps, &completion);
status = tdi_dispatch_complete(DeviceObject, irp, result, completion.routine, completion.context);
//DbgPrint("IRP_MJ_CREATE \n");
break;
/*case IRP_MJ_DEVICE_CONTROL:
if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
status = TdiMapUserRequest(DeviceObject, irp, irps);
}else
status = STATUS_NOT_IMPLEMENTED; // set fake status
if (status != STATUS_SUCCESS) {
void *buf = (irps->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) ?irps->Parameters.DeviceIoControl.Type3InputBuffer : NULL;
//这里的buf是send的指针,目前不用
// send IRP to original driver
status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);
break;
}*/
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
/* 根据irps->MinorFunction类型进行处理 */
if (irps->MinorFunction == TDI_CONNECT) {
tdi_connect(irp, irps, &completion);
}
else if (irps->MinorFunction == TDI_ASSOCIATE_ADDRESS) {
tdi_associate_address(irp, irps, &completion);
}
status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW,completion.routine, completion.context);
break;
default:
DbgPrint("default \n");
status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);
return status;
}
}
else
status = g_old_DriverObject.MajorFunction[irps->MajorFunction](DeviceObject, irp);//避免二次完成
return status;
}
void HookTcpIp() {
UNICODE_STRING drv_name;
NTSTATUS status;
int i;
//之后用来做过滤的
status = get_device_object(L"\\Device\\Tcp", &g_tcpfltobj);
status = get_device_object(L"\\Device\\Udp", &g_udpfltobj);
//status = get_device_object(L"\\Device\\Tcp6", &g_tcpfltobj6);
//status = get_device_object(L"\\Device\\Udp6", &g_udpfltobj6);
//DbgPrint("Tcp %llX Udp %llX Tcp6 %llX Udp6 %llX \n", g_tcpfltobj, g_udpfltobj, g_tcpfltobj6, g_udpfltobj6);
RtlInitUnicodeString(&drv_name, L"\\Driver\\tdx");//tdx
status = ObReferenceObjectByName(&drv_name, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, &new_DriverObject);
if (status != STATUS_SUCCESS) {
DbgPrint("ObReferenceObjectByName failed \n");
return;
}
ObDereferenceObject(new_DriverObject);//解引用
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
g_old_DriverObject.MajorFunction[i] = new_DriverObject->MajorFunction[i];
new_DriverObject->MajorFunction[i] = TdiHookDeviceDispatch;//替换方法
}
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject) {
int i;
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
new_DriverObject->MajorFunction[i] = g_old_DriverObject.MajorFunction[i];//还原
DbgPrint("See You !\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegPath) {
DriverObject->DriverUnload = DriverUnload;
HookTcpIp();
return STATUS_SUCCESS;
}
经过测试无法在打开ie的时候无法拦截到connect请求,但是如果关闭网卡之后在打开,可以看到IRP_MJ_CREATE和IRP_MJ_INTERNAL_DEVICE_CONTROL(TDI_ASSOCIATE_ADDRESS)的消息,由于技术有限也不知道是不是姿势不对还是说windows真的改了。