Firewall develop For Windows

Introduction:

I suppose any experienced Internet user knows what is firewall and when it is required. Those of you who interest in exact definition of this term I address to well-known on-line technical terms encyclopedia on www.whatis.com . If you are not lazy to do this you will even find two relative definitions (firewall and personal firewall). I’m not going to provide here exact classification and just enumerate some typical representatives. As far as this article is Windows systems relative the following does not pretend to cover all. Among server-oriented products I could mention WinGate, WinRoute, Vicomsoft Internet Gateway, WinProxy and etc… All these products differ in their functionality and price, and in addition to internal network intrusion protection usually realize single Internet connection sharing. From personal firewall group I can mention AtGuard, Outpost Firewall, ZoneAlarm, Tiny Personal Firewall, Sygate Personal Firewall and etc. I’m not going to discuss these solutions here; end users are responsible for this. We will concentrate on the technical part of question, in particular how to organize traffic filtering in operating systems from Windows family. I should mention, that I’m not going to describe each approach in detail; this would take pretty much amount of time. I’ll try to point different approaches advantages and disadvantages and additional information sources. Only one variant, so-called NDIS-hooking approach will be reviewed in detail. At this time its realized at least by one third-party company www.pcausa.com, which offers some source code resources for developers. Please, note that if Part I of this paper is suitable for the majority of Windows developers then Part II and Part III require deep knowledge of Windows internals and strong driver development skills. For those people who would like to experiment with network packet filtering or need to develop custom solution (network security, internet connection sharing, VPN and etc.) and have no desire or no opportunity to learn driver development we offer WinpkFilter© development framework. Those of readers who interested in development of pure kernel-mode solution also can use WinpkFilter© framework (pure IOCTL interface is well documented). The Part II and Part III of this paper covers the approach to cross-platform NDIS-hooking driver development, but the great amount of details is not mentioned here. The raw time esteem for the development stable set of drivers is 6-12(or even more) months depending of your experience, so think twice before starting your project from scratch.

Part I. Network traffic filtering technologies for Windows.

In spite of the fact that Windows 9x/ME and Windows NT/XP provides similar socket interface and NDIS architecture even allows binary compatible miniport drivers for network interfaces their network subsystem internals differ a lot. Regretfully, the size of this article does not allow us to review each of them in details, some interesting NT relative information can be found in chapter13 “Inside Microsoft Windows 2000 Third Edition” (David A. Solomon, Mark E. Russinovich MS Press 2000). As for Windows 9x/ME I can hardly recommend something. Actually, NT/2000/XP network subsystem is more complicated then 9x/ME, but we can subdivide both on some common parts:

  • NDIS. In 1989 Microsoft and 3Com jointly developed Network Driver Interface Specification (NDIS), which allows network protocol drivers use of network interface services hiding details of their realization. Network interface driver developed in conformance with this specification is commonly called NDIS-miniport. One of the Microsoft goals was to make network hardware vendors life easier, once developed NDIS-miniport is portable between Windows versions. Details subject description can be found in DDK documentation (Network Drivers section), in two words NDIS describes rules (types and interfaces) to follow in network driver development and provides functions library to call instead kernel-exported services.
  • Network Protocol Drivers. Detailed description of this driver class is out of this article subject, however for better understanding of network filtering technologies I would advise to look into DDK documentation (Network Drivers section). In two words, network protocol driver (like TCPIP an example) on it’s lower edge uses NDIS library function for network access and may provide Transport Data Interface (TDI) on the upper edge. Exported TDI interface can be used by various TDI-clients, like an example part of socket implementation afd.sys (NT/2000/XP). The usage of TDI has much common with socket interface, an example the next sequence of requests establishes connection to remote system (NT specific):
    • 1. Client allocates and initializes address open TDI IRP. On this request TDI returns file object known as address object and representing network address. This step is equivalent to bind call from Windows Sockets interface.
    • 2. Client allocates and initializes connection open TDI IRP, for what TDI return file object known as connection object and representing connection. This step is equivalent to socket function call from Windows Sockets interface.
    • 3. Client associates connection object with address object, through associate address TDI IRP.
    • 4. TDI client who wishes to accept connection issue listen TDI IRP, specifying number of connections for this connection object, and then sending accept TDI IRP for each remote client connection. This step is equal to listen and accept functions from Windows Sockets. TDI client who wishes to establish connection to remote system allocates connect TDI IRP, specifying connection object. This IRP complete when connection will be established (or error occur). This step is equivalent to connect function from Windows Sockets.
  • User-Mode DLLs that forms Windows Sockets interface. These are well-known ws2_32.dll, msafd.dll, wshtcpip.dll and etc.

