Sample Image - FwHookDrv.jpg

Introduction

Probably, Firewall-Hook driver
is one of the most undocumented methods a developer can use to develop packet filtering applications in Windows systems. Microsoft doesn't give any documentation about it, and the only place where you can learn something is in the DDK header files (ipFirewall.h).
In fact, when I installed the Windows 2000 DDK, I was very surprised when I found this .h (and its contents!) because no documentation about the existence of Firewall hook could be read. In the next versions of DDK, Microsoft adds a few documentation
about it: "this method exists but it is not recommended to implement".

However, because it's an easy method to implement firewall solutions, I think it is interesting to know how Firewall-Hook drivers
work.

The Firewall-Hook Driver

I don't understand why Microsoft doesn't recommend the development of Firewall-Hook drivers.
It's true that I never recommend it when you want to develop a complete firewall solution, but for small applications, it can be a good alternative. Basically, a Firewall-Hook driver
can do the same work that a Filter Hook driver can do (see my article"Developing
Firewalls for Windows 2000/XP"
, to get more information) but with less restrictions.

If you remember, Filter-Hook driver only allows one filter function installed in the system. If one application already uses this functionality, your application doesn't work. With Firewall-Hook driver,
you don't have this problem. You can install all filter functions you need. Each filter function has a priority assigned, so the system will call one function after another (in priority order) until a function returns "DROP PACKET". If all functions return
"ALLOW PACKET", the packet will be allowed. You can imagine it as a chain of filter functions. This chain is broken when one of them returns "DROP PACKET". The order of each function in the chain is given by its priority value.

Chained function figure

In the figure, I represent the next process:

  1. A packet is received in your host. IP driver has the list of filter functions ordered by priority (the function with more priority is Filter Function 1).
  2. First, IP driver passes the packet to the highest priority filter function and waits for the return value.
  3. Filter function 1 returns "ALLOW PACKET".
  4. Because Filter function 1 allows the packet, IP driver passes the packet to the next filter function: Filter function 2.
  5. In this case, Filter function 2 returns "DROP PACKET". So, IP driver drops the packet and does not continue calling the next filter functions.

Another problem you can find with Filter-Hook drivers is that for sent packets, you can't access packet content data. However, you can access all data with a Firewall-Hook driver.
The structure of data received in a Firewall-Hook filter
function is more complex than the one received in Filter-Hook driver. It's more similar to the structure of packets you can find in a NDIS driver, where the total packet is composed by a chain of buffers. But be patient, we can learn more about it later.

As Filter-Hook driver, Firewall-Hook driver
is only a kernel mode driver used to install a callback function (butFirewall-Hook driver
installs a callback in IP driver). In fact, the process to install a Firewall-Hook driver
is similar to the one used to install a Filter-Hook driver. Inside ipFirewall.h file, you can find the next lines:

typedef struct _IP_SET_FIREWALL_HOOK_INFO 
{ 
    // Packet filter callout. 
    IPPacketFirewallPtr FirewallPtr;

    // Priority of the hook
    UINT Priority;

       // if TRUE then ADD else DELETE 
       BOOLEAN Add;
} IP_SET_FIREWALL_HOOK_INFO, *PIP_SET_FIREWALL_HOOK_INFO;   
 
#define DD_IP_DEVICE_NAME L\\<A href="file://Ip/">Device\\Ip</A> 
#define _IP_CTL_CODE(function, method, access) \ 
        CTL_CODE(FSCTL_IP_BASE, function, method, access) 
#define IOCTL_IP_SET_FIREWALL_HOOK \ 
        _IP_CTL_CODE(12, METHOD_BUFFERED, FILE_WRITE_ACCESS)

These lines give you an idea about how to install a callback function. You have only to fill aIP_SET_FIREWALL_HOOK_INFO structure
with the data of your callback function and install it sending the IOCTL
IOCTL_IP_SET_FIREWALL_HOOK
 to the IP device. Easy, if you have worked with drivers and if you have worked with documented Filter-Hook drivers before. An important parameter about this structure is the field Priority.
Each field contains the priority of the filter function, greater as greater is this value.

PDEVICE_OBJECT ipDeviceObject=NULL; 
IP_SET_FIREWALL_HOOK_INFO filterData; 

//..... 

// Init structure filterData.
FirewallPtr = filterFunction; 
filterData.Priority = 1; 
filterData.Add = TRUE; 

//.... 

// Send the commando to ip driver
IoCallDriver(ipDeviceObject, irp);

If you want to uninstall a filter function, you can use the same code but putting FALSE value
into filterData.Add.

The Filter Function

The filter function for a Firewall-Hook driver
is more complex than that used in Filter-Hook drivers. Therefore, the complexity grows because there isn’t documentation about the function and its parameters. The function has the following signature:

FORWARD_ACTION cbFilterFunction(VOID **pData, 
                                     UINT RecvInterfaceIndex, 
                                     UINT *pSendInterfaceIndex, 
                                     UCHAR *pDestinationType, 
                                     VOID *pContext, 
                                     UINT ContextLength, 
                                     struct IPRcvBuf **pRcvBuf);

With patience and using debugging methods (and interpreting the name of the parameters :)), I get the following information about these parameters:

pData *pData points
to a (struct
IPRcvBuf *
) structure with packet buffer.
RecvInterfaceIndex Interface where the data is received.
pSendInterfaceIndex Pointer to unsigned int containing
the value of the index where data is sent. Although it is a pointer, changing this value doesn't get the packet to be rerouted :(.
pDestinationType Pointer to unsigned int with
destination type: local network, remote, broadcast, multicast, etc.
pContext Point to a FIREWALL_CONTEXT_T structure
where you can find information about the packet as if the packet is incoming or outgoing packet.
ContextLength Size of buffer pointed by pContext.
Its value is alwayssizeof(FIREWALL_CONTEXT_T).
pRcvBuf *pRcvBuf points
always to NULL.

This information can be changed in future Windows versions because no official documentation is available. I only guarantee that this is the meaning of these fields that I obtained from my tests in Windows 2000 and Windows XP.

For each packet, our