Способы фильтрации сетевого траффика в Windows 9x/2000/Net.2003 Server — Архив WASM.RU

Все статьи

Способы фильтрации сетевого траффика в Windows 9x/2000/Net.2003 Server — Архив WASM.RU

Введение.

В данной статье даются основные сведения по способам фильтрации сетевого траффика в Windows 9x/2000/Net.2003 Server, даётся описание фильтрации IP-траффика в Windows 2000 на основе Windows 2000 Filter-Hook Driver способа.Также указываются особенности реализации других методов фильтрации.

Часть первая, теоретическая.

Способы фильтрации сетевого трафика .

Существует несколько способов фильтрации сетевого траффика .Для начала кратко рассмотрим основы сетевой подсистемы Windows:

1) NDIS. В 1989 году Microsoft и 3Com совместно разработали Network Driver Interface Specification (NDIS), которая позволяет драйверам сетевых протоколов использовать сервисы сетевых интерфейсов (отправка/прием сетевых пакетов) скрывая детали их реализации. Драйвер сетевого адаптера, разработанный в соответствии с этой спецификацией, принято называть NDIS минипортом (miniport).Одно из преимуществ - то, что код свободно переносится из 9x/ME - winNT/2000 . Детальное описание предмета можно найти в документации DDK (раздел NetworkDrivers), вкратце NDIS описывает правила (интерфейсы и структуры), в соответствии, с которыми должны разрабатываться драйвера сетевых адаптеров, а так же предоставляет библиотеку функций, к которой должен обращаться разработчик вместо прямого использования сервисов ядра.

2) Драйвера сетевых протоколов. Вкратце, драйвер сетевого протокола (такого как, например TCP/IP) для работы с сетевыми интерфейсами использует функции уже упомянутой библиотеки NDIS и может предоставлять TDI (Transport Data Interface) вышележащим уровням (TDI-клиентам, одним из типичных представителей которых в ядре NT/2000/XP является afd.sys - kernel-mode часть Windows Sockets).

3) User-Mode DLL's которые формируют интерфейс WindowsSockets. Это ws2_32.dll, msafd.dll, wshtcpip.dll и другие.

Тех, кто хочет более детально рассмотреть сетевую подсистему Windows , отсылаю к David Solomon, Mark Russinovich : Inside Windows 2000, часть 13.

Технологии фильтрации:

Технологии фильтрации в User-mode автор не рассматривает.

Технологии фильтрации сетевого трафика в режиме ядра:

1) Kernel-mode sockets filter. Эта технология применима для WindowsNT/2000. Основана на перехвате всех вызовов из msafd.dll (самая низкоуровневая user-mode DLL из состава Windows Sockets) к модулю ядра afd.sys (kernel-mode часть WindowsSockets). Данная технология требует аккуратного обращения с интерфейсами AFD , т.к. они изменяются в разных версиях NT. AFD является TDI клиентом и реализует приём/отправку данных через драйвер протокола. Msafd.dll сообщает AFD название протокола для каждого сокета.Для более подробного изучения отправляю в Inside Windows 2000, раздел 13, подраздел Networking APIs.Способ бесполезен при маршрутизации, т.к. она осуществляется внутри TCPIP.SYS(иногда и вне его - поиск по DDK: Fast Forwarding Path - происходит внутри NDIS ) и не доходит до сокетов. Хотя данный способ удобен для шифрования потоков данных и QoS - Quality of Service - предоставляется специальное API (смотреть в MSDN - поиск по QOS Reference).

2) TDI-filter driver. Технология применима как в Windows 9x/ME так и в WindowsNT/2000, хотя конкретные реализации сильно отличаются. Что касается Windows NT/2000, то в случае TCP/IP фильтрации необходимо перехватывать все вызовы, направленные устройствам (devices) созданным модулем tcpip.sys (\Device\RawIp, \Device\Udp, \Device\Tcp). Технология достаточно известная и используется в ряде коммерческих продуктов (например, OutpostFirewall).

3) NDIS Intermediate Driver Способ очень неудобен в инсталляции и программировании. Желающие могут изучить DDK. Ниже приведён пример кода, показывающего громоздкость программирования :