Let us review possible ways for network traffic filtering. May be this will be new for some readers but about whole traffic can be filtered from User-mode, with no need in writing any drivers. No doubt, these methods has many limitations, an example does not provide any real network protection (Trojan application can skip Windows Sockets interface and use TDI directly), however can be used for such purposes like QOS(Quality Of Service).

User-mode traffic filtering.

  • 1) Winsock Layered Service Provider (LSP). This approach is well documented in MSDN and has a good example (SPI.CPP). As method advantage I would mention the possibility to determine process that called Windows Sockets. This can be used for such tasks like QOS (Quality Of Service), encryption of data streams and etc. However, don’t forget that TCPIP can be called directly via TDI; therefore this method is in no use for Trojan/virus protection and etc. Additionally, this approach can’t be used on router, because packets are routed on the TCPIP level (or even on MAC level, for details search in DDK for FFP).
  • 2) Windows 2000 Packet Filtering Interface. Windows 2000 provides API using which user-mode application can install a set of “filter descriptors”, which will be used by TCPIP for packet filtering (PASS/DROP). However, rules for filtering are rather limited (pass/drop based on IP address and port information), and this approach can be used only starting from Windows 2000 and higher, what is rather serious limitation.
  • 3) Substitution of Winsock DLL. This approach mentioned only for security reasons. I would not recommend it using nowadays because of well-known reasons.
  • 4) Global hook of all “dangerous” functions (starting from Windows sockets, DeviceIoControl and etc). If you ask me if this can be done I answer yes, but this approach is rather difficult to realize and developer must be very careful, because it have possible impact on overall system stability and security.

Kernel-mode traffic filtering:

  • 1) Kernel-mode sockets filter. This technology is applicable for Windows NT/2000. It is based on interception of all calls from msafd.dll (the lowest level user-mode Windows Sockets DLL) to the kernel-mode module afd.sys (the TDI-client, kernel-mode a part of Windows Sockets). This method is interesting, but its possibilities are no much wider, than LSP's. In addition I would like to add that AFD interface is extended from version to version of Windows NT family what limits it portability.
  • 2) TDI-filter driver. This technology applied for both Windows 9x/ME and Windows NT/2000 though concrete implementations strongly differ. The example of the code for a Windows 9x can be found in the examples to Vireo/Numega VtoolsD, therefore I will not observe it here. As for Windows NT/2000, in case of TCP/IP filtering it is necessary to intercept (using IoAttachDevice or patching dispatch table in driver object) all calls, directed to devices created by tcpip.sys driver (/Device/RawIp, /Device/Udp, /Device/Tcp, /Device/Ip, /Device/MULTICAST). I would recommend you to make simple experiment, download and install Device Filter utility from this site. Then attach to devices created by TCPIP and try any network activite (even "ping 127.0.0.1" is OK). Utility will show you all requests to the transport. This technology is well known and also it's used in a number of commercial products (for example, Outpost Firewall). However, as well as methods above, this approach can be used only for creation of personal firewall class products, and it can't protect you TCPIP stack from hackers attacks.
  • 3) NDIS Intermediate Driver. Microsoft has provided this class of drivers just for needs similar to ours, however implementation of this drivers for Windows 98/ME/NT leaves to wish the best, and in a Windows 95 is absent at all. In particular they are very inconvenient in installation and for end user. Actually, support of IM drivers was improved in Windows 2000/XP, but there is another problem, you will have to digitally sign your driver at Microsoft, elsewhere user will have a horrible nag-message. Interested persons can look at NDIS IM FAQ, and documentation in DDK. I shall not examine this variant in detail here, instead of it we shall consider worthy alternative.
  • 4) Windows 2000 Filter-Hook Driver. The method is described in DDK documentation and applicable only in Windows 2000 and higher, therefore I not shall stop on this variant.
  • 5) NDIS Hooking Filter Driver. This approach we will review in more detail here. Briefly the technique based on interception of some subset of NDIS functions which in the further allow to trace registration of all protocols installed in the operating system and opening of network interfaces by them. Among advantages of the given approach it is necessary to mention ease of installation and transparent support of Dial-Up interfaces what require additional work in case of IM drivers.
