📄 tdi_fw.c
字号:
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
//
// $Id: tdi_fw.c,v 1.7 2002/12/03 12:14:28 dev Exp $
/*
* Simple TDI-based personal firewall
*/
#include <ntddk.h>
#include <tdikrnl.h>
#include "sock.h"
#include "dispatch.h"
#include "filter.h"
#include "memtrack.h"
#include "obj_tbl.h"
#include "tdi_fw.h"
#define IOCTL_TRANSFER_TYPE(ioctl) ((ioctl) & 3)
/* context for tdi_skip_complete */
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;
/* prototypes */
static NTSTATUS DeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
static VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
#ifndef USE_TDI_HOOKING
static NTSTATUS c_n_a_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT *fltobj,
PDEVICE_OBJECT *oldobj, wchar_t *devname);
static void d_n_d_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT oldobj,
PDEVICE_OBJECT fltobj);
#else
static NTSTATUS hook_tcpip(DRIVER_OBJECT *old_DriverObject, BOOLEAN b_hook);
static NTSTATUS get_device_object(wchar_t *name, PDEVICE_OBJECT *devobj);
#endif
static NTSTATUS tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);
/* device objects for: */
PDEVICE_OBJECT
g_tcpfltobj = NULL, // \Device\Tcp
g_udpfltobj = NULL, // \Device\Udp
g_ipfltobj = NULL, // \Device\RawIp
g_devcontrol = NULL; // control device
ULONG g_got_control = 0; // got control app (contains pid)
#ifndef USE_TDI_HOOKING
// original device objects
PDEVICE_OBJECT g_tcpoldobj, g_udpoldobj, g_ipoldobj;
#else
// original driver object
DRIVER_OBJECT g_old_DriverObject;
BOOLEAN g_hooked = FALSE;
#endif
/* initialization */
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT theDriverObject,
IN PUNICODE_STRING theRegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
int i;
UNICODE_STRING name, linkname;
memtrack_init();
#ifdef USE_TDI_HOOKING
KdPrint(("[tdi_fw] WARNING! Using unstable working mode: TDI hooking!\n"));
#endif
status = ot_init();
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: ot_init: 0x%x\n", status));
goto done;
}
status = filter_init();
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: filter_init: 0x%x\n", status));
goto done;
}
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
theDriverObject->MajorFunction[i] = DeviceDispatch;
#if DBG
// register UnLoad procedure
theDriverObject->DriverUnload = OnUnload;
#endif
/* create control device and symbolic link */
RtlInitUnicodeString(&name, L"\\Device\\tdi_fw");
status = IoCreateDevice(theDriverObject,
0,
&name,
0,
0,
TRUE, // exclusive! only one control app!
&g_devcontrol);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: IoCreateDevice(control): 0x%x!\n", status));
goto done;
}
RtlInitUnicodeString(&linkname, L"\\??\\tdi_fw");
status = IoCreateSymbolicLink(&linkname, &name);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: IoCreateSymbolicLink: 0x%x!\n", status));
goto done;
}
#ifndef USE_TDI_HOOKING
status = c_n_a_device(theDriverObject, &g_tcpfltobj, &g_tcpoldobj, L"\\Device\\Tcp");
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status));
goto done;
}
status = c_n_a_device(theDriverObject, &g_udpfltobj, &g_udpoldobj, L"\\Device\\Udp");
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status));
goto done;
}
status = c_n_a_device(theDriverObject, &g_ipfltobj, &g_ipoldobj, L"\\Device\\RawIp");
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status));
goto done;
}
#else /* USE_TDI_HOOKING */
/* get device objects for tcp/udp/ip */
status = get_device_object(L"\\Device\\Tcp", &g_tcpfltobj);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: get_device_object(tcp): 0x%x\n", status));
goto done;
}
status = get_device_object(L"\\Device\\Udp", &g_udpfltobj);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: get_device_object(udp): 0x%x\n", status));
goto done;
}
status = get_device_object(L"\\Device\\RawIp", &g_ipfltobj);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: get_device_object(ip): 0x%x\n", status));
goto done;
}
/* hook tcpip */
status = hook_tcpip(&g_old_DriverObject, TRUE);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: hook_driver: 0x%x\n", status));
goto done;
}
g_hooked = TRUE;
#endif /* USE_TDI_HOOKING */
status = STATUS_SUCCESS;
done:
if (status != STATUS_SUCCESS) {
// cleanup
OnUnload(theDriverObject);
}
return status;
}
/* deinitialization */
VOID
OnUnload(IN PDRIVER_OBJECT DriverObject)
{
#ifndef USE_TDI_HOOKING
d_n_d_device(DriverObject, g_tcpoldobj, g_tcpfltobj);
d_n_d_device(DriverObject, g_udpoldobj, g_udpfltobj);
d_n_d_device(DriverObject, g_ipoldobj, g_ipfltobj);
#else
if (g_hooked)
hook_tcpip(&g_old_DriverObject, FALSE);
#endif
// delete control device and symbolic link
if (g_devcontrol != NULL) {
UNICODE_STRING linkname;
RtlInitUnicodeString(&linkname, L"\\??\\tdi_fw");
IoDeleteSymbolicLink(&linkname);
IoDeleteDevice(g_devcontrol);
}
filter_free();
ot_free();
memtrack_free();
}
#ifndef USE_TDI_HOOKING
/* create & attach device */
NTSTATUS
c_n_a_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT *fltobj, PDEVICE_OBJECT *oldobj,
wchar_t *devname)
{
NTSTATUS status;
UNICODE_STRING str;
/* create filter device */
status = IoCreateDevice(DriverObject,
0,
NULL,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
fltobj);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] c_n_a_device: IoCreateDevice(%S): 0x%x\n", devname, status));
return status;
}
(*fltobj)->Flags |= DO_DIRECT_IO;
RtlInitUnicodeString(&str, devname);
status = IoAttachDevice(*fltobj, &str, oldobj);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] DriverEntry: IoAttachDevice(%S): 0x%x\n", devname, status));
return status;
}
KdPrint(("[tdi_fw] DriverEntry: %S fileobj: 0x%x\n", devname, *fltobj));
return STATUS_SUCCESS;
}
/* detach & delete device */
void
d_n_d_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT oldobj, PDEVICE_OBJECT fltobj)
{
/*
* Detaching of a filter driver at runtime is a high-risk deal
*/
#if 1
// for extremal guys only!
if (oldobj != NULL && fltobj != NULL) {
int i;
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = g_tcpoldobj->DriverObject->MajorFunction[i];
}
#endif
if (oldobj != NULL)
IoDetachDevice(oldobj);
if (fltobj != NULL)
IoDeleteDevice(fltobj);
}
#else /* USE_TDI_HOOKING */
/* hook/unhook driver */
NTSTATUS
hook_tcpip(DRIVER_OBJECT *old_DriverObject, BOOLEAN b_hook)
{
UNICODE_STRING drv_name;
NTSTATUS status;
PDRIVER_OBJECT new_DriverObject;
int i;
RtlInitUnicodeString(&drv_name, L"\\Driver\\Tcpip");
status = ObReferenceObjectByName(&drv_name, OBJ_CASE_INSENSITIVE, NULL, 0,
IoDriverObjectType, KernelMode, NULL, &new_DriverObject);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] hook_driver: ObReferenceObjectByName\n"));
return status;
}
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
if (b_hook) {
old_DriverObject->MajorFunction[i] = new_DriverObject->MajorFunction[i];
new_DriverObject->MajorFunction[i] = DeviceDispatch;
} else
new_DriverObject->MajorFunction[i] = old_DriverObject->MajorFunction[i];
}
return STATUS_SUCCESS;
}
/* get device object by its name */
NTSTATUS
get_device_object(wchar_t *name, PDEVICE_OBJECT *devobj)
{
UNICODE_STRING str;
OBJECT_ATTRIBUTES oa;
NTSTATUS status;
HANDLE handle = NULL;
IO_STATUS_BLOCK isb;
PFILE_OBJECT fileobj;
// !!! this is UGLY way but I don't know the shortest one
RtlInitUnicodeString(&str, name);
InitializeObjectAttributes(&oa, &str, OBJ_CASE_INSENSITIVE, 0, 0);
status = ZwCreateFile(&handle, 0, &oa, &isb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN,
0, NULL, 0);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] get_device_object: ZwCreateFile: 0x%x\n"));
goto done;
}
status = ObReferenceObjectByHandle(handle, GENERIC_READ | GENERIC_WRITE, NULL,
KernelMode, &fileobj, NULL);
if (status != STATUS_SUCCESS) {
KdPrint(("[tdi_fw] get_device_object: ObReferenceObjectByHandle: 0x%x\n"));
goto done;
}
// and get DeviceObject by FileObject
*devobj = fileobj->DeviceObject;
ObDereferenceObject(fileobj);
KdPrint(("[tdi_fw] get_device_object: \"%S\" devobj: 0x%x\n", name, *devobj));
done:
if (handle != NULL)
ZwClose(handle);
return status;
}
#endif /* USE_TDI_HOOKING */
/* dispatch */
NTSTATUS
DeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp)
{
PIO_STACK_LOCATION irps;
NTSTATUS status;
// sanity check
if (irp == NULL) {
KdPrint(("[tdi_fw] DeviceDispatch: !irp\n"));
return STATUS_SUCCESS;
}
irps = IoGetCurrentIrpStackLocation(irp);
if (DeviceObject == g_tcpfltobj || DeviceObject == g_udpfltobj ||
DeviceObject == g_ipfltobj) {
/*
* This IRP is for filtered device
*/
int result;
struct completion completion;
memset(&completion, 0, sizeof(completion));
// Analyze MajorFunction
switch (irps->MajorFunction) {
case IRP_MJ_CREATE: /* create fileobject */
result = tdi_create(irp, irps, &completion);
status = tdi_dispatch_complete(DeviceObject, irp, result,
completion.routine, completion.context);
break;
case IRP_MJ_DEVICE_CONTROL:
KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_DEVICE_CONTROL, minor 0x%x for 0x%08X\n",
irps->MinorFunction, irps->FileObject));
if (KeGetCurrentIrql() == PASSIVE_LEVEL) {
/*
* try to convert it to IRP_MJ_INTERNAL_DEVICE_CONTROL
* (works on PASSIVE_LEVEL only!)
*/
status = TdiMapUserRequest(DeviceObject, irp, irps);
} else
status = STATUS_NOT_IMPLEMENTED; // set fake status
if (status != STATUS_SUCCESS) {
// send IRP to original driver
status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL);
break;
}
// don't break! go to internal device control!
case IRP_MJ_INTERNAL_DEVICE_CONTROL: {
/*
* Analyze ioctl for TDI driver
*/
int i;
for (i = 0; g_tdi_ioctls[i].MinorFunction != 0; i++)
if (g_tdi_ioctls[i].MinorFunction == irps->MinorFunction) {
#if DBG
// print description
KdPrint(("[tdi_fw] DeviceDispatch: %s (0x%x) for 0x%x\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -