书写NDIS过滤钩子驱动实现ip包过滤

创建时间:2002-10-21
文章属性:原创
文章提交: flashsky (flashsky1_at_sina.com)

作者:FLASHSKY
EMAIL:flashsky@xfocus.org
站点: www.xfocus.net  www.shopsky.com
转载请注明原作者安全焦点

在普通的WINDOWS 2000下实现实现包过滤的方法主要是书写NDIS过滤驱动程序,需要的技巧比较高,而且烦琐,需要考虑很多细节。但是对于很多应用而言,只需要能更方便的对ip包进行过滤处理,其实NDIS对于ip包的过滤提供一种书写过滤钩子驱动的方式,主要方法是:
驱动中建立一个普通的设备,然后通过IOCTL_PF_SET_EXTENSION_POINTER操作将你的内核模式的过滤钩子挂接到系统默认的ip过滤驱动上,这样你就可以在自己的过滤钩子里面实现完整的基于包的各种分析和过滤的处理了。
下面就是一个完整的NDIS过滤钩子驱动的代码拒绝所有外来的TCP带S的建立连接的请求。
注意事项:
    1。需要在DDK环境中编译
    2。需要修改注册表中LMHK/System//CurrentControlSet//Services//IPFILTERDRIVER的START类型为3,让他随系统启动而启动
    3。编译生成了sys文件后需要拷贝到winnt/system32/drivers目录下
    4。需要运行一个程序后手动生成注册表项
    5。使用时用net start fxfilthook启动驱动,用net stop fxfilthook停止驱动
    6。此方法只能对ip包进行过滤,其他的协议不会经过这个过滤钩子进行处理。

//驱动程序的头文件
#include "ntddk.h"
#include "ntddndis.h"
#include "pfhook.h"
#ifndef __NTHANDLE_H
#define __NTHANDLE_H

#define NT_DEVICE_NAME L"//Device//Fxfilthook"
#define DOS_DEVICE_NAME L"//DosDevices//Fxfilthook"

#define PROT_TCP   6

#include "ntddk.h"
#include "xfilthook.h"

typedef struct IPHeader {
    UCHAR     iph_verlen;     // Version and length
    UCHAR     iph_tos;        // Type of service
    USHORT    iph_length;     // Total datagram length
    USHORT    iph_id;         // Identification
    USHORT    iph_offset;     // Flags, fragment offset
    UCHAR     iph_ttl;        // Time to live
    UCHAR     iph_protocol;   // Protocol
    USHORT    iph_xsum;       // Header checksum
    ULONG     iph_src;        // Source address
    ULONG     iph_dest;       // Destination address
} IPHeader;

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath);

NTSTATUS
CreateFilterHook
(IN PDRIVER_OBJECT DriverObject);

VOID
DriverUnload
(IN PDRIVER_OBJECT DriverObject);

PF_FORWARD_ACTION
IpFilterHook(
  IN unsigned char *PacketHeader,
  IN unsigned char *Packet,
  IN unsigned int PacketLength,
  IN unsigned int RecvInterfaceIndex,
  IN unsigned int SendInterfaceIndex,
  IN IPAddr RecvLinkNextHop,
  IN IPAddr SendLinkNextHop);
#endif

//驱动程序的c文件
#define PROT_TCP   6
#include "ntddk.h"
#include "ntddndis.h"
#include "pfhook.h"
#include "fxfilthook.h"

PDEVICE_OBJECT                  deviceObject;
UNICODE_STRING                  win32DeviceName;

//住驱动入口点
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS                        status = STATUS_SUCCESS;
    UNICODE_STRING                  ntDeviceName;
        
    RtlInitUnicodeString(&ntDeviceName,NT_DEVICE_NAME);
    //建立一个过滤钩子驱动设备
    status = IoCreateDevice (DriverObject,0,&ntDeviceName,FILE_DEVICE_UNKNOWN,0,TRUE,&deviceObject);    
    if (!NT_SUCCESS (status)) {
        goto ERROR;
    }
    RtlInitUnicodeString(&win32DeviceName, DOS_DEVICE_NAME);
    //建立一个过滤钩子驱动设备符号连接
    status = IoCreateSymbolicLink( &win32DeviceName, &ntDeviceName );
    if (!NT_SUCCESS(status))    // If we couldn't create the link then
    {                           //  abort installation.
        goto ERROR;
    }