local status:		NTSTATUS
local PChars:		NDIS_PROTOCOL_CHARACTERISTICS
local MChars:		NDIS_MINIPORT_CHARACTERISTICS
	local Param:		PNDIS_CONFIGURATION_PARAMETER
	local Name1:		NDIS_STRING
	local WrapperHandle:NDIS_HANDLE
	local DriverHandler:	NDIS_HANDLE
	local ProtHandler:	NDIS_HANDLE
	mov DriverHandler,NULL
	mov ProtHandler,NULL
	invoke NdisInitializeWrapper,addr WrapperHandle,pDriverObject, pusRegistryPath,NULL
	invoke RtlZeroMemory,addr MChars,sizeof NDIS_MINIPORT_CHARACTERISTICS
	mov MChars.MajorNdisVersion,		5
	mov MChars.MinorNdisVersion,		NULL
	mov MChars.InitializeHandler,		offset MPInitialize
	mov MChars.QueryInformationHandler,	offset MPQueryInformation
	mov MChars.SetInformationHandler,	offset MPSetInformation 
	mov MChars.ResetHandler,			offset MPReset
	mov MChars.TransferDataHandler,		offset MPTransferData
	mov MChars.HaltHandler,			offset MPHalt
	mov MChars.CheckForHangHandler,		NULL
	mov MChars.SendHandler,			offset MPSend
	mov MChars.ReturnPacketHandler,		offset MPReturnPacket
	invoke NdisIMRegisterLayeredMiniport,WrapperHandle,addr MChars,	sizeof MChars,\
addr DriverHandler
	.if eax == STATUS_SUCCESS
		invoke NdisMRegisterUnloadHandler,WrapperHandle,offset Unload
		invoke RtlZeroMemory,addr PChars, sizeof NDIS_PROTOCOL_CHARACTERISTICS
		mov PChars.MajorNdisVersion,	5
		mov PChars.MinorNdisVersion,	0
		invoke RtlInitUnicodeString,addr PChars.Name_,addr stroka
		mov PChars.OpenAdapterCompleteHandler,	offset PtOpenAdapterComplete
		mov PChars.CloseAdapterCompleteHandler,	offset PtCloseAdapterComplete
		mov PChars.SendCompleteHandler ,		offset PtSendComplete
		mov PChars.TransferDataCompleteHandler ,	offset PtTransferDataComplete
		mov PChars.ResetCompleteHandler ,	offset PtResetComplete
		mov PChars.RequestCompleteHandler,	offset PtRequestComplete
		mov PChars.ReceiveHandler ,		offset PtReceive
		mov PChars.ReceiveCompleteHandler ,	offset PtReceiveComplete
		mov PChars.StatusHandler,			offset PtStatus 
		mov PChars.StatusCompleteHandler,	offset PtStatusComplete
		mov PChars.BindAdapterHandler ,		offset PtBindAdapter
		mov PChars.UnbindAdapterHandler ,	offset PtUnbindAdapter
		mov PChars.UnloadHandler ,		NULL
		mov PChars.ReceivePacketHandler ,	offset PtReceivePacket	
		mov PChars.PnPEventHandler,		offset PtPNPHandler

		invoke NdisRegisterProtocol,addr status,addr ProtHandler,addr PChars,\
					sizeof NDIS_PROTOCOL_CHARACTERISTICS
		.if eax==STATUS_SUCCESS
			invoke NdisIMAssociateMiniport,DriverHandler,ProtHandler 
			mov eax,STATUS_SUCCESS
			ret
		.endif
	.endif

Вкратце способ заключается в создании виртуального адаптера и его установки таким образом,что при каждом вызове реального адаптера сначала шло обращение к виртуальному.Т.е мы как бы накладываем наш виртуальный адаптер на реальный.

Вся обработка поступивших вызовов идёт в MP* и Pt* функциях. Где MP* -относится к Miniport, т.е. к нашему виртуальному адаптеру, а Pt* - к Protocol , протоколу, реализуемуму нашим адаптером.

Т.е если мы хотим фильтровать TCP/IP , Protocol должен уметь обрабатывать IP - пакеты .

4) Windows 2000 Filter-Hook Driver. Метод описан в документации DDK и применим только в Windows 2000 и выше, его мы и будем рассматривать в практической части.

5) NDIS Hooking Filter Driver.Способ сводится к перехвату некоторых функций NDIS библиотеки, которые в дальнейшем позволяют отследить регистрацию всех протоколов установленных в операционной системе и открытие ими сетевых интерфейсов. Используется в небезызвестном ZoneAlarm. Для Windows 2000 достаточно перехватить 4 функции:

  • NdisRegisterProtocol
  • NdisDeregisterProtocol
  • NdisOpenAdapter
  • NdisCloseAdapter

6) Packet Filtering API. На данный момент доступно в Windows 2000 Server и Windows .NET Server 2003.

