Есть в Win-де такая штука как filter-hook driver,
которая может занимаеться фильтрацией IP-пакетов.
В драйвере регистрируется так называемая filter-hook callback function,
которая выглядит примерно так:
убедительная просьба использовать таги ccode & asm для соотв. кусков кода — модератор
вызываеются слдеующая группа функций
ZwDeviceIoControlFile
ZwOpenProcess
ZwQueryInformationProcess
ZwOpenProcessToken
ZwQueryInformationToken
ZwCreateFile
ZwDeviceIoControlFile
ZwWriteFile
ZwReadFile
ZwClose
которые работаю на уровне IRQL 0 (PASSIVE_LEVEL),
а KeGetCurrentIrql показывает что уровень IRQL есть 2 (DISPATCH_LEVEL)
и естественно получаю синий экран с IRQL_NOT_LESS_OR_EQUAL.
Как быть, как заставить выполится этому участку кода?
Дело в том, что значение action, то что должна вернуть filter-hook callback function,
зависит как раз от того, как обработаются данные из пакета в этом уастке кода.
На сколько я понимаю понизить IRQL в 0 перед //begin smthcode
а потом обратно повысить в 2 после //end smthcode нельзя? Как же поступить?
вообще то, желательно так не делать.
А вы можете объяснить какие данные вы пытаетесь вытянуть из пакета?
ZwQueryInformationToken
По видимому пытаетесь получить SID usera процесса в контекcте которого передается/принимается пакет; так вот я скажу, что ничего не получится для incoming packets там случайный контекст; хотя для outgoing packets там вроде верный контекст, кто передает, того и контекст.
ZwDeviceIoControlFile
Это вообще непонятно зачем
ZwCreateFile
ZwWriteFile
ZwReadFile
ZwClose
Работу с этими функциями надо организовать в отдельном потоке, я так понимаю это для логирования.
Эти функции нужны для определения других вещей на основе данных полученых из пакета.
Логирование тоже присутсвует .
Так что, предлагаете весь этот участок кода перекинуть в другой поток?
Может и пример подкините, как в потоке с IRQL=2 получать данные из потока с IRQL=0?
А>Эти функции нужны для определения других вещей на основе данных полученых из пакета.
В общем, мне неизвестно что там вам надо получить, поэтому ничего советовать не буду.
А>Логирование тоже присутсвует :).
Вот по поводу логирования. Это дело надо однозначно перенести в отдельный поток.
1. Где нибудь в DriverEntry...
//Создаем поток
PsCreateSystemThread(&hLogThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, (PKSTART_ROUTINE)LogThreadFunction, NULL);
//Также инициализируем очередь (стандартная работа с LIST_ENTRY очередями)
//элементами очереди будут структуры типа LOG_RECORD (см. ниже)
InitializeListHead(&LogListHead);
// SpinLock для очереди
KeInitializeSpinLock(&LogListLock);
2. В сетевом фильтре:
PF_FORWARD_ACTION
hook_proc(
unsigned char *PacketHeader,
unsigned char *Packet,
unsigned int PacketLength,
unsigned int RecvInterfaceIndex,
unsigned int SendInterfaceIndex,
ULONG RecvLinkNextHop,
ULONG SendLinkNextHop
)
{
PF_FORWARD_ACTION action;
//...
// здесь добавляем элемент в очередь со всей необходимой информацией для логирования
//...return action;
}
3. В LogThreadFunction (Ф-ция LogThreadFunction будет выполняться на IRQL = PASSIVE_LEVEL, так что проблем с повышенным IRQL не будет)
Вот, например, самая простая реализация
VOID LogpThreadProcedure( IN PVOID StartContext )
{
PLOG_RECORD pLogRecord = NULL;
///////////////////////////////////////////////////////////////////////////////
//log thread cyclewhile(!bLogFlushDiskShutdown) {
//шаримся по списку, пока есть в нем элементы и сбрасываем инфу на дискwhile ( (pLogRecord = LogGetFirstRecordList()) )
{
//сбрасываем инфу на диск
LogFlushToDisk(...);
//удаляем элемент из очереди
LogRemoveRecordList(pLogRecord);
}
//здесь говорим потоку спать 5c
SleepLogThread();
}
///////////////////////////////////////////////////////////////////////////////
// - вот тут я не уверен нужна ли здесь эта ф-ция, в примерах MSDN она используется,
//но у меня и без нее все нормально работает
//т.е. вопрос к знатокам: "При выходе из потока нужно ли вызыватьPsTerminateSystemThread?"
//по логике - не нужно, но там кто его знает...
PsTerminateSystemThread( STATUS_SUCCESS );
}
}
структура LOG_RECORD буде иметь вид:
typedef struct _LOG_RECORD {
LIST_ENTRY Entry;
LARGE_INTEGER LogTimeStamp;
//здесь любая инфа на ваш вкус: ip-адреса, порты и т.п.
}LOG_RECORD, *PLOG_RECORD;
Ф-ции по работе с очередью (LogRemoveRecordList, LogGetFirstRecordList) и другие ф-ции (LogFlushToDisk, SleepLogThread) напишите сами.
Ну что ж, let's go!
А>>Эти функции нужны для определения других вещей на основе данных полученых из пакета.
O>В общем, мне неизвестно что там вам надо получить, поэтому ничего советовать не буду.
ZwCreateFile
ZwDeviceIoControlFile
Эти функции используются для получения структур MIB_TCP_RAW и MIB_UDP_RAW от TCPIP драйвера
посылая ему IOCTL_TCP_QUERY_INFORMATION_EX.
ZwOpenProcess
ZwQueryInformationProcess
ZwOpenProcessToken
ZwQueryInformationToken
Эти функции используются для получения имени файла запущеного процеса по заданому PID и
SID юзера запустившего его.
Итого, надо получать эту инфу на каждый прием/посылка IP пакета и спать 5 секунд нельзя .
Еслиб не этот случай, что callback функция работает на IRQL=2 ... наверное все былоб хорошо .
Конечно такая схема работы на первый взгляд не есть хороший вариант. Но иметь на любой момент времени
табличку запущенных процессов в системе, чтобы на каждый IP пакет получать инфу по заданному PID процесса
пока не представляется возможным... Работать ведь надо этой filter-hook callback function быстро...
Re[5]: Выполнить код в PASSIVE_LEVEL.
От:
Аноним
Дата:
27.01.07 09:49
Оценка:
DKG>Конечно такая схема работы на первый взгляд не есть хороший вариант. Но иметь на любой момент времени DKG>табличку запущенных процессов в системе, чтобы на каждый IP пакет получать инфу по заданному PID процесса DKG>пока не представляется возможным... Работать ведь надо этой filter-hook callback function быстро...
Наивно думаете что все это будет работать быстрее одной несчастной мапы?
Здравствуйте, Аноним, Вы писали:
DKG>>Конечно такая схема работы на первый взгляд не есть хороший вариант. Но иметь на любой момент времени DKG>>табличку запущенных процессов в системе, чтобы на каждый IP пакет получать инфу по заданному PID процесса DKG>>пока не представляется возможным... Работать ведь надо этой filter-hook callback function быстро... А>Наивно думаете что все это будет работать быстрее одной несчастной мапы?
Пока не представляю как все это должно работать.
По подробней можете сказать, что вы имеете в виду?
Здравствуйте, DimanKGKZ, Вы писали:
DKG>ZwCreateFile DKG>ZwDeviceIoControlFile DKG>Эти функции используются для получения структур MIB_TCP_RAW и MIB_UDP_RAW от TCPIP драйвера DKG>посылая ему IOCTL_TCP_QUERY_INFORMATION_EX.
Это можно заменить на посылку IRP соответствующему устройству. Работать будет на DISPATCH_LEVEL
DKG>ZwOpenProcess DKG>ZwQueryInformationProcess DKG>ZwOpenProcessToken DKG>ZwQueryInformationToken DKG>Эти функции используются для получения имени файла запущеного процеса по заданому PID и DKG>SID юзера запустившего его.
По поводу PID-SID Вам ответили в соседней ветке. Держать список процессов IMHO оптимальный вариант.
TC>По поводу PID-SID Вам ответили в соседней ветке. Держать список процессов IMHO оптимальный вариант.
Схемку такой работы не нарисуете? Что есть мапа ?
В своем же драйвере организовать перехват создания/унмичтожения процессов с помощью PsSetCreateProcessNotifyRoutine() ?
А как будут общаться filter-hook callback function и функция перхвата создания/процессов? Если есть такой способ через ту самую мапу,
почемубы тогда не отлавливать создание/уничтожение процессов, а выполнить в этом месте
ZwOpenProcess
ZwQueryInformationProcess
ZwOpenProcessToken
ZwQueryInformationToken
а за одно и
ZwCreateFile
ZwDeviceIoControlFile
Дело в том что кроме списка процессов необходимо еще и знать какие TCP, UDP порты они занял.
А если процесс закрыл порт и через полчаса открыл другой? Есть способ отловить?
Как же поток на irgl=2 синхронизировать с потоком на irql=0?
Здравствуйте, TarasCo, Вы писали:
TC>Здравствуйте, DimanKGKZ, Вы писали:
DKG>>ZwCreateFile DKG>>ZwDeviceIoControlFile DKG>>Эти функции используются для получения структур MIB_TCP_RAW и MIB_UDP_RAW от TCPIP драйвера DKG>>посылая ему IOCTL_TCP_QUERY_INFORMATION_EX.
TC>Это можно заменить на посылку IRP соответствующему устройству. Работать будет на DISPATCH_LEVEL
Если из одного драйвера послать IRP на DISPATCH_LEVEL другому драйверу, то функция обработки IRP пакетов
во втором драйвере тоже будет работать на DISPATCH_LEVEL ?
Здравствуйте, DimanKGKZ, Вы писали:
DKG>во втором драйвере тоже будет работать на DISPATCH_LEVEL ?
Ну естественно. При вызове IoCallDriver IRP прямиком попадет в диспетчерский обработчик. Если до вызова IoCallDriver IRQL = DISPATCH_LEVEL, то понизиться он никак не может.
Здравствуйте, DimanKGKZ, Вы писали:
DKG>В своем же драйвере организовать перехват создания/унмичтожения процессов с помощью PsSetCreateProcessNotifyRoutine() ?
можно
DKG>А как будут общаться filter-hook callback function и функция перхвата создания/процессов?
Вот тут-то и засада.
Вы из filter-hook callback function не можете привязаться к конкретному процессу, чтобы определить кто послал/принял пакет, потому как для incoming packets там случайный контекст; хотя для outgoing packets там вроде верный контекст, кто передает, того и контекст. — я это уже говорил.
В общем нет общего идентификатора, по которому можно связать очередь процессов и процессов, которые осуществляют передау данных по сети...
Хотя стоп! подождите... В принципе, для TCP и UDP можно по адресам и портам.
1. По хорошему, нужен TDI filter.
2. Но по плохому подойдет и посылка IRP (IOCTL_TCP_QUERY_INFORMATION_EX) к \Device\Tcp (TarasCo говорил). Получите таблицу tcp соединений. Осуществите поиск в таблице на предмет наличия требуемого адреса и порта (т.е. тот адрес и порт, котрые пришли в пакете) в таблице tcp. Если найдете, то pid тоже известен из табл. tcp. Ну а если pid, известен, то это дело легко можно связать со списком процессов который вы создаете с помощью PsSetCreateProcessNotifyRoutine.
DKG>А если процесс закрыл порт и через полчаса открыл другой? Есть способ отловить?
TDI — для w2k, wxp, w2k3; WFP — Vista. Но в Vista какой-то бок, там по этому callback'у FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4 можно отлавливать момент создания адресного объекта/соединения, но как отлавливать момент его закрытия неизвестно.
Здравствуйте, onyx2, Вы писали:
O>TDI — для w2k, wxp, w2k3; WFP — Vista. Но в Vista какой-то бок, там по этому callback'у FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4 можно отлавливать момент создания адресного объекта/соединения, но как отлавливать момент его закрытия неизвестно.
Я думаю, на уровне фильтрации ресурсов это невозможно, но можно на уровне фильтрации потоков данных. Тогда в classifyFn можно задать контекст через вызов FwpsFlowAssociateContext0, который будет потом передан в flowDeleteFn — так наверное можно отследить завершение например устанвленного соединения.
Здравствуйте, TarasCo, Вы писали:
TC>Я думаю, на уровне фильтрации ресурсов это невозможно, но можно на уровне фильтрации потоков данных. Тогда в classifyFn можно задать контекст через вызов FwpsFlowAssociateContext0, который будет потом передан в flowDeleteFn — так наверное можно отследить завершение например устанвленного соединения.
Здравствуйте, TarasCo, Вы писали:
TC>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 TC>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6
TC>Я сам не пробовал :)
А я пробовал. Данные callback'и отхватывают момент установки соединения (ну это понятно, даже название соответствующее).
А вот disconnect'а как такового нет. Его можно определить в callback'е FWPM_LAYER_STREAM_V4/FWPM_LAYER_STREAM_V6 по приходящим в него флагам. Что-то типа этого:
void CoutTcpClassifyStream(
IN const FWPS_INCOMING_VALUES0* inFixedValues,
IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
IN OUT void* layerData,
IN const FWPS_FILTER0* filter,
IN UINT64 flowContext,
OUT FWPS_CLASSIFY_OUT0* classifyOut
)
{
FWPS_STREAM_CALLOUT_IO_PACKET0* streamPacket = (FWPS_STREAM_CALLOUT_IO_PACKET0*)layerData;
do {
if (!streamPacket || !streamPacket->streamData) { break; }
if ( (streamPacket->streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) ||
(streamPacket->streamData->flags & FWPS_STREAM_FLAG_SEND_ABORT) ) {
//disconnect on send
}
if ( (streamPacket->streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT) ||
(streamPacket->streamData->flags & FWPS_STREAM_FLAG_RECEIVE_ABORT) ) {
//disconnect on receive
}
} while(0);
if (classifyOut) {
classifyOut->actionType = FWP_ACTION_CONTINUE;
classifyOut->flags = 0;
}
}
TC>Я думаю, на уровне фильтрации ресурсов это невозможно, но можно на уровне фильтрации потоков данных. Тогда в classifyFn можно задать контекст через вызов FwpsFlowAssociateContext0, который будет потом передан в flowDeleteFn — так наверное можно отследить завершение например устанвленного соединения.
Я много callback'ов протестировал и единственный callback для которого flowdeleteFn имеет значение это FWPM_LAYER_STREAM. В принципе и там можно ловить disconnect. Т.е. получается когда в stream'е происходит disconnect, то затем автоматически вызывается flowDeleteFn для stream'а.
Connect/Disconnect удалось как-то отловить.
А вот Open/Close addr. object не удалось (то что было в TDI — IRP_MJ_CREATE/IRP_MJ_CLOSE). И никаких идей нет.
Здравствуйте, onyx2, Вы писали:
TC>>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 TC>>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6
TC>>Я сам не пробовал
O>А я пробовал. Данные callback'и отхватывают момент установки соединения (ну это понятно, даже название соответствующее). O>А вот disconnect'а как такового нет.
Я имел в виду другое. В этом месте вызвать FwpsFlowAssociateContext0. А момент окончания потока отслеживать из flowDeleteFn.
Здравствуйте, TarasCo, Вы писали:
TC>Здравствуйте, DimanKGKZ, Вы писали:
DKG>>Интеренсно, как это вобще реализовать?
TC>Реализовать то это не сложно, но это полный пипец производительности. Даже не так, вот так — ПОЛНЫЙ ПИПЕЦ.
Подскажите пожалуйста, как реализовать можно. Думаю пипец большой не будет, ну хотябы потому,
что задержка будет не большая... я так думаю , судя по dbgviewr-у. Даже если и будет тормозить,
так ему и надо. Это будет у компа основная обязанность.
Здравствуйте, DimanKGKZ, Вы писали:
DKG>Подскажите пожалуйста, как реализовать можно. Думаю пипец большой не будет, ну хотябы потому, DKG>что задержка будет не большая... я так думаю , судя по dbgviewr-у. Даже если и будет тормозить, DKG>так ему и надо. Это будет у компа основная обязанность.
Можете попробывать так:
1. В обработчике который потенциально может находиться на DISPATCH_LEVEL, но должен ждать код на PASSIVE_LEVEL запретить прерывания:
__asm cli
2. Крутиться в цикле, проверяя некий флаг
3. Флаг проверять с помощью InterlockedCompareExchange
4. После установки флага разрешить прерывания и продолжить выполнение.
В потоке, который будет делать вспомогательные действия после их выполнения установить флаг с помощью любой Interlocked функции.
Только врядли это все будет хорошо работать, IMHO возможен вариант дедлока и пока Вы это все отладите — Вы поседеете, а XP никто использовать уже не будет. Может Вам сразу — под Vista, там все что Вам нужно уже предусмотрено разработчиками.