Part II. NDIS Hooking Filter Driver in a Windows 9x/ME.

Before continue reading I recommend you to open MSDN and read documentation for the following NDIS functions:

- NdisRegisterProtocol 
- NdisDeregisterProtocol 
- NdisOpenAdapter 
- NdisCloseAdapter 
- NdisSend

As acquaintance to writing drivers of virtual devices (VxD) for the platform of a Windows 9x/ME is desirable. In the further examples of the code we will use functions and data structures defined in Vireo/Numega VToolsD. Certainly, all code can be modified for compilation with DDK, however VtoolsD allows writing much more compact code and hides VxD implementation details.

The beginning of the beginnings …

As it was already mentioned above, in the Windows 9x/ME NDIS library is realized as the virtual device driver ndis.vxd. As far as we need to intercept part of NDIS functions, we should write our own virtual device driver (VxD). I am not going to teach you here to write virtual device drivers, therefore for understanding underwritten I recommend you to familiarize with a subject. In the further it is supposed, that the reader has some knowledge Windows 9x/ME internals and can create VxD, even with the help of such tools as Numega VtoolsD.

If you have followed to my advice and have viewed descriptions of five mentioned above NDIS functions, it must be clear for you, that interception of five listed functions should be made before initialization of protocols (calling NdisRegisterProtocol by them). For an examined example as the order of initialization was selected VNETBIOS_Init_Order. I leave other parameters of the VxD on your discretion as they entirely depend on that functionality what you want to receive.

Hooking of VxD services …

The technique of hooking VxD services is well documented; therefore I shall not waste time on retelling already written. I'll bring a short code snippet instead. I do not bring the code for each concrete function, that is done below for NdisRegisterProtocol, it is necessary to do and for four other functions.

...
   // Function Prototype For Hooking NdisRegisterProtocol
   typedef VOID NDIS_API OS_NDIS_REGISTER_PROTOCOL (
    PNDIS_STATUS Status,
    PNDIS_HANDLE NdisProtocolHandle,
   PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
    UINT CharacteristicsLength
    );
   
   typedef OS_NDIS_REGISTER_PROTOCOL *POS_NDIS_REGISTER_PROTOCOL;...
   // Thunks for NDIS services hooking
   HDSC_Thunk thunkNdisRegisterProtocolHook;
   ...
   // Old handlers
   POS_NDIS_REGISTER_PROTOCOL OldNdisRegisterProtocol = NULL;
   ...
   // New NdisRegisterProtocol handler
   VOID NDIS_API NH_NdisRegisterProtocol (
 PNDIS_STATUS Status, 
 PNDIS_HANDLE NdisProtocolHandle,
 PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
 UINT CharacteristicsLength
 )
   {
    ...
   }
   ...
   // Hooking VxD services of NDIS.VXD
   NDIS_STATUS HookNdisVxdServices ()
   {
     OldNdisRegisterProtocol = 
     (POS_NDIS_REGISTER_PROTOCOL) Hook_Device_Service_C (
   GetVxDServiceOrdinal (NdisRegisterProtocol),
   NH_NdisRegisterProtocol, 
   *thunkNdisRegisterProtocolHook
   );

     if (! OldNdisRegisterProtocol)
      return NDIS_STATUS_FAILURE;
     ...
   
     return NDIS_STATUS_SUCCESS;
 }

HookNdisVxdServices function should be called in the initialization handler of for the virtual device.

What is next?

