基于Filter-Hook Driver(使用ipfirewall.h)的IP过滤驱动
|
来源:http://www.smatrix.org 作者:fleshwound 发布时间:2007-03-09
|
|
Author: fleshwound Email: fleshwound@126.com 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 * 作 者:fleshwound@126.com * 相关信息: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
|
|
|
[推荐]
[评论(0条)]
[返回顶部] [打印本页]
[关闭窗口] |
|
|
|
|
|
|
推荐广告 |
|
|
|
|