TDI FILTER driver

Home Forums Discussions General Discussion TDI FILTER driver

This topic contains 61 replies, has 2 voices, and was last updated by  Dmitry_177 10 years, 4 months ago.

Viewing 15 posts - 1 through 15 (of 62 total)
  • Author
    Posts
  • #5108

    Dmitry_177
    Participant

    У меня в драйвере не создается девайс и не аттачится потом к драйверу Tcp.. А перехватывается функция MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] драйвера Tcp. Исходящий трафик(MinorFunction=TDI_SEND) ловится отлично, а вот входящий почему-то нет..:( У кого есть какие соображения?

    #6277

    Vadim Smirnov
    Moderator

    Ну так а что сделано чтобы получать входящий траффик? Обычно входящие данные идут через callbacks, соответственно нужно перехватывать их установку.

    ЗЫ К суппорту тема не имеет отношения, для подобных вопросов есть отдельная борда Windows Internals

    ЗЗЫ Тему отредактировал, следите за кодировкой…

    #6278

    Dmitry_177
    Participant

    Собственно сам перехват:

    в *.h файле:

    PFILE_OBJECT pFile_tcp;
    PDEVICE_OBJECT pDev_tcp;
    PDRIVER_OBJECT pDrv_tcpip;
    
    typedef NTSTATUS (*OLDTCPIRPMJDEVICECONTROL)(IN PDEVICE_OBJECT, IN PIRP);
    OLDTCPIRPMJDEVICECONTROL OldTcpIrpMjDeviceControl;

    в *.с файле:

    UNICODE_STRING deviceTCPUnicodeString;
    WCHAR deviceTCPNameBuffer[]  = L"\\Device\\Tcp";
    
    RtlInitUnicodeString (&deviceTCPUnicodeString, deviceTCPNameBuffer);
    ntStatus = IoGetDeviceObjectPointer(&deviceTCPUnicodeString, FILE_READ_DATA, &pFile_tcp, &pDev_tcp);
    if(!NT_SUCCESS(ntStatus))
       return ntStatus;
    pDrv_tcpip = pDev_tcp->DriverObject;
    
    OldTcpIrpMjDeviceControl = pDrv_tcpip->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL];
    
    if (OldTcpIrpMjDeviceControl)
       InterlockedExchange ((PLONG)&pDrv_tcpip->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL], (LONG)HookedTcpDeviceControl);
    
    ...
    
    NTSTATUS HookedTcpDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
        PIO_STACK_LOCATION      irpStack;
        UCHAR         *mdlBuffer;
    
        irpStack = IoGetCurrentIrpStackLocation (Irp);
        switch (irpStack->MajorFunction)
       {
           case IRP_MJ_INTERNAL_DEVICE_CONTROL:
             if (irpStack->MinorFunction == TDI_SEND)
             {
                DbgPrint("tdifilter TDI_SEND");
    
                mdlBuffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, LowPagePriority);
    
                DbgPrint (mdlBuffer);
             }
    
             if (irpStack->MinorFunction == TDI_RECEIVE)
             {
                DbgPrint("tdifilter TDI_RECEIVE");
    
                mdlBuffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, LowPagePriority);
    
                DbgPrint (mdlBuffer);
             }
    
           break;
          
           default:
           break;
           }
    
        return OldTcpIrpMjDeviceControl(DeviceObject, Irp);
    }

    по идее все должно ловиться и TDI_RECEIVE тоже.. Но почему-то этого не происходит.. Если я захожу на какойнибудь сайт, по идее там должны быть http-пакеты и html страничка.. Но этого почему-то нету..=(

    #6279

    Vadim Smirnov
    Moderator

    Во-первых, до того как будет вызван оригинальный обработчик никаких данных в IRP TDI_RECEIVE нет и быть не может, так как IRP перехвачен на пути от приложения к сети, а не наоборот. Так можно только TDI_SEND поймать.

    Ну а во вторых, большинство TDI клиентов используют не IRPs с TDI_RECEIVE, а устанавливают callbacks на события с использованием TDI_SET_EVENT_HANDLER (в случае с receive это ClientEventReceive). В DDK все написано.

    #6280

    Dmitry_177
    Participant

    По поводу первого я уже сам догадался.. и попробовал вызывать оригинальную функцию в начале, а потом уже смотреть в IRP TDI_RECEIVE..=) Но всеравно и так не работает..

    Спасибо за наводку, буду разбираться..

    #6281

    Dmitry_177
    Participant

    В HookedTcpDeviceControl делаю так:

    if (irpStack->MinorFunction == TDI_SET_EVENT_HANDLER)
    {
       if (((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventType == TDI_EVENT_RECEIVE)
       {
          .....
       }
    }

    Вот где точки, там в ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler по идее содержится адрес callback функции ClientEventReceive. В ней на сколько я понял в параметре Tsdu содержатся принятые данные.. Как можно их вытащить от туда? Подскажите пожалуйста..

    #6282

    Dmitry_177
    Participant

    Нужно перехватывать регистрацию TDI_EVENT_RECEIVE event’а и менять указатель на свой…

    Ловим:

    MajorFunction=IRP_INTERNAL_DEVICE_CONTROL
    MinorFunction=TDI_SET_EVENT_HANDLER
    Parameters->EventType=TDI_EVENT_RECEIVE

    Из DDK я как понял в Parameters->EventHandler будет указатель на callback функцию ClientEventReceive, но как его поменять на свой? может так?:

    OldClientEventReceive = ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler;
    if (OldClientEventReceive)
    {
       ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler =
    
    HookedClientEventReceive;
    }

    А еще тогда в HookedClientEventReceive нужно вызывать оригинал:

    return OldClientEventReceive(TdiEventContext,
                        ConnectionContext,
                        ReceiveFlags,
                        BytesIndicated,
                        BytesAvailable,
                        BytesTaken,
                        Tsdu,
                        IoRequestPacket);

    Как тогда все оригинальные адреса callback функций сохранять для разных потоков вызвавших TDI_SET_EVENT_HANDLER чтобы потом их вызывать в HookedClientEventReceive? Или может есть какойнибудь способ передавать этот адрес в саму функцию HookedClientEventReceive?

    #6283

    Vadim Smirnov
    Moderator

    IrpSp->FileObject
    Pointer to an open file object representing a local-node address. The transport uses the FsContext and, possibly, FsContext2 fields to access the state it maintains about this address.
    Depending on the type of ClientEventXxx handler to be registered, this address might be or become associated with an established endpoint-to-endpoint connection made by this client.

    Хендлеры ставятся в контексте address object, то есть сохранять подменять нужно не для разных потоков, а для разных address object.

    IrpSp->Parameters
    Pointer to a TDI_REQUEST_KERNEL_SET_EVENT structure, defined as follows:
    struct _TDI_REQUEST_KERNEL_SET_EVENT {
    LONG EventType;
    PVOID EventHandler;
    PVOID EventContext;
    } TDI_REQUEST_KERNEL_SET_EVENT, *PTDI_REQUEST_KERNEL_SET_EVENT;
    The transport uses the members of this structure as follows:

    EventType
    Specifies the type of ClientEventXxx handler to be registered (see Comments).
    EventHandler
    Specifies the entry point of the ClientEventXxx routine to be called when this type of event occurs. This member can be NULL if the client is deregistering a previously registered event handler.
    EventContext
    Specifies a pointer to be passed, uninterpreted by the transport, to the given ClientEventXxx routine whenever it is called. This member is NULL if EventHandler is NULL.

    Можно подменить EventContext на некую собственную структуру оборачивающую address object и содержащую указатель на оригинальный ClientEventReceive.

    P.S. А вообще вместо изобретения велосипеда стоило заглянуть в Resources и сходить по ссылке http://sourceforge.net/projects/tdifw

    #6284

    Dmitry_177
    Participant

    Что-то я не пойму.. а как тогда хранить для каждого address object свой оригинал callback функции? и потом еще в самой callback функции определять какой оригинал вызывать..

    tdi_fw-а я смотрел исходники..

    #6285

    Vadim Smirnov
    Moderator

    Что-то я не пойму.. а как тогда хранить для каждого address object свой оригинал callback функции? и потом еще в самой callback функции определять какой оригинал вызывать..

    Честно говоря, если после моего предыдущего пояснения остались вопросы, то может тогда не стоит и браться за подобный проект? Лучше возьмите за основу что-нибудь готовое, иначе на написание первого стабильного драйвера потратите уйму времени Да и TDI в Vista уже depreciated, так что стоит ли напрягаться…
    🙄

    Распишу что я имел ввиду. Для каждого address object аллокируем некую структуру, которую храним у себя например в списке. В этой структур помимо прочих полей, которые могут понадобится, мы сохраняем оригинальный адрес ClientEventReceive и оригинальный контекст, который должен быть в нее передан. В обработчике TDI_SET_EVENT_HANDLER с TDI_EVENT_RECEIVE подменяем оригинальную ClientEventReceive и контекст заменяем на адрес той структуры, которая у нас оборачивает address object. Соответсвенно, в новом обработчике ClientEventReceive имеем указатель на структуру с оригинальным обработчиком и контекстом. Теперь понятно? 8)

    #6286

    Dmitry_177
    Participant

    Спасибо за разъяснение…

    Я уже спрашивал, так правильно будет перехватывать?

    OldClientEventReceive = ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler;
    if (OldClientEventReceive)
    {
       ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler = HookedClientEventReceive;
    }

    Ну и соответственно и контекст еще так же присвоить…

    А еще, подскажете пожалуйста как в драйвере хранить список? Вроде как на уровне ядра подругому все, другие функции и т.д…

    З.Ы. я не так давно изучаю ring0, многого еще не знаю.. 😳

    #6287

    Vadim Smirnov
    Moderator

    Я уже спрашивал, так правильно будет перехватывать?

    Да

    Ну и соответственно и контекст еще так же присвоить…

    Да

    А еще, подскажете пожалуйста как в драйвере хранить список

    Можешь свой список сделать. Можешь использовать встроенные односвязные или двухсвязные. Смотри функции:


    InitializeListHead, ExInterlockedInsertHeadList, ExInterlockedInsertTailList, ExInterlockedRemoveHeadList, ExInterlockedPopEntryList, ExInterlockedPushEntryList, InsertHeadList, InsertTailList, IsListEmpty, KeInitializeSpinLock, PopEntryList, PushEntryList, RemoveEntryList, RemoveHeadList, RemoveTailList
    #6288

    Dmitry_177
    Participant

    Спасибо большое 🙂 Вы очень добры.. Буду разбираться..

    #6289

    Dmitry_177
    Participant

    Реализовал что-то наподобии, но у меня опять же таки не ловятся входящие пакеты и еще синий экран появляется.. Выложу весь код:

    в *.h файле:

    typedef NTSTATUS (*OLDCLIENTEVENTRECEIVE)(IN PVOID,
                                    IN CONNECTION_CONTEXT,
                                    IN ULONG,
                                    IN ULONG,
                                    IN ULONG,
                                    OUT ULONG,
                                    IN PVOID,
                                    OUT PIRP);
    
    // структура про которую мы говорили
    typedef struct _CLIENTEVENTRECEIVECONTEXT
    {
       LIST_ENTRY   ListEntry;
       PVOID      EventHandler;
       PVOID      EventContext;
    } CLIENTEVENTRECEIVECONTEXT, *PCLIENTEVENTRECEIVECONTEXT;

    полный код драйвера в *.c файле

    #include "ntddk.h"
    #include "TdiKrnl.h"
    #include "main.h"
    
    PPAGED_LOOKASIDE_LIST   g_pPagedLookasideList;
    LIST_ENTRY            g_ClientEventReceiveListHead;
    KSPIN_LOCK            g_ClientEventReceiveListLock;
       
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT  DriverObject,
                    IN PUNICODE_STRING RegistryPath)
    {
       OldTcpIrpMjDeviceControl = NULL;
    
       g_pPagedLookasideList = ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
    
       ExInitializePagedLookasideList(g_pPagedLookasideList, NULL, NULL, 0, sizeof(CLIENTEVENTRECEIVECONTEXT), 'tdis', 0);
    
       InitializeListHead(&g_ClientEventReceiveListHead);
       KeInitializeSpinLock(&g_ClientEventReceiveListLock);
    
       DriverObject->DriverUnload = OnUnload;
    
       return InstallDriverHook();
    }
    
    NTSTATUS InstallDriverHook()
    {
        NTSTATUS       ntStatus;     
       UNICODE_STRING deviceTCPUnicodeString;
       WCHAR deviceTCPNameBuffer[]  = L"\\Device\\Tcp";
        pFile_tcp  = NULL;
       pDev_tcp   = NULL;
       pDrv_tcpip = NULL;
    
       RtlInitUnicodeString (&deviceTCPUnicodeString, deviceTCPNameBuffer);
       ntStatus = IoGetDeviceObjectPointer(&deviceTCPUnicodeString, FILE_READ_DATA, &pFile_tcp, &pDev_tcp);
       if(!NT_SUCCESS(ntStatus))
          return ntStatus;
       pDrv_tcpip = pDev_tcp->DriverObject;
    
       OldTcpIrpMjDeviceControl = pDrv_tcpip->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL];
       if (OldTcpIrpMjDeviceControl)
          pDrv_tcpip->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HookedTcpDeviceControl;      
          //InterlockedExchange ((PLONG)&pDrv_tcpip->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL], (LONG)HookedTcpDeviceControl);
    
       return STATUS_SUCCESS;
    }
    
    NTSTATUS HookedTcpDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
        PIO_STACK_LOCATION         irpStack;
       UCHAR                  *mdlBuffer;
       PCLIENTEVENTRECEIVECONTEXT   pBlockFromPagedLookasideList;
       KIRQL                  irql;
    
        irpStack = IoGetCurrentIrpStackLocation (Irp);
    
        switch (irpStack->MajorFunction)
       {
           case IRP_MJ_INTERNAL_DEVICE_CONTROL:
             if (irpStack->MinorFunction == TDI_SEND)
             {
                DbgPrint("tdi_sniffer TDI_SEND:");
    
                mdlBuffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, LowPagePriority);
    
                DbgPrint (mdlBuffer);
             }
    
             if (irpStack->MinorFunction == TDI_SET_EVENT_HANDLER)
             {
                if (((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventType == TDI_EVENT_RECEIVE)
                {
                   DbgPrint("tdi_sniffer TDI_SET_EVENT_HANDLER -> TDI_EVENT_RECEIVE");
    
                   pBlockFromPagedLookasideList = ExAllocateFromPagedLookasideList(g_pPagedLookasideList);
    
                   memset(pBlockFromPagedLookasideList, 0, sizeof(CLIENTEVENTRECEIVECONTEXT));
    
                   KeAcquireSpinLock(&g_ClientEventReceiveListLock, &irql);
    
                   InsertHeadList(&g_ClientEventReceiveListHead, &pBlockFromPagedLookasideList->ListEntry);
    
                   // ñîõðàíÿåì îðèãèíàë ôóíêöèè â ñòðóêòóðå
                   pBlockFromPagedLookasideList->EventHandler = ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler;
    
                   // ñîõðàíÿåì îðèãèíàë êîíòåêñòà â ñòðóêòóðå
                   pBlockFromPagedLookasideList->EventContext = ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventContext;
    
                      
                   ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler = HookedClientEventReceive;
                   ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventContext = pBlockFromPagedLookasideList;
    
                   KeReleaseSpinLock(&g_ClientEventReceiveListLock, irql);
    
                   DbgPrint("tdi_sniffer ClientEventReceive Hooked...");
                }
             }
    
          break;
          
          default:
          break;
        }
    
       return OldTcpIrpMjDeviceControl(DeviceObject, Irp);
    }
    
    NTSTATUS HookedClientEventReceive(IN PVOID  TdiEventContext,
                              IN CONNECTION_CONTEXT  ConnectionContext,
                              IN ULONG  ReceiveFlags,
                              IN ULONG  BytesIndicated,
                              IN ULONG  BytesAvailable,
                              OUT ULONG  *BytesTaken,
                              IN PVOID  Tsdu,
                              OUT PIRP  *IoRequestPacket)
    {
       UCHAR   *sduBuffer;
    
       PCLIENTEVENTRECEIVECONTEXT   pBlockFromPagedLookasideList;
       OLDCLIENTEVENTRECEIVE      OldClientEventReceive;
    
       pBlockFromPagedLookasideList = TdiEventContext; // â TdiEventContext ïî èäåå ñîäåðæèòñÿ óêàçàòåëü íà ìîþ ñòðóêòóðó
       OldClientEventReceive = pBlockFromPagedLookasideList->EventHandler;
    
       sduBuffer = Tsdu;
       DbgPrint("tdi_sniffer TDI_RECEIVE:");
       DbgPrint(sduBuffer); // íåçíàþ êàê âûòàùèòü ïðèíÿòûå ïàêåòû èç Tsdu, åñëè îíè òàì íàõîäÿòñÿ èëè åùå ãäå, èç DDK ÿ ÷òî-òî íå ïîíÿë ãäå èìåííî îíè ñîäåðæàòñÿ
    
       // âûçûâàåì îðèãèíàë ôóíêöèè
       return OldClientEventReceive(pBlockFromPagedLookasideList->EventContext,
                             ConnectionContext,
                             ReceiveFlags,
                             BytesIndicated,
                             BytesAvailable,
                             *BytesTaken,
                             Tsdu,
                             *IoRequestPacket);
    }
    
    NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)
    {
       if (OldTcpIrpMjDeviceControl)
          InterlockedExchange ((PLONG)&pDrv_tcpip->MajorFunction[IRP_MJ_DEVICE_CONTROL], (LONG)OldTcpIrpMjDeviceControl);   
       if (pFile_tcp != NULL)
          ObDereferenceObject(pFile_tcp);
       pFile_tcp = NULL;
    
       return STATUS_SUCCESS;
    }

    Выгрузку списка и проверку на существующий в нем элемент я еще пока не делал, так что не обращайте на это внимания.. Подскажите пожалуйста правильно ли я понял суть со своей структурой и правильно ли я делаю? Почему-то всеравно не показываются входящие пакеты, даже DbgPrint(“tdi_sniffer TDI_RECEIVE:”); не показывается.. И подскажите пожалуйста как вытащить принятые пакеты и от куда их вообще нужно вытаскивать, из Tsdu?

    #6290

    Dmitry_177
    Participant

    SerpentFly, помоги пожалуйста.. Все что я смог сделать я отобразил это в коде.. Я реально зашел в тупик.. Помоги пожалуйста..

Viewing 15 posts - 1 through 15 (of 62 total)

You must be logged in to reply to this topic.