Before answering this question, let's take a look, what we already have. Actually we already can view all outgoing network traffic. We are not limited only to view, but also to modify, or, for example, to transfer packets to the application working in Ring3. Anyway, we have all necessary to move further. There is a question on how to get access to the incoming traffic. Actually it not as difficult as it seems, for this purpose we have intercepted NdisRegisterProtocol. As one of arguments of this function the protocol transfers the pointer to structure NDIS_PROTOCOL_CHARACTERISTICS. This structure in details is described in documentation DDK. In new handler NdisRegisterProtocol we can modify this structure, in particular we are interested with ReceiveHandler field, this function called in reply to call by the driver of the network interface of NdisIndicateReceive function. How to process this call and to receive whole packet (the network adapter can transfer only a part of the package) documented in DDK, and I shall omit these details. Thus, actually we can process not only outgoing, but also incoming traffic. For what we intercepted three more functions? I believe, any well-designed firewall should watch the protocols, which have registered in the system, and the network adapters open them, namely the staying functions allow us to watch it.

Windows ME …

Let's put, you followed the above-stated guidelines and as a result of persistent work have created the network-filtering driver. Unfortunately, this driver will work normally only under Windows 95/98. If you install your VxD on Windows ME (I'm not going to review variants of VxD installation here, the most universal for the given class of drivers is installation through the registry) your driver will not intercept any registered protocol. The problem occurs because, TCP/IP protocol has moved from the virtual device driver (VxD) into tcpip.sys that does not know anything about VxD services. To support new implementation of the TCP/IP stack ndis.vxd exports library functions not only as VxD-services (as it did before for NDIS-miniports support, which are binary compatible with Windows NT (if built with this option) though for protocols it was not used). It is done using well-known PELDR_AddExportTable function (service of vxdldr.vxd). The problem can be resolved by simple hooking of this service, in the new handler we should check, that these are NDIS exports and change five pointers in the table (for previously mentioned functions). I shall not stop on concrete implementation, as it does not represent anything complex. Another moment with NdisRegisterProtocol function, more exactly with structure NDIS_PROTOCOL_CHARACTERISTICS is much more interesting. This structure differently defined in a Windows 9x and Windows NT DDK. You can find exact definitions in the proprietary DDK's header file ndis.h, The most important moment here is that tcpip.sys calls NdisRegisterProtocol, transferring it NDIS_PROTOCOL_CHARACTERISTICS as it is defined in NT DDK, therefore ndis.vxd does not export the same function as VxD-service and through the PELDR-interface. The function exported through the PELDR-interface should convert NDIS_PROTOCOL_CHARACTERISTICS from the format accepted in NT in the format understandable to VxD-service, then call the last. And it is necessary to mark, that in Windows ME VxD-service NdisRegisterProtocol has another structure as a parameter then one defined in a Windows 9x DDK structure, its extended and not documented variant (which allows tcpip.sys to use NDIS version up to 5.0 though in practice it uses version 4.0).

Definition of this structure should look approximately so:

typedef 
struct _ME_NDIS_PROTOCOL_CHARACTERISTICS
{
    UCHAR MajorNdisVersion;
    UCHAR MinorNdisVersion;
    ULONG Reserved;
    OPEN_ADAPTER_COMPLETE_HANDLER OpenAdapterCompleteHandler;
    CLOSE_ADAPTER_COMPLETE_HANDLER CloseAdapterCompleteHandler;
    SEND_COMPLETE_HANDLER SendCompleteHandler;
    TRANSFER_DATA_COMPLETE_HANDLER TransferDataCompleteHandler;
    RESET_COMPLETE_HANDLER ResetCompleteHandler;
    REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
    RECEIVE_HANDLER ReceiveHandler;
    RECEIVE_COMPLETE_HANDLER ReceiveCompleteHandler;
    STATUS_HANDLER StatusHandler;
    STATUS_COMPLETE_HANDLER StatusCompleteHandler;
    BIND_ADAPTER_HANDLER BindAdapterHandler;
    UNBIND_ADAPTER_HANDLER UnbindAdapterHandler;
    UNLOAD_PROTOCOL_HANDLER UnloadProtocolHandler;
    NDIS_STRING Name;
    RECEIVE_PACKET_HANDLER ReceivePacketHandler;
    PNP_EVENT_HANDLER PnPEventHandler;
    PVOID ReservedHandlers [4];
    PVOID CoSendCompleteHandler;
    PVOID CoStatusHandler;
   PVOID CoReceivePacketHandler;
    PVOID CoAfRegisterNotifyHandler;
} ME_NDIS_PROTOCOL_CHARACTERISTICS;