//申明卸载例程
    DriverObject->DriverUnload = DriverUnload;
//建立钩子挂接
    status = CreateFilterHook(DriverObject);
    if (!NT_SUCCESS(status))    // If we couldn't create the link then
    {                           //  abort installation.
        IoDeleteSymbolicLink(&win32DeviceName);    
        goto ERROR;
    }
    return(STATUS_SUCCESS);
ERROR:
    if(deviceObject)
        IoDeleteDevice(deviceObject);
    //DbgPrint( "Leave DriverEntry failed/n" );
    return status;
}

NTSTATUS
CreateFilterHook(IN PDRIVER_OBJECT DriverObject)
{
    PIRP                            nirp;
    NTSTATUS                        status = STATUS_SUCCESS;
    PFILE_OBJECT                    filtfileob;
    UNICODE_STRING                  ntDeviceName;    
    PDEVICE_OBJECT                  filtdeviceob;
    PF_SET_EXTENSION_HOOK_INFO        filthook;    
    IO_STATUS_BLOCK                    filtstatus;

    RtlInitUnicodeString(&ntDeviceName,L"//Device//IPFILTERDRIVER");
         //将钩子挂接函数放入结构中
    filthook.ExtensionPointer = IpFilterHook;
         //获得系统ipfilterdriver驱动的设备指针
    status = IoGetDeviceObjectPointer(&ntDeviceName,FILE_GENERIC_READ|FILE_GENERIC_WRITE,&filtfileob,&filtdeviceob);
    if(status!=STATUS_SUCCESS)
        return status;
         //绑定过滤钩子到系统ipfilterdriver驱动的设备指针
    nirp = IoBuildDeviceIoControlRequest(
        IOCTL_PF_SET_EXTENSION_POINTER,
        filtdeviceob,
        &filthook,
        sizeof(PF_SET_EXTENSION_HOOK_INFO),
        NULL,
        0,
        FALSE,
        NULL,
        &filtstatus);
    if(nirp==NULL)
        return filtstatus.Status;
         //调度系统ipfilterdriver设备重新操作irp
    return (IoCallDriver(filtdeviceob,nirp));
}

VOID
DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
//与加载一样,只是钩子函数结构中放NULL,让系统ipfilterdriver卸载加载的钩子函数

    PIRP                            nirp;
    NTSTATUS                        status = STATUS_SUCCESS;
    PDEVICE_OBJECT                  filtdeviceob;
    PFILE_OBJECT                    filtfileob;
    PF_SET_EXTENSION_HOOK_INFO        filthook;    
    IO_STATUS_BLOCK                    filtstatus;
    UNICODE_STRING                  ntDeviceName;    

    RtlInitUnicodeString(&ntDeviceName,L"//Device//IPFILTERDRIVER");
    filthook.ExtensionPointer = NULL;
    status = IoGetDeviceObjectPointer(&ntDeviceName,FILE_GENERIC_READ|FILE_GENERIC_WRITE,&filtfileob,&filtdeviceob);
    if(status==STATUS_SUCCESS)
    {
        nirp = IoBuildDeviceIoControlRequest(
            IOCTL_PF_SET_EXTENSION_POINTER,
            filtdeviceob,
            &filthook,
            sizeof(PF_SET_EXTENSION_HOOK_INFO),
            NULL,
            0,
            FALSE,
            NULL,
            &filtstatus);
        if(nirp!=NULL)
            IoCallDriver(filtdeviceob,nirp);
    }
    IoDeleteSymbolicLink(&win32DeviceName);    
    IoDeleteDevice(deviceObject);
    return;
}

PF_FORWARD_ACTION
IpFilterHook(
        unsigned char   *PacketHeader,
        unsigned char   *Packet,
        unsigned int    PacketLength,
        unsigned int    RecvInterfaceIndex,
        unsigned int    SendInterfaceIndex,
        IPAddr          RecvLinkNextHop,
        IPAddr          SendLinkNextHop
)
{
//过滤钩子函数,这儿只简单判断属于TCP协议且数据是抵达而且带SYN标志则过滤。大家可以根据需要修改自己的过滤判断和处理。
    if(((IPHeader *)PacketHeader)->iph_protocol == PROT_TCP)
    {
//Packet[13]==0x2就是TCP中SYN的标志
//SendInterfaceIndex==INVALID_PF_IF_INDEX说明包是抵达而不是发送的,因此这样过滤就不会影响自己的包出去,但是外来带SYN请求的包则会拒绝。
        if(Packet[13]==0x2 && SendInterfaceIndex==INVALID_PF_IF_INDEX)
            return PF_DROP;
    }
    return PF_FORWARD;
}

