Author: fleshwound
Email:
[email protected]
Homepage: http://www.smatrix.org
IP过滤驱动可以广泛的应用于网络安全产品的研发,NDIS和TDI的驱动资料很多,有比较成熟的代码可以参考,但是使用IPFIREWALL.h开发的IP过滤驱动的资料非常少,这次自己做一个软件的时候参考VCKBASE上的一篇文章《开发Windows 2000/XP下的防火墙》(作者:Jesús O)的基础上,写了一个驱动,代码都做了详细的注释了,只要稍微有点驱动设计基础的都可以看得懂,我把自己的特殊的回调函数去掉了,保留了基本的完整框架,牛人就不需要看了,初学者都可以在此基础上继续快速开发。
1 SmatrixIPDiv.cpp文件
2 protocol.h头文件
3 SmatrixIPDiv.h头文件
* Copyright (c) 2007,安全矩阵(Security Matrix)
* All rights reserved.
*
* 文件名称:SmatrixIPDiv.cpp
* 文件标识:S
* 摘 要:IP过滤驱动,利用ipfirewall捕获包、分析包、过滤包
* 开始时间:2006年12月26日
*
* 当前版本:1.0
* 作 者:
[email protected]
* 相关信息: http://www.smatrix.org
* 完成日期:2007年1月2日
*/
extern "C"
{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ntddk.h>
#include <ntddndis.h>
#include <pfhook.h>
#include <ndis.h>
#include <ipfirewall.h>
}
#include "SmatrixIPDiv.h"
#include "protocol.h"
///////////////////////// 自定义函数的声明///////////////////////
//关闭打开驱动函数
NTSTATUS DispatchCreateClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
//驱动卸载函数
void DriverUnload(PDRIVER_OBJECT pDriverObj);
//IO控制派遣函数(内核消息处理)
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
// 向过滤列表中添加一个过滤规则
NTSTATUS AddFilterToList(CIPFilter* pFilter);
//清除过滤列表
void ClearFilterList();
// 注册钩子回调函数
NTSTATUS SetFilterFunction(IPPacketFirewallPtr filterFunction, BOOLEAN load);
//包过滤函数
FORWARD_ACTION FilterPacket(unsigned char *PacketHeader,
unsigned char *Packet,
unsigned int PacketLength,
DIRECTION_E direction,
unsigned int RecvInterfaceIndex,
unsigned int SendInterfaceIndex);
//IP过滤器函数
FORWARD_ACTION IPFilterFunction(VOID **pData,
UINT RecvInterfaceIndex,
UINT *pSendInterfaceIndex,
UCHAR *pDestinationType,
VOID *pContext,
UINT ContextLength,
struct IPRcvBuf **pRcvBuf);
// 过滤列表首地址
struct CFilterList* g_pHeader = NULL;
// 驱动内部名称和符号连接名称
#define DEVICE_NAME L"//Device//DevSMFltIP"
#define LINK_NAME L"//DosDevices//DrvSMFltIp"
//驱动入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
NTSTATUS status = STATUS_SUCCESS;
// 初始化各个派遣例程
pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreateClose;
pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateClose;
pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
pDriverObj->DriverUnload = DriverUnload;
// 创建、初始化设备对象
// 设备名称
UNICODE_STRING ustrDevName;
RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
// 创建设备对象
PDEVICE_OBJECT pDevObj;
status = IoCreateDevice(pDriverObj,
0,
&ustrDevName,
FILE_DEVICE_DRVFLTIP,
0,
FALSE,
&pDevObj);
if(!NT_SUCCESS(status))
{
return status;
}
// 创建符号连接名称
// 符号连接名称
UNICODE_STRING ustrLinkName;
RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
// 创建关联
status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName);
if(!NT_SUCCESS(status))
{
IoDeleteDevice(pDevObj);
return status;
}
return STATUS_SUCCESS;
}
void DriverUnload(PDRIVER_OBJECT pDriverObj)
{
// 卸载过滤函数
SetFilterFunction(IPFilterFunction,FALSE);
// 释放所有资源
ClearFilterList();
// 删除符号连接名称
UNICODE_STRING strLink;
RtlInitUnicodeString(&strLink, LINK_NAME);
IoDeleteSymbolicLink(&strLink);
// 删除设备对象
IoDeleteDevice(pDriverObj->DeviceObject);
}
// 处理IRP_MJ_CREATE、IRP_MJ_CLOSE功能代码
NTSTATUS DispatchCreateClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
// pIrp->IoStatus.Information = 0;
// 完成此请求
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
// I/O控制派遣例程
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
// 取得此IRP(pIrp)的I/O堆栈指针
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
// 取得I/O控制代码
ULONG uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
// 取得I/O缓冲区指针和它的长度
PVOID pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
ULONG uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
// 响应用户的命令
switch(uIoControlCode)
{
case START_IP_HOOK: // 开始过滤
status = SetFilterFunction(IPFilterFunction,TRUE);
break;
case STOP_IP_HOOK: // 停止过滤
status = SetFilterFunction(IPFilterFunction,FALSE);
break;
case ADD_FILTER: // 添加一个过滤规则
if(uInSize == sizeof(CIPFilter))
status = AddFilterToList((CIPFilter*)pIoBuffer);
else
status = STATUS_INVALID_DEVICE_REQUEST;
break;
case CLEAR_FILTER: // 释放过滤规则列表
ClearFilterList();
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
// 完成请求
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
///////////////////////////////////////////////////////////////////
//过滤列表
// 向过滤列表中添加一个过滤规则
NTSTATUS AddFilterToList(CIPFilter* pFilter)
{
// 为新的过滤规则申请内存空间
CFilterList* pNew = (CFilterList*)ExAllocatePool(NonPagedPool, sizeof(CFilterList));
if(pNew == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
// 填充这块内存
RtlCopyMemory(&pNew->ipf, pFilter, sizeof(CIPFilter));
// 连接到过滤列表中
pNew->pNext = g_pHeader;
g_pHeader = pNew;
return STATUS_SUCCESS;
}
// 清除过滤列表
void ClearFilterList()
{
CFilterList* pNext;
// 释放过滤列表占用的所有内存
while(g_pHeader != NULL)
{
pNext = g_pHeader->pNext;
// 释放内存
ExFreePool(g_pHeader);
g_pHeader = pNext;
}
}
// 包过滤函数
FORWARD_ACTION FilterPacket(unsigned char *PacketHeader,
unsigned char *Packet,
unsigned int PacketLength,
DIRECTION_E direction,
unsigned int RecvInterfaceIndex,
unsigned int SendInterfaceIndex)
{
// 提取IP头
IPHeader* pIPHdr = (IPHeader*)PacketHeader;
TCPHeader *pTCPHdr = NULL;
UDPHeader *pUDPHdr = NULL;
if(pIPHdr->ipProtocol == 6) // 是TCP协议
{
// 提取TCP头
pTCPHdr = (TCPHeader*)Packet;
// 我们接受所有已经建立连接的TCP封包
if(!(pTCPHdr->flags & 0x02))
{
return FORWARD;
}
}
// 与过滤规则相比较,决定采取的行动
CFilterList* pList = g_pHeader;
while(pList != NULL)
{
// 比较协议
if(pList->ipf.protocol == 0 || pList->ipf.protocol == pIPHdr->ipProtocol)
{
// 查看源IP地址
if(pList->ipf.sourceIP != 0 &&
(pList->ipf.sourceIP & pList->ipf.sourceMask) != pIPHdr->ipSource)
{
pList = pList->pNext;
continue;
}
// 查看目标IP地址
if(pList->ipf.destinationIP != 0 &&
(pList->ipf.destinationIP & pList->ipf.destinationMask) != pIPHdr->ipDestination)
{
pList = pList->pNext;
continue;
}
// 如果是TCP封包,查看端口号
if(pIPHdr->ipProtocol == 6)
{
pTCPHdr = (TCPHeader*)Packet;
if(pList->ipf.sourcePort == 0 || pList->ipf.sourcePort == pTCPHdr->sourcePort)
{
if(pList->ipf.destinationPort == 0
|| pList->ipf.destinationPort == pTCPHdr->destinationPort)
{
// 现在决定如何处理这个封包
if(pList->ipf.bDrop)
return DROP;
else
return FORWARD;
}
}
}
// 如果是UDP封包,查看端口号
else if(pIPHdr->ipProtocol == 17)
{
pUDPHdr = (UDPHeader*)Packet;
if(pList->ipf.sourcePort == 0 || pList->ipf.sourcePort == pUDPHdr->sourcePort)
{
if(pList->ipf.destinationPort == 0
|| pList->ipf.destinationPort == pUDPHdr->destinationPort)
{
// 现在决定如何处理这个封包
if(pList->ipf.bDrop)
return DROP;
else
return FORWARD;
}
}
}
else
{
// 对于其它封包,我们直接处理
if(pList->ipf.bDrop)
return DROP;
else
return FORWARD;
}
}
// 比较下一个规则
pList = pList->pNext;
}
// 我们接受所有没有注册的封包
return FORWARD;
}
// 注册钩子回调函数
NTSTATUS SetFilterFunction(IPPacketFirewallPtr filterFunction, BOOLEAN load)
{
//{变量定义BEGIN}
NTSTATUS status = STATUS_SUCCESS; //内核状态
NTSTATUS waitStatus = STATUS_SUCCESS; //受信状态
PDEVICE_OBJECT pDeviceObj = NULL; //pDeviceObj变量将指向IP过滤驱动设备对象
PFILE_OBJECT pFileObj = NULL; //内核过滤器设备
IP_SET_FIREWALL_HOOK_INFO filterData; //IP_SET_FIREWALL_HOOK_INFO结构
UNICODE_STRING ustrFilterDriver; // IP过滤驱动的名称
KEVENT event; //
IO_STATUS_BLOCK ioStatus; //
PIRP pIrp; //
//{变量定义END}
// 初始化IP过滤驱动的名称
RtlInitUnicodeString(&ustrFilterDriver, DD_IP_DEVICE_NAME);
// 取得设备对象指针
status = IoGetDeviceObjectPointer(&ustrFilterDriver, STANDARD_RIGHTS_ALL, &pFileObj, &pDeviceObj);
if(!NT_SUCCESS(status))
{
return status;
}
/////////// 使用到IP过滤驱动中设备对象的指针创建一个IRP///////////////////////////
// 填充IP_SET_FIREWALL_HOOK_INFO结构
filterData.FirewallPtr = filterFunction;
filterData.Priority = 1;
filterData.Add = load;
// 我们需要初始化一个事件对象。
// 构建IRP时需要使用这个事件内核对象,当IP过滤取得接受到此IRP,完成工作以后会将它置位
KeInitializeEvent(&event, NotificationEvent, FALSE);
// 为设备控制请求申请和构建一个IRP
pIrp = IoBuildDeviceIoControlRequest(IOCTL_IP_SET_FIREWALL_HOOK, // io control code
pDeviceObj,
(PVOID) &filterData,
sizeof(IP_SET_FIREWALL_HOOK_INFO),
NULL,
0,
FALSE,
&event,
&ioStatus);
if(NULL==pIrp)
{
// 如果不能申请空间得到pIrp,返回对应的错误代码
return STATUS_INSUFFICIENT_RESOURCES;
}
////////////////////////////////////////////////////////////////
/////////////// 请求安装钩子回调函数/////////////////////////////
// 发送此IRP到IP过滤驱动
status = IoCallDriver(pDeviceObj, pIrp);
// 等待IP过滤驱动的通知
if(status == STATUS_PENDING)
{
waitStatus=KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
if (!NT_SUCCESS(waitStatus)) //受信状态不成功,返回
{
return waitStatus;
}
}
status = ioStatus.Status;
if(!NT_SUCCESS(status))//状态不成功,返回
{
return status;
}
/////////////////////////////////////////////////////////////////////////
////////////////////// 清除内核资源/////////////////////////////////////
if(pFileObj != NULL)
ObDereferenceObject(pFileObj);
pDeviceObj = NULL; //避免产生野指针
pFileObj = NULL; //避免产生野指针
return status;
}
//IP过滤器函数
FORWARD_ACTION IPFilterFunction(VOID **pData,
UINT RecvInterfaceIndex,
UINT *pSendInterfaceIndex,
UCHAR *pDestinationType,
VOID *pContext,
UINT ContextLength,
struct IPRcvBuf **pRcvBuf)
{
FORWARD_ACTION result = FORWARD;
unsigned char *packet = NULL;
int bufferSize = 0;
struct IPRcvBuf *buffer =(struct IPRcvBuf *) *pData;
PFIREWALL_CONTEXT_T fwContext = (PFIREWALL_CONTEXT_T)pContext;
DIRECTION_E direction=IP_RECEIVE;
//如果包指针不为空,IPRcvBuf中存在数据
if(buffer != NULL)
{
bufferSize = buffer->ipr_size;
while(buffer->ipr_next != NULL) //得到整个IPRcvBuf缓冲链中数据总长度
{
buffer = buffer->ipr_next;
bufferSize += buffer->ipr_size;
}
//分配一个不分页的内存,将整个IPRcvBuf缓冲链放入其中
packet = (unsigned char *) ExAllocatePool(NonPagedPool, bufferSize);
if(packet != NULL)
{
IPHeader *ipp = (IPHeader *)packet;
unsigned int offset = 0;
buffer = (struct IPRcvBuf *) *pData;
memcpy(packet, buffer->ipr_buffer, buffer->ipr_size);
while(buffer->ipr_next != NULL)
{
offset += buffer->ipr_size;
buffer = buffer->ipr_next;
memcpy(packet + offset, buffer->ipr_buffer, buffer->ipr_size);
}
if (NULL != fwContext)
{
direction=fwContext->Direction;
}
else
{
direction=(DIRECTION_E)0;
}
//调用包检测函数,通过返回FORWARD,否则返回DROP
result = FilterPacket(packet,
packet + (ipp->ipHeaderLength * 4),
bufferSize - (ipp->ipHeaderLength * 4),
direction,
RecvInterfaceIndex,
(pSendInterfaceIndex != NULL) ? *pSendInterfaceIndex : 0);
}
}
//释放分配的临时包缓存
if(NULL != packet) ExFreePool(packet);
return result;
}
2 定义常见的封包结构信息
//文件名称:protocol.h
typedef struct IPHeader
{ UCHAR ipHeaderLength:4; // 头长度
UCHAR ipVersion:4; // 版本号
UCHAR ipTOS; // 服务类型
USHORT ipLength; // 封包总长度,即整个IP报的长度
USHORT ipID; // 封包标识,惟一标识发送的每一个数据报
USHORT ipFlags; // 标志
UCHAR ipTTL; // 生存时间,就是TTL
UCHAR ipProtocol; // 协议,可能是TCP、UDP、ICMP等
USHORT ipChecksum; // 校验和
ULONG ipSource; // 源IP地址
ULONG ipDestination; // 目标IP地址
} IPPacket;
typedef struct _TCPHeader
{
USHORT sourcePort; // 源端口号
USHORT destinationPort; // 目的端口号
ULONG sequenceNumber; // 序号
ULONG acknowledgeNumber; // 确认序号
UCHAR dataoffset; // 数据指针
UCHAR flags; // 标志
USHORT windows; // 窗口大小
USHORT checksum; // 校验和
USHORT urgentPointer; // 紧急指针
} TCPHeader;
typedef struct _UDPHeader
{
USHORT sourcePort; // 源端口号
USHORT destinationPort; // 目的端口号
USHORT len; // 封包长度
USHORT checksum; // 校验和
} UDPHeader;
enum
{
IPPROTO_IP = 0, // Dummy protocol for TCP.
IPPROTO_HOPOPTS = 0, // IPv6 Hop-by-Hop options. */
IPPROTO_ICMP = 1, // Internet Control Message Protocol. */
IPPROTO_IGMP = 2, // Internet Group Management Protocol. */
IPPROTO_IPIP = 4, // IPIP tunnels (older KA9Q tunnels use 94). */
IPPROTO_TCP = 6, // Transmission Control Protocol. */
IPPROTO_EGP = 8, // Exterior Gateway Protocol. */
IPPROTO_PUP = 12, // PUP protocol. */
IPPROTO_UDP = 17, // User Datagram Protocol. */
IPPROTO_IDP = 22, // XNS IDP protocol. */
IPPROTO_TP = 29, // SO Transport Protocol Class 4. */
IPPROTO_IPV6 = 41, // IPv6 header. */
IPPROTO_ROUTING = 43, // IPv6 routing header. */
IPPROTO_FRAGMENT = 44, // IPv6 fragmentation header. */
IPPROTO_RSVP = 46, // Reservation Protocol. */
IPPROTO_GRE = 47, // General Routing Encapsulation. */
IPPROTO_ESP = 50, // encapsulating security payload. */
IPPROTO_AH = 51, // authentication header. */
IPPROTO_ICMPV6 = 58, // ICMPv6. */
IPPROTO_NONE = 59, /* IPv6 no next header. */
IPPROTO_DSTOPTS = 60, /* IPv6 destination options. */
IPPROTO_MTP = 92, /* Multicast Transport Protocol. */
IPPROTO_ENCAP = 98, /* Encapsulation Header. */
IPPROTO_PIM = 103, /* Protocol Independent Multicast. */
IPPROTO_COMP = 108, /* Compression Header Protocol. */
IPPROTO_RAW = 255, /* Raw IP packets. */
IPPROTO_MAX
};
3 IP过滤驱动相关结构和宏定义
// 文件名称:SmatrixIPDiv.h
#ifndef __SMATRIXIPDIV_H__
#define __SMATRIXIPDIV_H__
// 自定义设备类型,在创建设备对象时使用
// 注意,自定义值的范围是32768-65535
#define FILE_DEVICE_DRVFLTIP 0x00654322
// 自定义的IO控制代码,用于区分不同的设备控制请求
// 注意,自定义值的范围是2048-4095
#define DRVFLTIP_IOCTL_INDEX 0x830
//
// 定义各种设备控制代码。分别是开始过滤、停止过滤、添加过滤规则、清除过滤规则
//
#define START_IP_HOOK CTL_CODE(FILE_DEVICE_DRVFLTIP, /
DRVFLTIP_IOCTL_INDEX, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define STOP_IP_HOOK CTL_CODE(FILE_DEVICE_DRVFLTIP, /
DRVFLTIP_IOCTL_INDEX+1, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define ADD_FILTER CTL_CODE(FILE_DEVICE_DRVFLTIP, /
DRVFLTIP_IOCTL_INDEX+2, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define CLEAR_FILTER CTL_CODE(FILE_DEVICE_DRVFLTIP, /
DRVFLTIP_IOCTL_INDEX+3, METHOD_BUFFERED, FILE_ANY_ACCESS)
// 定义过滤规则的结构
struct CIPFilter
{
USHORT protocol; // 使用的协议
ULONG sourceIP; // 源IP地址
ULONG destinationIP; // 目标IP地址
ULONG sourceMask; // 源地址屏蔽码
ULONG destinationMask; // 目的地址屏蔽码
USHORT sourcePort; // 源端口号
USHORT destinationPort; // 目的端口号
BOOLEAN bDrop; // 是否丢弃此封包
};
// 过滤列表
struct CFilterList
{
CIPFilter ipf; // 过滤规则
CFilterList* pNext; // 指向下一个CFilterList结构
};
#endif // __SMATRIXIPDIV_H__
[注:这里感谢下sinister和驱动网若干牛人的热情指导和建议,需要驱动开发向导文件得可以到 http://www.smatrix.org/bbs 下-by fleshwound]
参考文献:
1开发Windows 2000/XP下的防火墙, http://www.vckbase.com/document/viewdoc/?id=1067