And pseudocode NdisRegisterProtocol exported through PELDR-tools looks approximately so:

 // New entry for export from NDIS.VXD exported through PELDR_AddExportTable
VOID NDIS_API
   WDM_NdisRegisterProtocol (
   OUT PNDIS_STATUS Status,
   OUT PNDIS_HANDLE NdisProtocolHandle,
   IN PNDIS50_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
   IN UINT CharacteristicsLength
   )
{
   unsigned short* pUnicode = NULL;
   unsigned char* pAnsi = NULL;
   unsigned int Counter = 0;
   unsigned char* pProto = NULL;
   
   ME_NDIS_PROTOCOL_CHARACTERISTICS MilleniumCharacteristics;
   NdisZeroMemory (
 *MilleniumCharacteristics,  
 sizeof (MilleniumCharacteristics)
 );
   
   MilleniumCharacteristics.MajorNdisVersion = 
    ProtocolCharacteristics->MajorNdisVersion;
   MilleniumCharacteristics.MinorNdisVersion  =
    ProtocolCharacteristics->MinorNdisVersion;
   MilleniumCharacteristics.Reserved =
    ProtocolCharacteristics->Reserved;
   
   MilleniumCharacteristics.OpenAdapterCompleteHandler = 
    ProtocolCharacteristics->OpenAdapterCompleteHandler;
   MilleniumCharacteristics.CloseAdapterCompleteHandler = 
    ProtocolCharacteristics->CloseAdapterCompleteHandler;
   MilleniumCharacteristics.SendCompleteHandler = 
    ProtocolCharacteristics->SendCompleteHandler;
   MilleniumCharacteristics.TransferDataCompleteHandler = 
    ProtocolCharacteristics->TransferDataCompleteHandler;
   MilleniumCharacteristics.ResetCompleteHandler = 
    ProtocolCharacteristics->ResetCompleteHandler;
   MilleniumCharacteristics.RequestCompleteHandler = 
    ProtocolCharacteristics->RequestCompleteHandler;
   MilleniumCharacteristics.ReceiveHandler = 
    ProtocolCharacteristics->ReceiveHandler;
   MilleniumCharacteristics.ReceiveCompleteHandler = 
    ProtocolCharacteristics->ReceiveCompleteHandler;
   MilleniumCharacteristics.StatusHandler = 
    ProtocolCharacteristics->StatusHandler;
   MilleniumCharacteristics.StatusCompleteHandler = 
    ProtocolCharacteristics->StatusCompleteHandler;
   
   if (ProtocolCharacteristics->Ndis40Chars.Ndis30Chars.MajorNdisVersion > 3)
   {
    MilleniumCharacteristics.BindAdapterHandler = 
  ProtocolCharacteristics->BindAdapterHandler;
 MilleniumCharacteristics.UnbindAdapterHandler = 
  ProtocolCharacteristics->UnbindAdapterHandler;
    MilleniumCharacteristics.UnloadProtocolHandler = 
  ProtocolCharacteristics->UnloadHandler;
    MilleniumCharacteristics.PnPEventHandler = 
  ProtocolCharacteristics->PnPEventHandler;
    MilleniumCharacteristics.ReceivePacketHandler = 
  ProtocolCharacteristics->ReceivePacketHandler;
   }
   
   if (ProtocolCharacteristics->MajorNdisVersion > 4)
   {
   MilleniumCharacteristics.CoReceivePacketHandler = 
   ProtocolCharacteristics->CoReceivePacketHandler;
    MilleniumCharacteristics.CoSendCompleteHandler = 
  ProtocolCharacteristics->CoSendCompleteHandler;
    MilleniumCharacteristics.CoStatusHandler = 
  ProtocolCharacteristics->CoStatusHandler;
    MilleniumCharacteristics.CoAfRegisterNotifyHandler = 
  ProtocolCharacteristics->CoAfRegisterNotifyHandler;
    MilleniumCharacteristics.ReservedHandlers [0] = 
  ProtocolCharacteristics->ReservedHandlers [0];
    MilleniumCharacteristics.ReservedHandlers [1] = 
  ProtocolCharacteristics->ReservedHandlers [1];
    MilleniumCharacteristics.ReservedHandlers [2] = 
  ProtocolCharacteristics->ReservedHandlers [2];
    MilleniumCharacteristics.ReservedHandlers [3] = 
  ProtocolCharacteristics->ReservedHandlers [3];
   }
   
   MilleniumCharacteristics.Name.Length = 
      ProtocolCharacteristics->Name.Length/2;
   MilleniumCharacteristics.Name.MaximumLength =  
      ProtocolCharacteristics->Name.MaximumLength/2;
   MilleniumCharacteristics.Name.Buffer = 
      (PUCHAR) HeapAllocate (
 ProtocolCharacteristics->Name.MaximumLength,
 0
 );
        
   pAnsi = MilleniumCharacteristics.Name.Buffer;
   pUnicode = (unsigned short *)
      ProtocolCharacteristics->Name.Buffer;
   
    // Copy UNICODE string to ANSI string
   for (
 Counter = 0;
 Counter < MilleniumCharacteristics.Name.Length;
 ++Counter
 )
   {
    *(pAnsi + Counter) = (UCHAR) *(pUnicode + Counter);
   }

   // finalize ANSI string with zero
   *(pAnsi + MilleniumCharacteristics.Name.Length) = 0; 
    
   NH_NdisRegisterProtocol (
     Status, 
     NdisProtocolHandle, 
     (PNDIS_PROTOCOL_CHARACTERISTICS)*MilleniumCharacteristics, 
     sizeof (MilleniumCharacteristics)
     );
 
   if (*Status == NDIS_STATUS_SUCCESS)
   {
      // pProto points to internal NDIS structure    
      // which holds information about protocol
      pProto = (PUCHAR) (*NdisProtocolHandle);

     // Some internal operation 
     *(pProto + 0x34) = *(pProto + 0x34) | 1;
   }
   
   HeapFree ((PVOID) MilleniumCharacteristics. Name. Buffer, 0);
}
   

