| RSS



Меню

Bookmark and Share


Статистика
Ваш IP: 3.16.70.101
Вы используете: v





Сейчас на сайте:

Тех поддержка ->

Облако тэгов
ОС видио Tor Обратная сторона антенна 4.6 PHP Эксплоит Windows Server 2008 qip Virtual chroot kernel proc sysctl tune FreeBSD bridge Boot Disk Bluetooth GEO game directx Emulator Python Shell DDoS червь Conficker вирус троян Лаборатория Касперского пиратство apple iPhone ИТ-отрасль Щеголев Microsoft экономический кризис Twitter социальная сеть анонимность Лицензия Open Source ASP.NET MVC уязвимость MySQL база данных файлообмен закон франция пират Skype мобильный Deutsche Telekom Хакер киберпреступник Trend Micro кибератака Германия робот утечка данных персональные данные ноутбук интернет Китай цензура ядро Linux Торвальдс Windows Vista Acer Linux патент браузер Firefox Internet Explorer Opera Net Applications Safari Intel Linux Foundation Moblin Oracle патч банкомат кардер HSM IBM X-Force Cofee сша кибервойна Эстония Dell ИТ-специалист хакерские атаки Pirate Bay контроль кибербезопасность язык программирования The Pirate Bay Пиратская партия утечка информации приговор Mozilla Chrome безопасность Госдума СМИ Windows 8 Баллмер взлом Пентагон ботнет Украина Facebook Cisco cloud Windows XP нетбук торрент музыка биометрический nokia ФБР IP-адрес CIPAV Comcast sms RSA java Google CAPTCHA Symantec спам конфиденциальная информация инсайдер Perimetrix антивирус тест Anti-Malware Windows 7 операционная система Windows провайдер авторское право RapidShare UNIX свиной грипп шантаж дети EFF BluWiki копирайт экстремизм Panda Security cloud computing McAfee Cybercrime Response Unit Bottle Domains HTTPS ICANN студент шпионское ПО Норвегия школьник New York Times XSS YouTube Warner Music кибершпионаж КНДР Ubuntu свободное ПО AMD ATI касперский Россия РФ сервер хостинг фальшивый антивирус Comodo CA Wi-Fi D-Link суд пароль блог фишинг Одноклассники медведев контрафакт мошенник штраф Sony GPS по Gumblar JAVASCRIPT хакеры вредоносное ПО Yahoo ФАС компьютер Софт MPAA кибероружие PandaLabs Red Hat Минкомсвязи сбой ASUSTeK Computer мошенничество Доктор Веб ВКонтакте Cyber-Arc исходный код PCI DSS МВД фильтр порнография BREIN свобода слова Казахстан GEMA Autodesk сисадмин Gmail кредитная карта кибермошенник LiveJournal шифрование криптография Deep Purple банк нанотехнологии Wikipedia zero-day ColdFusion выборы кража данных DNS BIND Android BASIC атака Black Hat Mac OS X Click Forensics Clampi домен фсб Прокуратура Уголовное дело icq Barrelfish киберпреступность Sophos AT&T ошибка Electa Gamma Knife OpenBSD DARPA военные Сайт Visual Studio 2010 .NET Framework 4 Chrome OS электронная почта турция конференция спамер FTC полиция российская ОС Koobface Великобритания БЕЛОРУССИЯ грузия BSA Bittorrent облачные вычисления Azure Европа Dr.Web Билл Гейтс спецслужбы Cryzip Живой Журнал Royal Bank of Scotland смартфон Canonical Pwn2Own F-Secure Symbian Hotmail фильм

Главная » Статьи » Общие Статьи

Сам себе Руссинович

Итак, поскольку необходимых нам функций, как я уже говорил, в 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, по сути, представляющую собой функцию, которая принимает, если я правильно посчитал, пять параметров. До пяти я вроде бы считать умею, а если что-то не так, то простите старика-ветерана клавиатурного труда. Итак, функция получает следующие параметры:

  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 record

dwNumEntries: DWORD;

Table: array[0..0] of TMIB_TCPEXROW;

end;

В ней содержатся всего два параметра: количество элементов в таблице и массив элементов таблицы состояний портов. Каждый элемент массива - это тоже структура типа TMIB_TCPEXROW, представляющая собой вот что:

PMIB_TCPEXROW = ^TMIB_TCPEXROW;

TMIB_TCPEXROW = packed record

dwState: DWORD;

dwLocalAddr: DWORD;

dwLocalPort: DWORD;

dwRemoteAddr: DWORD;

dwRemotePort: DWORD;

dwProcessID: DWORD;

end;

