Перехват ClientEventReceive

Тема в разделе "WASM.NT.KERNEL", создана пользователем Dmitry_177, 19 июл 2007.

  1. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Делаю перехват ClientEventReceive.. Но почему-то при вызове оригинальной функции:
    Код (Text):
    1.     ntStatus = OldClientEventReceive(pBlockFromPagedLookasideList->EventContext,
    2.                      ConnectionContext,
    3.                      ReceiveFlags,
    4.                      BytesIndicated,
    5.                      BytesAvailable,
    6.                      BytesTaken,
    7.                      Tsdu,
    8.                      IoRequestPacket);
    выскакивает BSOD.. Подскажите пожалуйста, немогу я разобраться.. анализ дампа показывает следующее:

    tdifilter_testdriver.sys это и есть мой драйвер.. Никак не пойму почему ошибка на IoRequestPacket???
     
  2. TarasCo

    TarasCo New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2005
    Сообщения:
    106
    Похоже, OldClientEventReceive у Вас указывает куда то в неправильное место, иначе мы бы видели в стеке драйвер afd.sys или netbt.sys. Попробуйте трассировать в отладчике место вызова OldClientEventReceive.

    :)))
    отладчик Вам указывает на вызов ф. OldClientEventReceive, это же ее последний параметр, не так ли?
     
  3. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Правильно указывает.. перед тем как сделать перехват, выводил адрес в DbgPrint, а потом при вызове оригинала опять выводил адрес OldClientEventReceive.. Они совпадают!
     
  4. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Вообще в TDI_SET_EVENT_HANDLER в IrpSp->Parameters содержится структура
    Код (Text):
    1. struct _TDI_REQUEST_KERNEL_SET_EVENT {
    2.     LONG EventType;
    3.     PVOID EventHandler;
    4.     PVOID EventContext;
    5. } TDI_REQUEST_KERNEL_SET_EVENT, *PTDI_REQUEST_KERNEL_SET_EVENT;
    в EventHandler содержится адрес оригинальной ClientEventReceive? Собственно я и задаю в TDI_SET_EVENT_HANDLER адрес своей функции в EventHandler:

    Код (Text):
    1. ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventHandler = HookedClientEventReceive;
    А в EventContext задаю адрес на свою структуру, в которой хранится адрес оригинального контекста и функции:

    Код (Text):
    1. ((PTDI_REQUEST_KERNEL_SET_EVENT)&irpStack->Parameters)->EventContext = pBlockFromPagedLookasideList;
    Сам перехват проихродит.. данные Tsdu вывожу и все принятые данные показывается в DbgPrint, но при вызове оригинальной ClientEventReceive система падает... Вот никак не могу понять почему...
     
  5. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Блин!!! Разобрался :) TarasCo все правильно сказал, я действительно неправильно адрес передавал..

    Подскажите пожалуйста еще про TDI_EVENT_RECEIVE_DATAGRAM, когда это устанавливается? Что за датаграммы? Используются ли они при обычном лазании по сайтам, использования аськи, всяких других программ общения и всяких почтовых программ? Что-то не совсем понимаю что за датаграммы такие..
     
  6. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    перехватываю еще ClientEventChainedReceive сам перехват срабатывает, но данные почему-то из Tsdu немогу вытянуть.. Делаю так:
    Код (Text):
    1. NTSTATUS HookedClientEventChainedReceive(IN PVOID               TdiEventContext,
    2.                                          IN CONNECTION_CONTEXT  ConnectionContext,
    3.                                          IN ULONG               ReceiveFlags,
    4.                                          IN ULONG               ReceiveLength,
    5.                                          IN ULONG               StartingOffset,
    6.                                          IN PMDL                Tsdu,
    7.                                          IN PVOID               TsduDescriptor)
    8. {
    9.     UCHAR       *sduBuffer;
    10.  
    11.     DbgPrint("tdi_sniffer: -------***BEGIN TDI_EVENT_CHAINED_RECEIVE***-------\n");
    12.     sduBuffer = MmGetSystemAddressForMdlSafe (Tsdu, LowPagePriority);
    13.     DbgPrint(sduBuffer);
    14.     DbgPrint("tdi_sniffer: --------***END TDI_EVENT_CHAINED_RECEIVE***--------\n");
    15.  
    16.     return ((OLDCLIENTEVENTCHAINEDRECEIVE)((PCLIENTEVENTRECEIVECONTEXT)TdiEventContext)->EventHandler)(((PCLIENTEVENTRECEIVECONTEXT)TdiEventContext)->EventContext,
    17.                                                                                                        ConnectionContext,
    18.                                                                                                        ReceiveFlags,
    19.                                                                                                        ReceiveLength,
    20.                                                                                                        StartingOffset,
    21.                                                                                                        Tsdu,
    22.                                                                                                        TsduDescriptor);
    23. }
    т.к. в Tsdu содержится MDL адрес, вытягиваю данные функцией MmGetSystemAddressForMdlSafe.. и почему-то никакие принятые данные не отображаются..
     
  7. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    неужели никто не знает???
     
  8. TarasCo

    TarasCo New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2005
    Сообщения:
    106
    TDI_EVENT_RECEIVE_DATAGRAM - этот обработчик используют датаграммные протоколы. Обычно это UDP или IP ( сырой сокет ). Соотвественно, при "обычном лазании по сайтам" используется TCP протокол, который не является датаграммным и данный обработчик не нужен

    По поводу ClientEventChainedReceive: Вы берете данные сразу сначала буфера, а там скорее всего заголовки протоколов. К началу буфера нужно прибавить параметр StartingOffset, чтобы получить указатель на данные.
     
  9. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Если хоть даже и заголовки протоколов, отображаться то они должны же...

    А еще я так делал, прибавлял:

    Код (Text):
    1. sduBuffer = MmGetSystemAddressForMdlSafe (Tsdu + StartingOffset, LowPagePriority);
    BSOD сразуже..
     
  10. TarasCo

    TarasCo New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2005
    Сообщения:
    106
    По Вашему DbgPrint волшебная функция, отображающая любые типы данных? Она всего лишь выводит строку печтатаемых символов, заканчивающуюся нулем-терминатором. Если StartingOffset != 0, начало буфера можно считать случайным и первым символом может быть например ноль ( это, кстати, очень-очень вероятно :) ) - что должно выводиться?

    Еще бы не было BSOD а :). Нужно делать примерно так:
    Код (Text):
    1. UCHAR       *sduBuffer;
    2. sduBuffer = MmGetSystemAddressForMdlSafe (Tsdu, LowPagePriority);
    3. sduBuffer += StartingOffset;
     
  11. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    TarasCo
    Подскажи еще пожалуйста, а в каких случаях возникает TDI_EVENT_CHAINED_RECEIVE? Что-то я не пойму никак из DDK.. Скажи пример пожалуйста.. И тоже касается TDI_EVENT_RECEIVE_EXPEDITED..

    Вот при лазании по сайтам, использования аськи и всяких других программ для общения, и всяких там почтовых клиентов.. Какие event-ы используются и в каких именно событиях и при каких именно приеме данных? Подскажи пожалуйста, т.к. я не очень это понимаю из DDK..
     
  12. TarasCo

    TarasCo New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2005
    Сообщения:
    106
    Всю механику описывать долго. Вам нужно перехватывать данные, передаваемые по TCP соединению? ТОгда Вам нужны три перехватчика:
    1. Диспетчерский запрос TDI_RECEIVE. Его засылает драйвер afd, если клиентское приложение вызвало ф. recv и драйвер afd знает, что у tcpip есть данные ( до этого срабатывали нотификаторы типа ClientEventReceive ).
    2. ClientEventReceive - драйвер tcpip зовет этот нотификатор для извещения о том, что есть принятые данные
    3. ClientEventChainedReceive - вызывается в тех же случаях, что и ClientEventReceive, служит для оптимизации. Упрощенно говоря, если пришел TCP пакет, который не требует дополнительной обработки для сборки потока данных, его могут сразу прокинуть вверх клиенту - и если клиент не ступит, это позволит избежать лишних копирований данных.

    Что нужно учитывать:
    1. Драйвер afd очень часто возвращает STATUS_DATA_NOT_ACCEPTED - это не значит, что ему не нужны данные, это значит, что он заберет их позже с помощью запроса TDI_RECEIVE.
    2. Нотификаторы вызваются только в том случае, если у драйвера tcpip нет необработанного запроса TDI_RECEIVE.
    Т.е если наблюдать только за ClientEventReceive и ClientEventChainedReceive - можно не увидеть всех данных. Запрос TDI_RECEIVE может передаваться в возвращаемом параметре ф. ClientEventReceive, а может и через диспетчер IRP_MJ_INTERNAL_DEVICE_CONTROL
     
  13. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Я делал перехват TDI_RECEIVE:
    Код (Text):
    1.     switch (irpStack->MajorFunction)
    2.     {
    3.         case IRP_MJ_INTERNAL_DEVICE_CONTROL:
    4.             if (irpStack->MinorFunction == TDI_RECEIVE)
    5.             {
    6.                 ntStatus = OldTcpIrpMjDeviceControl(DeviceObject, Irp);   // вызов оригинальной функции
    7.  
    8.                 DbgPrint("tdi_sniffer: -------***BEGIN TDI_RECEIVE***-------\n");
    9.                 mdlBuffer = MmGetSystemAddressForMdlSafe (Irp->MdlAddress, LowPagePriority);
    10.                 DbgPrint(mdlBuffer);
    11.                 DbgPrint("\n");
    12.                 DbgPrint("tdi_sniffer: --------***END TDI_RECEIVE***--------\n");
    13.  
    14.                 return ntStatus;
    15.             }
    Токо у меня ничего не пишется.. :)

    Скажи еще пожалуйста, а как тогда выводить строки в которых есть нули-терминанты, но которые не заканчиваются на них? Вот например с использованием моего этого драйвера при открытии странички в браузере, я почему-то вижу только HTTP заголовки, а принятую html-ку(которая по идее должна идти после заголовка) не вижу, иногда, очень редко проскочит какой-нибудь маленький кусочек html-ки.. А еще часто бывает просто абра-кадабра какая-то пишется...
     
  14. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Все же всеравно мне не понятно...:dntknw:
     
  15. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    TarasCo, еще как-то не понятно как скачиваются сами картинки.. вот к примеру html-ка скачивается а сами фотки и др. как?
     
  16. TarasCo

    TarasCo New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2005
    Сообщения:
    106
    картинки обычно скачиваются через другие соединения. Т.е броузер скачав главный html файл начинает его парсить и подгружать дополнительный контент. Разные броузеры это делают по разному - открывают различное количество соединений ( по одному соединению могут и несколько картинок передать ).
     
  17. Dmitry_177

    Dmitry_177 New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2007
    Сообщения:
    75
    Сравнил я что у меня приходит в ethereal-е (сниффере) и что отображает мой драйвер.. а принципе все тоже самое(по TCP трафику) но у меня все также не полностью высвечиваются данные, вот например: при открытии в IE www-страницы мой драйвер пишет:

    и все, на этом обрыв данных хотя дальше тоже должно все быть.. а в ethereal-е все тоже самое т.е. начало тоже но там и продолжение есть..