Насчёт пунктов 2,3,5 : автор надеется осветить их в отдельной обширной статье по NDIS и TDI.

Часть вторая, практическая.

Использование Windows 2000 Filter-Hook Driver

Начиная с Windows 2000 Microsoft включила возможность фильтрации IP траффика в контексте IP Filter driver - стандартного сервиса Windows 2000. Как написано в DDK ,драйвера , используемые IP Filter driver сервисом, могут обрабатывать и фильтровать IP траффик, т.е расширять возможности IP Filter driver сервиса.

Правда при этом необходимо учитывать нюанс - только один драйвер может использоваться при фильтрации.

Драйвер для фильтрации траффика представляет собой обычный Kernel Mode Driver, реализующий определённую функцию фильтрации , которую он и регестрирует в IP Filter driver сервисе .Фильтруются как исходящий, так и входящий траффик.

Вот исходный текст простейшего драйвера для IP Filter driver, драйвер просто drop -ает все пакеты :

.386
.model flat, stdcall
;                              		  	  I N C L U D E   F I L E S
;#########################################################################
include D:\masm32\include\w2k\ntstatus.inc
include D:\masm32\include\w2k\ntddk.inc
include D:\masm32\include\w2k\pfhook.inc
include D:\masm32\include\w2k\ntoskrnl.inc
include D:\masm32\Macros\Strings.mac
includelib D:\NTDDK\libfre\i386\ntdll.lib
includelib D:\NTDDK\libfre\i386\ntoskrnl.lib
;						P R O T O
;##########################################################################
set_hook PROTO  :PacketFilterExtensionPtr 
;						 D A T A
;##########################################################################
.data
CCOUNTED_UNICODE_STRING "\\Device\\IPFILTERDRIVER" ,drvsmbl,4
ipfilter_name UNICODE_STRING <>
hook_nfo PF_SET_EXTENSION_HOOK_INFO <>
status NTSTATUS ?
devobj PDEVICE_OBJECT ?
isb IO_STATUS_BLOCK <>
fileobj PFILE_OBJECT NULL 
myirp PIRP NULL
;                                       			 C O D E
;############################################################################
.code
;                                     		  DriverEntry
;############################################################################
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
	mov eax,offset hookproc
	invoke set_hook, eax
	.if eax != STATUS_SUCCESS
        		ret
        	.endif
       	 mov eax, pDriverObject
        	 assume eax:PTR DRIVER_OBJECT
       	 mov [eax].DriverUnload,offset Unload
        	 assume eax:nothing
       	 mov eax,STATUS_SUCCESS
        	 ret
DriverEntry endp
;			        Windows 2000 hook (built in)
;###############################################################################
Unload proc p1DriverObject:PDRIVER_OBJECT
	invoke set_hook,NULL
	ret
Unload endp
;###############################################################################
set_hook proc hook_fn:PacketFilterExtensionPtr 

		invoke IoGetDeviceObjectPointer,addr drvsmbl,STANDARD_RIGHTS_ALL,\
addr fileobj,addr devobj

	mov status,eax   
        .if eax != STATUS_SUCCESS
        	jmp exit
        .endif

        mov eax,hook_fn
        mov hook_nfo.ExtensionPointer,eax
      
        invoke IoBuildDeviceIoControlRequest,IOCTL_PF_SET_EXTENSION_POINTER(),\
devobj, addr hook_nfo,\
        				sizeof hook_nfo, NULL, 0, FALSE, NULL,addr isb

	mov myirp,eax

        .if eax == NULL
        	mov status ,STATUS_INSUFFICIENT_RESOURCES
        	jmp exit
        .endif

        invoke IoCallDriver,devobj,myirp

        mov myirp,NULL
        mov eax,STATUS_SUCCESS
        ret
exit:

	.if fileobj!=NULL
		invoke ObDereferenceObject,fileobj
	.endif

	mov eax,status
	ret
	
set_hook endp
;###############################################################################
hookproc proc PacketHeader:PTR BYTE, Packet:PTR BYTE, PacketLength:WORD,
        RecvInterfaceIndex:WORD,SendInterfaceIndex:WORD,RecvLinkNextHop:DWORD,
        SendLinkNextHop:DWORD
        
        mov eax,PF_DROP
	ret
hookproc endp

end DriverEntry

Для компиляции потребуется masm32 by hutch ,последний KMDKit by Four-F, Update KMDKit by van (пока состоит из pfhook.inc и неполного ndis.inc).

Рассмотрим более подробно данный код.

