Программирование на C++ глазами хакера


Состояние локального компьютера


Если нужно узнать состояние портов локального компьютера, нет необходимости сканировать порты. Есть способ лучше — запросить состояние всех портов с помощью функции GetTcpTable. В этом случае вы получите более подробную информацию, которую можно свести в таблицу из следующих колонок:

локальный адрес — интерфейс, на котором открыт порт;

локальный порт — открытый порт;

удаленный адрес — адрес, с которого в данный момент установлено соединение с портом;

удаленный порт — порт на удаленной машине, через который происходит обращение к локальной машине;

состояние — может принимать различные значения: прослушивание, закрытие порта, принятие соединения и т. д.

Самое главное преимущество использования состояния локальной таблицы TCP — мгновенная работа. Сколько бы ни было открытых портов, их определение происходит в считанные миллисекунды.

Для иллюстрации примера работы с TCP-портом создайте MFC-приложение на основе диалогового окна с именем IPState. На главное диалоговое окно поместите один список типа List Box и кнопку с заголовком TCP Table. На 6.3 вы можете увидеть окно будущей программы.

6.3. Окно будущей программы IPState

По нажатии кнопки TCP Table должен выполняться код из листинга 6.3.



Листинг 6.3. Получение информации о ТСР-портах
void CIPStateDlg::OnBnClickedButton1() { DWORD dwStatus = NO_ERROR; PMIB_TCPTABLE pTcpTable = NULL; DWORD dwActualSize = 0;

dwStatus = GetTcpTable(pTcpTable, dwActualSize, TRUE);

pTcpTable = (PMIB_TCPTABLE) malloc(dwActualSize); assert(pTcpTable);

dwStatus = GetTcpTable(pTcpTable, dwActualSize, TRUE); if (dwStatus != NO_ERROR) { AfxMessageBox("Couldn't get tcp connection table."); free(pTcpTable); return; }

CString strState; struct in_addr inadLocal, inadRemote; DWORD dwRemotePort = 0; char szLocalIp[1000]; char szRemIp[1000];

if (pTcpTable != NULL) { lList.AddString("================================================="); lList.AddString("TCP table:"); for (int i=0; ipTcpTable-dwNumEntries; i++) { dwRemotePort = 0; switch (pTcpTable-table[i].dwState) { case MIB_TCP_STATE_LISTEN: strState="Listen"; dwRemotePort = pTcpTable-table[i].dwRemotePort; break; case MIB_TCP_STATE_CLOSED: strState="Closed"; break; case MIB_TCP_STATE_TIME_WAIT: strState="Time wait"; break; case MIB_TCP_STATE_LAST_ACK: strState="Last ACK"; break; case MIB_TCP_STATE_CLOSING: strState="Closing"; break; case MIB_TCP_STATE_CLOSE_WAIT: strState="Close Wait"; break; case MIB_TCP_STATE_FIN_WAIT1: strState="FIN wait"; break; case MIB_TCP_STATE_ESTAB: strState="EStab"; break; case MIB_TCP_STATE_SYN_RCVD: strState="SYN Received"; break; case MIB_TCP_STATE_SYN_SENT: strState="SYN Sent"; break; case MIB_TCP_STATE_DELETE_TCB: strState="Delete"; break; } inadLocal.s_addr = pTcpTable-table[i].dwLocalAddr; inadRemote.s_addr = pTcpTable-table[i].dwRemoteAddr; strcpy(szLocalIp, inet_ntoa(inadLocal)); strcpy(szRemIp, inet_ntoa(inadRemote));


char prtStr[1000]; sprintf(prtStr, "Loc Addr %1s; Loc Port %1u; Rem Addr %1s; Rem Port %1u; State %s;", szLocalIp, ntohs((unsigned short) (0x0000FFFF pTcpTable-table[i].dwLocalPort)), szRemIp, ntohs((unsigned short)(0x0000FFFF dwRemotePort)), strState); lList.AddString(prtStr); } } free(pTcpTable); }

