发新话题
打印

[转载]书写NDIS过滤钩子驱动实现ip包过滤

[转载]书写NDIS过滤钩子驱动实现ip包过滤

信息来源:绿盟

作者: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停止驱动

//驱动程序的头文件
#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;
}

TOP

发新话题