1) CCOUNTED_UNICODE_STRING "\\Device\\IPFILTERDRIVER" ,drvsmbl,4 - название нашего IP Filter driver сервиса.

2) hook_nfo PF_SET_EXTENSION_HOOK_INFO <> - структура , содержащая указатель типа PacketFilterExtensionPtr, т.е на нашу функцию фильтрации. Все остальные типы описаны в MSDN и KMD by Four-F.

3)

mov eax,offset hookproc
invoke set_hook, eax
.if eax != STATUS_SUCCESS
ret
.endif

Вызываем set_hook , в качестве параметра выступает offset нашей функции фильтрации.

Если хук не удалось установить, выходим.

4)

mov eax, pDriverObject
assume eax:PTR DRIVER_OBJECT
mov [eax].DriverUnload,offset Unload
assume eax:nothing
mov eax,STATUS_SUCCESS
ret

Стандартная процедура регистрации функции выхода.

5)

Unload proc p1DriverObject:PDRIVER_OBJECT
	invoke set_hook,NULL
	ret
Unload endp

Устанавливаем указатель на функцию фильтрации в IP Filter driver сервисе в NULL

6)

	set_hook proc hook_fn:PacketFilterExtensionPtr 

	invoke IoGetDeviceObjectPointer,addr drvsmbl,STANDARD_RIGHTS_ALL,addr fileobj,
            						addr devobj 

Наша функция установки фильтра.

IoGetDeviceObjectPointer - возвращает указатель в devobj на Device и file object , соответсвующий ему , название которого в drvsmbl . При условии, что доступ к нему разрешён.

7)

           invoke IoBuildDeviceIoControlRequest,IOCTL_PF_SET_EXTENSION_POINTER(),devobj, \
                  addr hook_nfo ,sizeof hook_nfo, NULL, 0, FALSE, NULL,addr isb

Данная функция подробно описана в Walter Oney's Programming the Microsoft Windows Driver Model.

Макрос IOCTL_PF_SET_EXTENSION_POINTER() определён в pfhook.inc

Результат - устанавливаем irp для нашего драйвера.

Все остальные функции в данном разделе описаны в DDK и Programming the Microsoft Windows Driver Model.

8)

	hookproc proc PacketHeader: DWORD , Packet: DWORD, PacketLength:WORD,
    		      RecvInterfaceIndex:WORD,SendInterfaceIndex:WORD,RecvLinkNextHop:DWORD,
                  SendLinkNextHop:DWORD
        
     	mov eax,PF_DROP
		ret
hookproc endp

Наш фильтр. Как видно, перед нами внутренности пакета.Заголовок и содержимое.

Возвращаем PF_DROP.

В pfhook.inc определены следующие константы для работы с IP пакетами:

PF_FORWARD		EQU	0t
PF_DROP			EQU	1t
PF_PASS			EQU	2t
PF_ICMP_ON_DROP	EQU	3t

PF_FORWARD - форвардит пакет. Т.е. если destination address != наш адрес и включена маршрутизация, то немедленно посылается forward response в IP стек.

PF_PASS - пропускает пакет на наш компьютер.

PF_ICMP_ON_DROP - дропает пакет и отправляет ICMP - сообщение.

Данная константа недокументирована, хотя и определена.

Как установить наш драйвер ?

Автор использовал утилиту instdrv из NT DDK . К сожалению, в Win2000 DDK она отсутсвует.

Итак, набираем в консоли:

net start ipfilterdriver 

instdrv filter  D:\projects\asm\filter\filter.sys

ping 127.0.0.1

	Destination host unreachable.	; host unreachable,		
Destination host unreachable.	; что и следовало ожидать,
Destination host unreachable.	; потому что все пакеты 
Destination host unreachable.	; уничтожены, ICMP - сообщение  
Ping statistics for 127.0.0.1:		; не отправлялось.
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum =  0ms, Average =  0ms
.		 
instdrv filter remove

Заключение.

Автор не претендует на полноту изложения , он постарался дать лишь общее представление о предмете. Автор также надеется , что данная статья позволит самостоятельно создавать firewall'ы на основе IP Filter driver сервиса и данного сэмпла.

Рекомендуемая литература:

Walter Oney's Programming the Microsoft Windows Driver Model.
David Solomon, Mark Russinovich : Inside Windows 2000

Благодарности: Volodya /wasm.ru , за то, что терпел и наставлял меня , и за instdrv.
Four-F/wasm.ru ,за KMDKit и замечательные статьи.
gl00my , за моральную поддержку.

Файлы:

2002-2013 (c) wasm.ru