Если ты не пропустил прошлый номер, то должен знать, что функция GetTcpTable возвращает примерно такую же структуру. Здесь также присутствует локальный адрес, локальный порт, удаленный адрес и удаленный порт. Самое последнее поле является новым и определяет идентификатор процесса, который открыл порт.

Теперь посмотрим на структуру PMIB_UDPEXTABLE, которая передается в качестве первого параметра функции получения состояний UDP-портов:

PMIB_UDPEXTABLE = ^TMIB_UDPEXTABLE;

TMIB_UDPEXTABLE = packed record

dwNumEntries: DWORD;

Table: array[0..0] of TMIB_UDPEXROW;

end;

Тут снова нас ожидает количество элементов в таблице состояний и массив из структур типа TMIB_UDPEXROW. Эта структура выглядит так:

PMIB_UDPEXROW = ^TMIB_UDPEXROW;

TMIB_UDPEXROW = packed record

dwLocalAddr: DWORD;

dwLocalPort: DWORD;

dwProcessID: DWORD;

end;

В ней мы видим локальный адрес, локальный порт и идентификатор процесса. Информации об удаленной машине нет и быть не может.

Вспомогательные функции

Для реализации примера нам понадобятся еще три системные функции из оконного ядра kernel32.dll:

CreateToolhelp32Snapshot: function (dwFlags, th32ProcessID: DWORD): THandle; stdcall;

{$EXTERNALSYM CreateToolhelp32Snapshot}