//简单的建立注册表项的程序

unsigned char sysdir[256];
unsigned char drivcedir[256];
int RegHandelDev(char * exename)
{
    //修改注册表启动一个NTHANDLE驱动程序
    char subkey[200];
    int buflen;
    HKEY hkResult;
    char Data[4];
    DWORD isok;
    buflen = sprintf(subkey,"System//CurrentControlSet//Services//%s",exename);
    subkey[buflen]=0;
    isok = RegCreateKey(HKEY_LOCAL_MACHINE,subkey,&hkResult);
    if(isok!=ERROR_SUCCESS)
        return FALSE;
    Data[0]=3;
    Data[1]=0;
    Data[2]=0;
    Data[3]=0;    
    isok=RegSetValueEx(hkResult,"Start",0,4,(const unsigned char *)Data,4);
    Data[0]=1;
    isok=RegSetValueEx(hkResult,"Type",0,4,(const unsigned char *)Data,4);
    isok=RegSetValueEx(hkResult,"ErrorControl",0,4,(const unsigned char *)Data,4);    
    GetSystemDirectory(sysdir,256);
    buflen = sprintf(drivcedir,"%s//Drivers//FxFiltHook.sys",sysdir);
    buflen = sprintf(subkey,"//??//%s",drivcedir);
    subkey[buflen]=0;
    isok=RegSetValueEx(hkResult,"ImagePath",0,1,(const unsigned char *)subkey,buflen);
    RegCloseKey(hkResult);    
    buflen = sprintf(subkey,"//Registry//Machine//System//CurrentControlSet//Services//%s",exename);
    subkey[buflen]=0;
    return TRUE;
}

int main(int argc,char *argv[])
{
    //注册驱动程序
    if(RegHandelDev("Fxfilthook")==FALSE)
        return FALSE;
    return TRUE;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NDIS(网络设备接口规范)是一种Microsoft Windows操作系统中的网络驱动程序模型。NDIS 网卡驱动程序用于管理计算机上的网络接口卡(NIC),负责将数据从计算机发送到网络,以及将数据从网络接收到计算机。下面是一个简单的示例代码,演示了如何在NDIS 网卡驱动程序中收发数据。 首先,需要引入NDIS驱动头文件和库文件。接着,定义一个NDIS驱动的设备对象,并初始化该对象。然后,创建一个NDIS接收处理函数,用于接收和处理从网络接口卡接收到的数据。在该函数中,可以使用NDIS提供的函数来获取和处理接收到的数据。 示例代码如下所示: ```cpp #include <ndis.h> NDIS_HANDLE g_NdisDeviceHandle; NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { // 初始化NDIS驱动设备对象 NDIS_MINIPORT_CHARACTERISTICS npChars = { 0 }; npChars.MajorNdisVersion = NDIS_MAJOR_VERSION; npChars.MinorNdisVersion = NDIS_MINOR_VERSION; // 设置NDIS回调函数 // ... // 创建NDIS设备对象 NdisMInitializeWrapper( &g_NdisDeviceHandle, DriverObject, RegistryPath, NULL ); // 注册NDIS设备对象 // ... return STATUS_SUCCESS; } NDIS_STATUS NdisReceivePacket( NDIS_HANDLE NdisMiniportHandle, PNDIS_PACKET Packet ) { // 处理接收到的数据 // 获取数据的数据 PVOID dataBuffer = NULL; UINT dataLength = 0; NdisQueryPacket( Packet, NULL, NULL, &dataBuffer, &dataLength ); // 处理数据 // ... return NDIS_STATUS_SUCCESS; } ``` 以上是一个简单的示例,展示了如何在NDIS网卡驱动程序中收发数据的基本流程。根据实际需求,可以在此基础上进行修改和扩展。请注意,此示例仅为了说明目的,并非可编译代码。在实际应用中,需要根据具体系统和驱动程序的要求进行相应的实现和调试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值