Thus, the problem with Windows Millennium Edition has been successfully resolved.

How to continue …

It seems to me, I've given here enough information to start with implementation of the driver of the described type, certainly, I have omitted a huge set of technical details, but all of them are perfectly stated in DDK's documentation. So have a desire, everything else will be applied. In the meantime we shall precede to next subject, let's review how the similar approach can be realized in Windows NT/2000.

Part III. NDIS Hooking Filter Driver in Windows NT/2000.

For the better understanding of the technology stated in the given part acquaintance with kernel architecture of Windows NT/2000/XP is recommended. Acquaintance to writing kernel-mode drivers and the PE-format is desirable.

How to start...

Certainly you should start from creation of the elementary NT kernel-mode driver. If for the Windows 9x/ME I have mentioned VToolsD for the given driver, for example, it is possible to use DriverWorks though certainly nothing prevents to write it, using DDK only and the command line compiler. I've already mentioned, that for drivers of the given type the order of loading is important, the main requirement to our driver to boot after NDIS, but before TCPIP (and accordingly other protocols which we want to filter). As far as Windows 2000 and NT have a little different order of loading for the network subsystem, I shall not result concrete guidelines. LoadOrder utility from www.osr.com displays the order of loading of drivers in convenient manner and may be helpful to you here.

How to hook …

Implementations of NDIS are various in a Windows 9x/ME and NT/2000, now it will be enough to hook only 4 functions:

- NdisRegisterProtocol 
- NdisDeregisterProtocol 
- NdisOpenAdapter 
- NdisCloseAdapter 