Process32First: function (hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; stdcall;

{$EXTERNALSYM Process32First}

Process32Next: function (hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; stdcall;

{$EXTERNALSYM Process32Next}

Давай кратко пробежимся по этим функциям:

  • CreateToolhelp32Snapshot - создает снимок указанного процесса;
  • Process32First - возвращает первый процесс из снимка;
  • Process32Next - возвращает следующий процесс из снимка.

За более подробной информацией по этим функциям обращайся к MSDN. У них достаточно много возможностей и различных флагов, поэтому описать их в одной статье будет сложно.

Загрузка функций

Мы объявили переменные, через которые будем обращаться к системным функциям, но все они являются указателями и на данном этапе указывают в никуда. Теперь в них необходимо записать соответствующие адреса. В прошлый раз для этого мы создавали функцию LoadAPIHelpAPI. Давай расширим ее и добавим следующие строки:

@AllocateAndGetTcpExTableFromStack:=GetProcAddress(HIpHlpApi, 'AllocateAndGetTcpExTableFromStack');

@AllocateAndGetUdpExTableFromStack:=GetProcAddress(HIpHlpApi, 'AllocateAndGetUdpExTableFromStack');

@CreateToolhelp32Snapshot := GetProcAddress(GetModuleHandle('kernel32.dll'), 'CreateToolhelp32Snapshot');

@Process32First := GetProcAddress(GetModuleHandle('kernel32.dll'), 'Process32First');

@Process32Next := GetProcAddress(GetModuleHandle('kernel32.dll'), 'Process32Next');

Теперь, после загрузки, каждая переменная будет указывать на соответствующую функцию в системе. Если какая-то функция не будет найдена, то соответствующая переменная будет равна нулю. Эту особенность мы будем использовать для того, чтобы определить, поддерживает ли ОС новые функции или необходимо использовать универсальный код, который мы рассматривали в прошлый раз.

Реализация

Вот мы и подошли к самому интересному - реализации универсального примера. В нашем старом коде по событию OnShow вызывалась функция GetConnections, в которой и происходило определение состояний портов. Улучшим пример, поставив условие вместо безусловного вызова:

procedure TForm1.FormShow(Sender: TObject);

begin

if @AllocateAndGetTcpExTableFromStack=nil then

GetConnections

else

GetExConnections;

end;

Если указатель AllocateAndGetTcpExTableFromStack равен нулю, значит, соответствующей функции нет в системе, и нужно вызывать GetConnections. Если он не равен нулю, то функция найдена в системе и можно использовать расширенные функции, которые мы рассмотрели сегодня. Полный код содержится в функции GetExConnections, которую мы поместили в листинге 1.

Логика GetExConnections практически не изменилась по сравнению с ранее написанной GetConnections. Мы точно так же получаем таблицу состояний и выводим ее содержимое, просто пользуясь при этом другими API функциями. Единственное, что заслуживает отдельного внимания - это вызов функции ProcessPidToName, которая должна переводить идентификатор процесса в удобочитаемое имя. Эту функцию с подробнейшими комментариями ты можешь увидеть в листинге 2.

Итог

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

Как видишь, все гениальное - в простоте и умении искать нужные функции. Можешь улучшить этот пример, чтобы он обновлял таблицу по таймеру и подсвечивал записи, состояние портов которых изменилось, или новые записи в таблице. Можно добавить возможность уничтожения выделенного процесса, ведь соответствующий идентификатор мы научились определять. Только не забывай, что при использовании старых функций процесс не определен. Кстати, написанный пример получает только состояние IP-портов старой версии, а реализацию состояния IPv6 легко организовать простым изменением последнего флага при вызове функций AllocateAndGetTcpExTableFromStack и AllocateAndGetUdpExTableFromStack.

На этом спешу откланяться. До новых встреч!

Листинг 1

procedure TForm1.GetExConnections;

var

TCPExTable: PMIB_TCPEXTABLE;

UDPExTable: PMIB_UDPEXTABLE;

hSnapshot: THandle;

i:Integer;

local_name:array[0..255]of char;

ExeName:String;

begin

lwTCP.Items.BeginUpdate;

lwTCP.Items.Clear;

// Получаем снимок процессов

hSnapshot := CreateToolhelp32Snapshot($2, 0);

try

// Определяем таблицу состояний TCP-портов

if AllocateAndGetTcpExTableFromStack(@TCPExTable, False, GetProcessHeap, 2, 2) = NO_ERROR then

begin

for i := 0 to TCPExTable.dwNumEntries - 1 do

begin

with lwTCP.Items.Add do

begin

Caption:='TCP';

if (hSnapshot = INVALID_HANDLE_VALUE) then

// Если не удалось получить снимок, то имя процесса оставить пустым

SubItems.Add('')

else

begin

// Снимок процессов был получен удачно, поэтому переводим ID в человеческое имя

ExeName:=ProcessPidToName(hSnapshot, tcpExTable.Table[i].dwProcessId);

SubItems.Add(ExeName);

end;

SubItems.Add(inet_ntoa(TInAddr(TCPExTable^.Table[I].dwLocalAddr)));

SubItems.Add(IntToStr(TCPExTable^.Table[I].dwLocalPort));

SubItems.Add(inet_ntoa(TInAddr(TCPExTable^.Table[I].dwRemoteAddr)));

SubItems.Add(IntToStr(TCPExTable^.Table[I].dwRemotePort));

SubItems.Add(TCPState[TCPExTable^.Table[I].dwState]);

end;

end;

end;

// Определяем таблицу состояний UPX-портов

if AllocateAndGetUdpExTableFromStack(@UdpExTable, False, GetProcessHeap, 2, 2) = NO_ERROR then

begin

for i := 0 to UDPExTable.dwNumEntries - 1 do

begin

with lwTCP.Items.Add do

begin

Caption:='UDP';

if (hSnapshot = INVALID_HANDLE_VALUE) then

// Если не удалось получить снимок, то имя процесса оставить пустым

SubItems.Add('')

else

// Снимок процессов был получен удачно, поэтому переводим ID в человеческое имя

SubItems.Add(ProcessPidToName(hSnapshot, UDPExTable.Table[i].dwProcessId));

gethostname(local_name, 255);

SubItems.Add(inet_ntoa(TInAddr(UDPExTable^.Table[I].dwLocalAddr)));

SubItems.Add(IntToStr(UDPExTable^.Table[I].dwLocalPort));

end;

end;

end;

finally

lwTCP.Items.EndUpdate;

end;

end;

Листинг 2

function TForm1.ProcessPidToName(hProcess: THandle; ProcID: DWORD): String;

var

procEntry:TPROCESSENTRY32;

ProcessName:String;

begin

procEntry.dwSize := sizeof(procEntry);

ProcessName:='???';

// Получаем первый процесс из снимка, который мы сделали в функции GetExConnections

if (Process32First(hProcess, procEntry)) then

begin

// Запускаем цикл перебора всех процессов

repeat

// Если текущий процесс равен искомому, то возвращаем его имя

if (procEntry.th32ProcessID = ProcId) then

begin

ProcessName:=procEntry.szExeFile;

Result:=ProcessName;

exit;

end;

// Цикл выполнять, пока функция Process32Next не вернет nil, то есть пока мы не достигнем конца снимка

until (not Process32Next(hProcess, &procEntry));

end;

Result:=ProcessName;

end;

Категория: Общие Статьи | Добавил: aka_kludge (03.12.2009)
Просмотров: 2198 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

14:03
Обновить


Пользователи
aka_kludge
qwerty
LeadyTOR
aka_Atlantis
AdHErENt
mAss
Sissutr
hiss
DrBio
tHick

Поиск


Copyright tHR - TeAM 2024 г. admin: aka_kludge (ICQ:334449009) Moderator's: LeadyTOR, ... Яндекс.Метрика