У функции GetTcpTable три параметра:

структура типа PMIB_TCPTABLE;

размер структуры, указанной в качестве первого параметра;

признак сортировки — если указано TRUE, то таблица будет отсортирована по номеру порта, иначе данные будут представлены в перемешанном виде.

Если в качестве первых двух параметров указать нулевое значение, то во втором параметре будет получен необходимый размер для хранения структур PMIB_TCPTABLE. Этот прием мы уже не раз использовали в главе 5.

Память определенного размера выделяется функцией malloc. В данном случае это необязательно делать в глобальной области.

Повторный вызов функции GetTcpTable позволяет через первый параметр (переменная рТсрTаblе типа PMIB_TCPTABLE) получить данные о состоянии всех TCP-портов. Их количество находится в параметре dwNumEntries структуры рТсрTаblе. Информацию об определенном порте можно узнать из параметра table[i], где i — номер порта. Этот параметр тоже является структурой, и в нем нас интересуют следующие элементы:

dwState — состояние порта. Этот параметр может принимать различные значения (MIB_TCP_STATE_LISTEN, MIB_TCP_STATE_CLOSED и т. д.). Список всех констант можно найти в коде программы или в справочной системе. Назначение констант просто определить, достаточно только внимательно посмотреть на код из листинга 6.3;

dwLocalPort — локальный порт;

dwRemotePort — удаленный порт;

dwLocalAddr — локальный адрес;

dwRemoteAddr — удаленный адрес.

В примере запускается бесконечный цикл, который перебирает все записи из параметра table, и информация добавляется в список List Box.



6.4. Результат работы программы IPState

Для правильной компиляции программы в начале модуля надо подключить три заголовочных файла:



#include iphlpapi.h
#include assert.h
#include winsock2.h

В свойствах проекта, в разделе Linker/Input в пункте Additional Dependencies нужно добавить две библиотеки IPHlpApi.lib и ws2_32.lib ( 6.5).

Для получения таблицы UDP- портов используется функция GetUdpTable. Она работает аналогично, но узнать можно только локальный адрес и локальный порт, потому что протокол UDP не устанавливает соединения, и нет сведений об удаленном компьютере.

Давайте добавим в программу кнопку UDP Table, а по ее нажатии должен будет выполняться код из листинга 6.4.



6.5. Подключение библиотек

Листинг 6.4. Получение таблицы состояния UDP-портов
void CIPStateDlg::OnBnClickedButton2() { DWORD dwStatus = NO_ERROR; PMIB_UDPTABLE pUdpTable = NULL; DWORD dwActualSize = 0;

dwStatus = GetUdpTable(pUdpTable, dwActualSize, TRUE);

pUdpTable = (PMIB_UDPTABLE) malloc(dwActualSize); assert(pUdpTable);

dwStatus = GetUdpTable(pUdpTable, dwActualSize, TRUE);

if (dwStatus != NO_ERROR) { AfxMessageBox("Couldn't get udp connection table."); free(pUdpTable); return; }

struct in_addr inadLocal; if (pUdpTable != NULL) { lList.AddString("================================================="); lList.AddString("UDP table:"); for (UINT i = 0; i pUdpTable-dwNumEntries; ++i) { inadLocal.s_addr = pUdpTable-table[i].dwLocalAddr;

char prtStr[1000]; sprintf(prtStr, "Loc Addr %1s; Loc Port %1u", inet_ntoa(inadLocal), ntohs((unsigned short)(0x0000FFFF pUdpTable-table[i].dwLocalPort))); lList.AddString(prtStr); } } free(pUdpTable); }

Код для получения информации о UDP похож на тот, что использовался для протокола TCP, и вам не составит труда разобраться с происходящим.

Примечание
Исходный код примера, описанного в этом разделе, вы можете найти на компакт - диске в каталоге \Demo\Chapter6\IPState.

Содержание раздела