Hooking NdisSend has no sense any more, if you take a look in ndis.h you will see, that in our case this function is defined as macro. However these four functions need to be intercepted somehow. Right at the beginning of this part I already marked, that it is desirable to familiarize with the PE-format, this knowledge is necessary for interception. The essence of the technology is reduced to that it is necessary to find ndis.sys header image in the memory and to patch the export table of it, changing addresses for four functions above. All necessary structures for operation with PE-image are in the winnt.h file from DDK. In Windows NT 4.0 this technology will work fine, however, having started this driver under Windows 2000 or XP (and if large 4MB pages are not used, if used WP protection disabled), you will see only " the dark blue screen of death ". The problem is that Windows 2000 protects a kernel image from possible modification. To resolve this problem there are two possible ways:

  • 1) Disable protection of a kernel image through the registry. For this purpose it is necessary to create in a HKLM/SYSTEM/CurrentControlSet/Control/S essionManager/Memory Management key REG_DWORD parameter with name EnforceWriteProtection and value 0.
  • 2) Reset Write Protection bits in register CR0, before updating the export table. It can be done, for example as follows:
 mov ebx, cr0; to receive current state Cr0push ebx; to save it(him)
 and ebx, ~0x10000; to reset WP bats
 mov cr0, ebx; to switch off write protection
 ; Here we modify the table of export....
 pop ebx;
 mov cr0, ebx; to restore the previous processor state
 

I do not bring here the code for modification of the export table mainly, because it is not a unique way to intercept NDIS function. Daniel Lanciany in his variant of NDIS-hooking driver has gone in other way, he has updated the beginning of functions, having inserted in them transitions to his code. In his handler he restores a body of the intercepted function, makes necessary operations on processing call, calls the restored function, and after return from it again modifies the beginning. As far as calls to this four functions set are not so often, this way is not much worse than editing of the export table, except one important drawback. As well as the similar method of hooking DLL functions in User-mode it may appear unsafe on SMP platforms.

What else it is necessary to do …

I shall not stop in detail on new handler NdisRegisterProtocol, as it should make practically the same as in a Windows 9x/ME i.e. to expose the handler of entering traffic (actually it is necessary to change not only ReceiveHandler, but also in particular TransferDataCompleteHandler). The only thing I should mention here is that if 9x/ME TCP/IP driver ("MSTCP") registers one protocol and this protocol directly opens both Ethernet adapters and PPPMAC (emulation Ethernet above dial-up) then in NT/2000/XP TCP/IP actually consists of two drivers TCPIP.SYS ("TCPIP") and WANARP.SYS ("TCPIP_WANARP" in 2000/XP, "RASARP" in NT 4.0) and this second protocol opens emulation /DEVICE/NDISWANIP (emulating Ethernet upper interface of intermediate NDISWAN driver).

The further operation in many respects is similar to writing of the driver of the network protocol; therefore I would advise to familiarize with appropriate section NT DDK (Network Drivers). The only complex enough moment is about new handler for NdisOpenAdapter. One of returned parameters of this function (NdisBindingHandle) actually is a pointer to NDIS_OPEN_BLOCKstructure . This structure is defined in ndis.h file, but, unfortunately, is not documented. This is important for us because it gives access to outgoing from the protocol traffic (fields SendHandler, SendPacketsHandler, and TransferDataHandler). Obviously, now it is necessary to transfer to the protocol our variant NDIS_OPEN_BLOCK, having saved the original. The following code fragment is taken from new NdisOpenAdapter handler:

