Здраствуйте Заранее извините за большое количество текста Пишу TDI-фильтр (блокирование траффика Tcp) и столкнулся с проблемой. Сам фильтр блокирует все исходящие соединения, кроме оных по одному определенному адресу. Я написал простую тестовую программку — состоящую из 3-х строчек Код (Text): socket() connect() send() которая подключается к этому разрешенному хосту. Если эти операции происходят в таком порядке "быстро", программа вылетает с ошибкой Access violation Code=0xc0000005, Address=0x0000000000000000 (никаких BSODов не происходит) Если "медленно", с задержкой (system("PAUSE")) после каждого шага — данные успешно передаются. Вот как выглядит процедура-перехватчик IRP_MN_INTERNAL_IOCTL Код (Text): NTSTATUS InternalIOCTLHook(PDEVICE_OBJECT pDeviceObject, PIRP pIrp) { NTSTATUS status; UCHAR query; PDEVICE_EXTENSION pdx; PTRANSPORT_ADDRESS connect_destaddress; ULONG ipaddress; LONG eventtype; PIO_STACK_LOCATION pIrpstack = IoGetCurrentIrpStackLocation(pIrp); //DbgPrint("IRP_MJ_INTERNAL_DEVICE_CONTROL cаught\n"); query = pIrpstack->MinorFunction; switch(query) { case TDI_ACCEPT: //or case TDI_RECEIVE_DATAGRAM: DbgPrint("TDI_ACCEPT (or TDI_RECEIVE_DATAGRAM) catch, reflecting\n"); pIrp->IoStatus.Status = STATUS_CONNECTION_REFUSED; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; case TDI_CONNECT: //if this is a connection to server - pass it, otherwise - reject connect_destaddress = (PTRANSPORT_ADDRESS)(((PTDI_REQUEST_KERNEL_CONNECT)(&pIrpstack->Parameters))->RequestConnectionInformation->RemoteAddress); if(connect_destaddress->Address[0].AddressType==TDI_ADDRESS_TYPE_IP) { ipaddress = ((TDI_ADDRESS_IP *)(connect_destaddress->Address->Address))->in_addr; DbgPrint("IP TDI_CONNECT detected: %u \n", ipaddress); if(ipaddress==SERVER_ADDRESS) { DbgPrint("Connection allowed for privileged address\n"); goto passit; } } case TDI_SEND_DATAGRAM: DbgPrint("TDI_SEND_DATAGRAM (or TDI_CONNECT), reflecting\n"); pIrp->IoStatus.Status = STATUS_ACCESS_DENIED; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; case TDI_SET_EVENT_HANDLER: eventtype = ((PTDI_REQUEST_KERNEL_SET_EVENT)(&pIrpstack->Parameters))->EventType; DbgPrint("TDI_SET_EVENT_HANDLER\n"); if(eventtype==TDI_EVENT_CONNECT || eventtype==TDI_EVENT_RECEIVE_DATAGRAM) { DbgPrint("TDI_SET_EVENT_HANDLER (connect or receive datagram) catch, reflecting\n"); pIrp->IoStatus.Status = STATUS_ACCESS_DENIED; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } } //pass packet passit: pdx = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension; IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pdx->pPrevDevObjInStack, pIrp); return status; } И вот что выдает отладчик после запуска тестирующей программки Код (Text): IP TDI_CONNECT detected: 30976192 Connection allowed for privileged address TDI_SET_EVENT_HANDLER TDI_SET_EVENT_HANDLER TDI_SET_EVENT_HANDLER TDI_SET_EVENT_HANDLER TDI_SET_EVENT_HANDLER Я думал, что SocketAPI устанавливает события ожидания (SET_EVENT_HANDLER) для соединения, если оно происходит "слишком быстро", но ведь DbgPrint-сообщений вида TDI_SET_EVENT_HANDLER (connect or receive datagram) catch, reflecting отладчик не выдает, значит эти EVENT_HANDLER's не устанавливаются.. Чем можно объяснить такое поведение? И почему не проиходит BSOD? Только начал разбираться в драйверах и TDI, прошу прощения за вермишелеподобный код Система Windows XP Спасибо И хотелось бы спросить — правильно ли, что ожидать TDI_SEND_DATAGRAM и TDI_RECEIVE_DATAGRAM (равно как и событий со словом *DATAGRAM* в их идентификаторах) на \Device\Tcp бессмысленно? И чтоб организовать фильтрацию Udp нужно отдельно создать DEVICE_OBJECT, присоединить его к открытому объекту \Device\Udp? Или можно обойтись одним объектом-фильтром DEVICE_OBJECT (тогда к чему его присоединять?) для обоих протоколов? Еще раз извините за глупые вопросы (Задал эти же вопросы на rsdn, правда безуспешно)
Код показывай. Событие TDI_EVENT_CONNECT это только для серверов (входящие соединения). Поведение чего? Приложения? Не знаю, возможно, ошибка в коде. Встречный вопрос - а почему должен быть? Код фильтра вполне корректный. Да. Нет. Можешь считать себя просветлённым ибо теперь ты знаешь разницу между форумом и IM.
К сказанному x64 добавить, в принципе, нечего) вермишелеподобный код (кстати классное слово, спасибо! взял на заметку ) возникает отнюдь не от незнания техники, а от нежелания писать читабельно Как ты аттачнешь его к двум девайсам сразу? Вообщем, надо код самой программки
x64 Спасибо за ответ Программа-сервер запускается на "чистой" (без установленного драйвера-фильтра) машине. Эта машина и есть тот единственный "разрешенный" хост в драйвере, куда пропускаются пакеты: Код (Text): #include <iostream> #include <winsock2.h> #include <windows.h> #include <stdlib.h> #pragma comment(lib, "ws2_32.lib") using namespace std; int main(int argc, char **argv) { WSADATA wsadata; WSAStartup(MAKEWORD(2, 0),&wsadata); int PORT=9482; if (argc>1) { PORT = atoi(argv[1]); cout << "Using custom port: " << argv[1]<<endl; } char buf[100]; cout << "Creating a server socket\n"; SOCKET servsock = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr; addr.sin_addr.S_un.S_addr = ADDR_ANY; addr.sin_family = AF_INET; addr.sin_port = htons(PORT); bind(servsock, (sockaddr*)&addr, sizeof(sockaddr)); cout << "bind() done\n"; listen(servsock, 0); cout << "listen() enabled\n"; int size; cout << "listening...\n"; SOCKET clsock = accept(servsock, (sockaddr*)&addr, &size); cout << "accepted!\n"; int ri = recv(clsock, buf, 99, 0); cout << "Received "<<ri<<" bytes: "<<buf; //cout.write(buf, 100); cout.flush(); cin.get(); WSACleanup(); } Клиент запускается на машине с установленным фильтром. Код (Text): #include <iostream> #include <winsock2.h> #include <windows.h> #include <string.h> #include <stdlib.h> #pragma comment(lib, "ws2_32.lib") using namespace std; #define REP(a) if (report) {cout << a << endl << flush; cin.get();} int main(int argc, char **argv) { WSADATA wsadata; WSAStartup(MAKEWORD(2, 0),&wsadata); int report = 0; cout << "Creating a client socket\n"; int PORT=9482; if (argc>1) { PORT = atoi(argv[1]); cout << "Using custom port: " << argv[1]<<endl; if(argc==3) { if(!strcmp(argv[2], "report")) { cout << "Using manual reporting mode\n"; report = 1; } } } REP("Begin: create socket") SOCKET clsock =socket(AF_INET, SOCK_STREAM, 0); if(clsock==INVALID_SOCKET) { cout << "Socket() error!\n"<<endl; cin.get(); return 0; } REP("End: create socket") sockaddr_in addr; addr.sin_addr.S_un.S_addr = inet_addr("192.168.216.1"); addr.sin_family = AF_INET; addr.sin_port = htons(PORT); REP("Begin: connect()") if(connect(clsock, (sockaddr*)(&addr), sizeof(sockaddr))) { cout << "CONNECT() ERROR!\n"<<endl<<flush; cin.get(); return 0; }; REP("End connect()") cout << "connect() done\n"; char buf[]="Hello from usermode ClSock!"; REP("Begin: send()") if(send(clsock, buf, strlen(buf)+1, 0)==SOCKET_ERROR) { cout << "send() error!\n"; return 0; }; REP("End: send()") cout << "sent!\n"; cout.flush(); cin.get(); WSACleanup(); } Если эти программы запустить как Код (Text): server.exe 1234 client.exe 1234 report и быстро нажимать enter, можно поймать Access violation Гарантированно AV появляется, если запустить так: Код (Text): server.exe 1234 client.exe 1234 Что-то подсказывает, что исключение происходит где-то в недрах той части Winsock что в режиме пользователя. Может из-за того что возвращаю STATUS_ACCESS_DENIED вместо ожидаемого этой библиотекой STATUS_CONNECTION_REFUSED? Разобраться в недрах Winsock к сожалению не позволяет квалификация Объект \Device\Tcp открывается ZwCreateFile, где в качестве параметра pEaBuffer передается лок. порт 0, лок. адрес 0.0.0.0 затем к этому pTcpDeviceObject аттачится только что созданный объект-фильтр. Этот же файловый объект используется для передачи/приема. Сейчас уже не уверен, что так можно делать, может имеет смысл создать свои объекты файл отдельно для фильтрации и отдельно для приема/отсылки по сети? Еще раз благодарю, если дочитали это до конца
Не надо домыслов, достаточно посмотреть call stack на момент исключения в том же WinDbg, запустив процесс под его отладкой.
По правде говоря, WinDbg использовал только на уровне консоли вывода сообщений DbgPrint, я не обладаю достаточной квалификацией в реверсинге к сожалению, чтоб разобрать дамп, хотя хотелось бы.. Вот что я получил в Ollydbg может вы подскажете, что не так? x64 Простите что надоедаю , но можно узнать ваше мнение по поводу ?
Great x64 Вобщем спасибо, теперь работает Как оказалось, программа режима пользователя вылетала из-за того, что в драйвере-фильтре один pTcpFileObject использовался и для отсылки данных, и для получения pTcpDeviceObject (ObReferenceObjectByHandle), по которому я получал DEVICE_OBJECT tcp TDI-транспорта, и к которому аттачился. Так и не понял, почему нельзя было делать так, как я сделал в первом варианте (и почему вылетала программа пользователя, а не вся система в bsod (причем блокирование происходило нормально, без ошибок, а вот если соединятся с "разрешенным" в фильтре хостом - получался AV)). Но в общем, это не настолько важно, главное что не вылетает