codingМихаил Фленов/ www.vr-online.ru /Сам себеРуссиновичСовременный метод определения состояния портовВ прошлый раз мы разобрались со старыми и надежными функциями определениясостояния портов. Сегодня мы двинемся дальше и познакомимся с новыми функциямиWindows XP, которые способны совершать еще немало интересного. Новый вариантпрограммы будет отображать не только открытые порты, но и процессы, которыеих открыли. В этом нам помогут функции, не описанные в заголовочных файлах Delphiи даже VC++, поэтому мы будем их загружать динамически.ФункцииИтак, поскольку необходимых нам функций,как я уже говорил, в Delphi нет и не предвидится,работу придется начать с заголовочногофайла. Нам понадобятся следующие функции:AllocateAndGetUdpExTableFromStack, AllocateAndGetTcpExTableFromStack, CreateToolhelp32Snapshot, Process32First и Process32Next.Первые две из них реализованы в библиотекеiphlpapi.dll и необходимы для получения изстека таблицы открытых TCP- и UDP-портовсоответственно.Какая из функций какую таблицу возвращает,нетрудно догадаться, исходя из ихимени. Остальные три функции реализованыв kernel32.dll и пригодятся нам для определенияпроцесса, который открыл порт.Напомню, что в прошлый раз мы писалипрограмму TCPView с запасом на будущее,а в главном окне даже подготовилиотдельную колонку для отображенияимени процесса. Сегодня с помощьюнескольких волшебных движений тазом мыее заполним.Если ты читал предыдущую статью (а еслине читал — вставляй DVD в дисковод и бериее оттуда), то открывай свой заголовочныйфайл, который уже должен быть создан,и начинай добавлять в него описанияфункций. Как и в прошлый раз, мы будемобъявлять функции в виде переменных,чтобы загружать их динамически.Состояния TCPДвинемся по порядку, а значит, начнем с рассмотренияфункции:AllocateAndGetTcpExTableFromStack:AllocateAndGetTcpExTableFromStack: function (pTCPTable: PMIB_TCPEXTABLE;bOrder: BOOL;heap: THandle;zero: DWORD;flags: DWORD): DWORD; stdcall;Здесь мы объявляем переменную AllocateAndGetTcpExTableFromStack, по сути, представляющуюсобой функцию, которая принимает,/ 122xàêåð 02 /98/ 07
codingПодробное описание функции Process32First в MSDN. Есличто-то не поймешь по исходнику, хватай англо-русский словарьи дуй сюдаРезультат работы программы. Во второй колонке показано имяпроцесса, который инициализировал работу с портомесли я правильно посчитал, пять параметров.До пяти я вроде бы считать умею, а если что‐тоне так, то простите старика-ветерана клавиатурноготруда. Итак, функция получает следующиепараметры:1. Указатель типа PMIB_TCPEXTABLE, черезкоторый нам вернут массив состоянияTCP-портов.2. Булево значение, определяющее, нужно лисортировать таблицу.3. Куча (heap), в которой нужно выделитьпамять для хранения результирующей таблицы.Вполне логично хранить результат в куче своегопроцесса, указатель на которую можно получитьс помощью функции GetProcessHeap.4. Флаги, определяющие, как себя будет вестифункция с кучей. В утилите Руссиновича здесьзачем‐то указывается двойка, и если запуститьпоиск по инету, то все найденные примеры будутавтоматом указывать на это же число. Зачем?Видимо, код копируется без понимания того, чтоон делает. Нам никакие «специфическиеповедения» кучи не нужны, поэтому смелопоставим сюда 0.5. Последний флаг определяет IP-адреса, длякоторых нужно получать таблицу. Здесь можноуказать флаг AF_INET или AF_INET6 для IP-протоколашестой версии. Интернетчики опять жекопируют код один к одному и явно указываютчисло 2 (значение константы AF_INET). Обеконстанты объявлены в заголовочном файлеWinsock… Хотя нет, константа AF_INET6 естьтолько в заголовочном файле второй версии,ведь первый Winsock ничего не знал о IPv6.Запусти поиск в рунете по названию функцииAllocateAndGetTcpExTableFromStack и в большинствеслучаев ты узнаешь, что функцияне документирована. Кем не документирована?В MSDN есть подробное описание, просто искатьего нужно умеючи :). Свежий msdn всегдаможно найти по адресу msdn.microsoft.com.Да, он обновляется с задержкой и уже послевыхода ОС, и чтобы быть впереди всей планеты,просто нужно купить подписку за немалоеколичество портретов американских лидеров.В общем, к чему я клоню: если новой функциинет в старой версии справки, то это не значит,что описание отсутствует вовсе ;).Кстати, если верить MSDN, эта функция устарелаи больше не поддерживается в новоиспеченнойWindows Vista! Я Висту пока ещене ставил и не проверял, но если это так, нашуниверсальный пример будет как раз кстати.Если посмотреть в SDK для Висты, можно заметитьинтересный факт: функция там объявлена,но только для совместимости. Так что не пытайсявызвать ее напрямую, иначе тебя ждет крахпрограммы. Что будет в качестве замены, ещенеизвестно, а Майкрософт пока молчит.Состояния UDPТаблицу состояний UDP-портов можно узнатьс помощью функции AllocateAndGetUdpExTableFromStack, которую необходимо объявитьследующим образом:AllocateAndGetUdpExTableFromStack:function (pUDPTable: PMIB_UDPEXTABLE;bOrder: BOOL;heap: THandle;zero: DWORD;flags: DWORD): DWORD; stdcall;Ее параметры идентичны параметрам функцииработы с TCP-портами, за исключением первого,который имеет тип PMIB_UDPEXTABLE.Порты UDP не имеют соединений, поэтому ихтаблица состояний немного отличается.Структуры данныхТеперь поговорим о структурах данных, черезкоторые мы будем получать результирующиетаблицы. Начнем с TCP-портов. Функцияпринимает в качестве первого параметра типданных PMIB_TCPEXTABLE, а, на самом деле,это структура следующего вида:PMIB_TCPEXTABLE = ^TMIB_TCPEXTABLE;TMIB_TCPEXTABLE = packed recorddwNumEntries: DWORD;Table: array [0..0] ofTMIB_TCPEXROW;end;В ней содержится всего два параметра: количествоэлементов в таблице и массив элементовтаблицы состояний портов. Каждый элементмассива — это тоже структура типаTMIB_TCPEXROW, представляющая собой вот что:PMIB_TCPEXROW = ^TMIB_TCPEXROW;TMIB_TCPEXROW = packed recorddwState: DWORD;dwLocalAddr: DWORD;dwLocalPort: DWORD;dwRemoteAddr: DWORD;dwRemotePort: DWORD;dwProcessID: DWORD;end;Если ты не пропустил прошлый номер, то должензнать, что функция GetTcpTable возвращаетпримерно такую же структуру. Здесь такжеприсутствует локальный адрес, локальный порт,удаленный адрес и удаленный порт. Самоепоследнее поле является новым и определяетидентификатор процесса, который открыл порт.Теперь посмотрим на структуру PMIB_UDPEXTABLE,которая передается в качестве первого параметрафункции получения состояний UDP-портов:PMIB_UDPEXTABLE = ^TMIB_UDPEXTABLE;TMIB_UDPEXTABLE = packed recorddwNumEntries: DWORD;Table: array [0..0] ofTMIB_UDPEXROW;end;Тут снова нас ожидает количество элементовв таблице состояний и массив из структур типаTMIB_UDPEXROW. Эта структура выглядит так:xàêåð 02 /98/ 07/123