// after calling original NdisOpenAdapter
NdisAcquireSpinLock ( &g_OpenAdapterLock );
if (( *Status == NDIS_STATUS_SUCCESS )||
     ( *Status == NDIS_STATUS_PENDING)
   )
{
   // Save old binding handle and adapter selected medium
   pAdapter -> m_NdisBindingHandle = *NdisBindingHandle;
   pAdapter -> m_Medium = MediumArray[*SelectedMediumIndex];
   
   // we does not support adapters except ethernet and /DEVICE/NDISWANIP
   if ( !( ( pAdapter -> m_Medium == NdisMediumDix ) ||
   ( pAdapter -> m_Medium == NdisMedium802_3 )||
   ( pAdapter -> m_Medium == NdisMediumWan ) ) )
   {
     // Release already allocated resources
     AF_FreeAdapterEntry ( pAdapter );
     NdisReleaseSpinLock ( &g_OpenAdapterLock );
     return;
   }
  // Copy Real Open Block to our location
    NdisMoveMemory ( 
     &pAdapter -> m_OpenBlock,
     *NdisBindingHandle,
     sizeof(NDIS_OPEN_BLOCK)
     );
   
    // Substitute NDIS_OPEN_BOCK
    *NdisBindingHandle = &pAdapter->m_OpenBlock;
  // Major work for initializing adapter finished
    // Check if complete handler did the remain in case of pending
    if ((*Status == NDIS_STATUS_PENDING)&&
        (pAdapter->m_dwAdapterState == ADAPTER_STATE_COMPLETE_FAILED)
     )
    {
     // Error while opening adapter occured, 
  // OpenAdapterComplete left us to free resource
     // Release already allocated resources
     AF_FreeAdapterEntry ( pAdapter );
     NdisReleaseSpinLock ( &g_OpenAdapterLock );
     return;
    }
  // Pointer to our OPEN_BLOCK (for convnience)
    pOpenBlock = (PNDIS_OPEN_BLOCK)*NdisBindingHandle;
  pAdapter->m_MacBindingHandle = pOpenBlock->MacBindingHandle;
  // Substitute Some Real handlers by our version
    pAdapter->m_SendHandler = pOpenBlock->SendHandler;
    pOpenBlock->SendHandler = OBF_SendHandler;
  pAdapter->m_SendPacketsHandler = pOpenBlock->SendPacketsHandler;
    pOpenBlock->SendPacketsHandler = OBF_SendPacketsHandler;
  pAdapter->m_RequestHandler = pOpenBlock->RequestHandler;
    pOpenBlock->RequestHandler = OBF_RequestHandler;
  pAdapter->m_TransferDataHandler = pOpenBlock->TransferDataHandler;
 ...

What we have …

Thus, the driver with minimum functionality turns out small enough and not but may appear a bit complex in implementation. Installation of it does not make problem as well as in a case with the driver for a Windows 9x/ME and require adding of several keys in the registry.

Besides the described static way of hooking NDIS library functions which demands loading the driver at a stage of start of the operating system and as such this driver can not be unloaded from memory, there is one more dynamic approach. This method works both under a Windows 9x/ME and under NT/2k/XP and though in the first case it is necessary to write VxD, and in the second kernel-mode the driver, a principle is identical. Among products existing in the market it is applied (besides control TDI and all started processes in the system) in rather known firewall ZoneAlarm (with widely recognized TrueVector technology). The essence of the approach that we register the dummy protocol (call NdisRegisterProtocol) i.e. which handlers do nothing, most complex of them can be ProtocolReceive, which returnes NDIS_STATUS_NOT_ACCEPTED. This protocol is one simple purpose to receive NdisProtocolHandle. Actually, it is the pointer to internal NDIS structure NDIS_PROTOCOL_BLOCK, which unfortunately, differs from one NDIS version to another and not always defined in ndis.h. And so in addition, this structure comprises NDIS_PROTOCOL_CHARACTERISTICS with addresses of all ProtocolXXX functions, NDIS_OPEN_BLOCK list (this structure in turn contains handlers Send/SendPackets/Request) all network interfaces bound to the given protocol and the pointer to next structure NDIS_PROTOCOL_BLOCK. The further is practically obvious, moving the list of registered protocols; we substitute the handlers where it is necessary. However, despite of apparent simplicity, this method is not simple and also demands the big care as we interfere with functionality of already working system.

The conclusion:

So, we have superficially considered the majority of approaches to firewall creation for the Windows platform, and the variant with interception NDIS was reviewed, as it seems to me, rather in details. As far as this is the only method that guarantees a complete control over network traffic, watching all registering protocols it seems to be the best way for network security relative projects. I did not try to teach you to write drivers in this small article, nonspecialists can address to DDK and learn about features of the Windows network subsystem. I can't say that this is easy to read material, but authors of books for some reason usually practically do not give NDIS attention, so this about the only source of information. From on-line resources, I think, it has some reasonable sense to look at www.ndis.com. NT Kernel Resources offers it's NDIS-hooks based product WinpkFilter©, you can use it for implementing custom network filtering, NAT, VPN solutions completely in user-mode.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值