Итак давайте приступим к написанию сканера. Для этого нам понадобиться библиотека winsock2. Найти ее можно на сайте www.cydsoft.com/vr-online в разделе заголовочные файлы. Скачали? Теперь перетащите файлы библиотеки winsock в %pathtodelphi%delphilib, чтобы Delphi смог найти наши файлы.
Давайте рассмотрим основные функции winsock. Для того, чтобы написать сканер (или другое сетевое приложение) нам понадобиться Socket.
Функции :
1. WSAStartUp(wVersionRequired : Word, var WSAData : TWSAData);
1. Для того, чтобы начать работать с winsock его нужно сначала стартовать. Как раз эта функция предназначена для этого. В качестве первого параметра ей нужно передать версию, второй параметр - это переменная, которая возвратит мне информацию о winsock.
2. WSACleanUp(Sock : TSocket);
2. Функция для уничтожения из памяти PC winsock. В качестве параметра ей нужно передать сокет.
3. socket(af : Integer, type : Integer, protocol : Integer);
3. Функция для создания сокета. В первый параметр нужно передать функцию подключения (AF_INET, PF_INET), второй параметр - тип подключения, и третий параметр - это протокол подключения (для TCP - это SOCK_STREAM, a для UDP - это SOCK_DGRAM).
4. connect(s : Cardinal, name : PSockAddr, namelen : Integer);
4. Собствено функция для подключения. В качестве первого параметра нужно передать переменную-сокет, второй параметр - это запись типа TSockAddr, и третий параметр - это размер записи, для нахождения размера воспользуйтесь функцией SizeOf().
5. closesocket(s : Cardinal);
5. Функция для закрытия сокета. В качестве первого параметра нужно передать сокет-переменную. Итак. Все. Хватит теории. Давайте приступим к боевым действиям.
Вот исходный текст сканера. Перепешите его, а я пока растолкую в чем тут собственно дело.
program Scanner;
{$APPTYPE CONSOLE}
uses
SysUtils, WinSock2;
var
D: TWSAData; S : TSocket; A : TSockAddr; ports : Integer; PName : String; tec : PServEnt; begin writeln('Port Scanner by Dark Eagle'); writeln; if paramcount < 1 then begin writeln('Usage : '+paramstr(0)+' 127.0.0.1 1 1024'); exit; end; if WSAStartup(MAKEWORD(2,0), D) <> 0 then begin writeln('Error'); exit; end; A.sin_family := AF_INET; A.sin_addr.S_addr := inet_addr(pchar(paramstr(1))); S := socket(AF_INET, SOCK_STREAM,0); if S = INVALID_SOCKET then begin writeln('Invalid socket'); exit; end; for ports := StrToInt(paramstr(2)) to StrToInt(paramstr(3)) do begin A.sin_port := htons(ports); tec := getservbyport(htons(ports), 'TCP'); if tec = nil then PName := 'Unknown' else begin PName := tec.s_name; end; if connect(S,@A,sizeof(A))=0 then writeln(IntToStr(ports)+' '+ PName +' open') else writeln(IntToStr(ports)+' '+ PName +' close'); end; WSACleanup; closesocket(S); writeln; writeln('Scan complete'); end.
Итак в разделе uses я подключаю библиотеку winsock2. Далее идут объявления переменных. Первая переменная - это, собственно, переменная для инициализации winsock. Вторая переменная - это переменная-сокет. Она нам нужна для создания сокета. Третяя переменная - это переменная с адресом сокета. Она хранит в себе адрес сервера, на который поступает соединение. Четвёртая переменная - это переменная типа целое число. Она нужна нам для запуска цикла сканирования портов. Пятая переменная - это переменная с хранением списка портов разных сервисов. Шестая переменная - это переменная winsock, она хранит в себе все записи о сканируемых сервисах.
Далее идет сам текст программы.
В первой строке кода идет вывод информации об авторе, с помощью стандартной функции writeln. Writeln без параметров это переход на новую строку. Далее идет проверка, если сканер запущен без параметров, то выводим о правильном использовании сканера.
Потом идет проверка о правильности запуска winsock с помощью описаной раньше функции WSAStartUp. Запускаем вторую версию Winsock, если же произошли ошибки то выводим сообщение об ошибке.
Далее идет присваивание параметров. Переменная для создания соединения с сокетом. Ей присваевается тип соединения с помощью записи:
A.sin_family := AF_INET;
Эта запись говорит о типе (в нашем случае это асинхроно, т.е. блокировка). Асинхроное соединение - это соединение, когда программа забрасывает соединениями сервер, а не ждет каждого ответа. Есть и другой способ соединения - это PF_INET, он наоборот ждет каждый ответ от сервера, что не так уж хорошо.
Далее идет функция преобразования адреса сервера в спец. формат, с помощью функции inet_addr. В качестве параметра ей нужно передать адрес сервера, что я и делаю.
Потом идет создание сокета. Функцию для этого я описал ранее. Последний параметр можно проигнорировать.
Потом сравнивается сокет, если сокет равен INVALID_SOCKET, тогда выводим сообщение об ошибке. Далее запускается цикл сканирования портов, с помощью циклов for..to..do. Потом присваевается записи адреса сокета порт. Он переводиться в спец. формат с помощью функции htons(). Эта функция обязательна для преобразования портов.
Далее я присваиваю переменной tec названия повтор протокола TCP с помощью функции getservbyport(). Потом я проверяю, если переменная tec равна нулю, то записываю в переменную PName, что порт неизвестен программе, в противном случае в переменную PName заносится название порта протокола TCP. Потом опять идет проверка, и если соединение удалось, то выводим сообщение, что порт открыт и название сервиса, в противном случае выводим сообщение, что порт закрыт.
Потом очищаем из памяти PC winsock и закрываем сокет.
Вот и все. Конечно сканер будет довольно медлительным, но это можно исправить
есди добавить к сканеру несколько процессов, так сканер станет быстрым.