Поиск
Вход
Последние темы
Перепечатка материалов (в любом виде) с данного сайта без письменного разрешения администратора запрещена.
Copyright ©2010-2011 Mine.ChudoForum.Ru - Все права защищены
Система удалённого администрирования
Страница 1 из 1
Система удалённого администрирования
Все начинается с запуска Делфи Client/Server , и вы должны иметь навыки программирования на нем.
В Винде должен быть установлен протокол TCP/IP. Это все должно работать
и на Делфи 4 и 5, а на Делфи 3 не проверял. После запуска Делфи создаем новый проект. Во вкладке
"Internet" выбираем компонент Server Socket и кидаем его на форму. В свойстве компонента
ServerSocket1 "port", в объект-инспекторе, установите по вкусу, но учтите, что порты примерно до
1000 уже заняты сервисными программами Интернета, например порт 80, это WWW сервер, порт 21 FTP
сервер, 110 и 25 для работы с почтой и так далее, мы возьмём 33333. Во вкладке Win32 выберем
компонент RichEdit и скидываем его на форму. В свойстве RichEdit Algin выбираем Client. Во
вкладке инспектора выберем объект Form1 и во вкладке Events выберем событие onCreate,
происходящее при создании формы. Впишем строчку
ServerSocket1.Active:=True;
Теперь, при запуске приложения наш сервер будет активизироваться на порту 33333.
У нашего компонента ServerSocket1 выберем событие ОnClientRead, происходящее при
передаче на сервер информации. Объявим переменную а : string , и в секции begin end;
напишем:
a:=Socket.ReceiveText;
RichEdit1.Lines.Add(a);// Ведем лог сообщений
if a = 'helo' then ServerSocket1.Socket.Connections[0].SendText('Hello, i`m you server');
Все будет выглядеть примерно так:
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
a:string;
begin
a:=Socket.ReceiveText;
RichEdit1.Lines.Add(a);
if a = 'helo' then Socket.SendText('Hello, i`m you server');
end;
Разберем немного эту программу. При получении сообщения ServerSocket вызывает событие OnClientRead,
передовая переменную Socket, имеющую тип TCustomWinSocket. В Socket.ReceiveText находится текст,
переданный серверу. Выводим текст, переданный нам в окно лога, которое представляет собой
компонент RichEdit. Далее идет проверка полученных данных, и если полученный текст совпадает
с какой-либо командой сервера, в нашем случае, пока одна команда 'helo', тогда клиенту передается
текст 'Hello, i`m you server'. Socket.SendText('Hello, i`m you server') - передает текст в то
соединение, из которого был получен запрос. ServerSocket может поддерживать несколько соединений,
но в данной статье мы это не будем рассматривать. Полный текст программы выглядит так:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
RichEdit1: TRichEdit;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Active:=true;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
a:string;
begin
a:=Socket.ReceiveText;
RichEdit1.Lines.Add(a);
if a = 'helo' then Socket..SendText('Hello, i`m you server');
end;
end.
Работающая программа сервер готова, теперь напишем универсальную программу-клиент.
Создаем новый проект и на форму выложим компонент StatusBar, он будет служить нам
информационной строкой сообщающей, соединен клиент с сервером или нет. Во вкладке
Standart выбираем компонент Panel и кидаем его на на форму. Свойству Algin этого компонента
присваиваем параметр alBotton. Далее кладем на эту Панель сначала компонент Edit, его свойству
Text присваиваем значение '127.0.0.1', это локальный IP нашего компьютера ( для испытания программы на нашем компе),
затем кладем кнопочку Button, свойству Caption присваиваем 'Connect', еще один компонент Edit, и
кнопочку с надписью 'Send', располагаем все это друг за другом. Далее на форму опускаем
компонент RichEdit, здесь мы будем просматривать ответ от сервера. Добавляем в любое место
формы компонент ClientSocket, и параметр 'Port' устанавливаем равный 33333, как и в нашем
сервере. В Инспекторе объектов (Object Inspector) выбираем вкладку Events. Щелкаем мышой два
раза на событии OnConnect. Вписываем строчку "StatusBar1.SimpleText:='Connect'";, выбираем
событие OnDisconnect и вписываем строчку "StatusBar1.SimpleText:='Disconnect';". Выбираем
событие OnRead и вписываем 'RichEdit1.Lines.Add(Socket.ReceiveText);'. Два раза нажимаем на
кнопке 'Connect' и в появившемся событии onClick вписываем текст:
if not constat then
begin
ClientSocket1.Address:=Edit1.text;
ClientSocket1.Active:=true;
Button2.Caption:='Disconnect';
constat:= not constat;
end
else
begin
ClientSocket1.Active:=false;
Button2.Caption:='Connect';
constat:= not constat;
end;
Переменная 'constat' показывает нам наше состояние, соединены мы с сервером или нет, и ее надо
объявить как глобальную переменную ' constat:boolean = false;' в поле var до implementation.
Нажимаем два раза на кнопку 'Send' и вписываем строчку: "ClientSocket1.Socket.SendText(Edit2.text);".
Сохраним проект. Юнит сохраним как cliUnit1, а имя проекту дадим Client. Итак, весь текст должен
выглядеть так:
unit cliUnit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, ComCtrls, ScktComp;
type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
RichEdit1: TRichEdit;
Panel1: TPanel;
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Button1: TButton;
Button2: TButton;
StatusBar1: TStatusBar;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
constat:boolean = false;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Socket.SendText(Edit2.text);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if not constat then
begin
ClientSocket1.Address:=Edit1.text;
ClientSocket1.Active:=true;
Button2.Caption:='Disconnect';
constat:= not constat;
end
else
begin
ClientSocket1.Active:=false;
Button2.Caption:='Connect';
constat:= not constat;
end;
end;
procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
begin
RichEdit1.Lines.Add(Socket.ReceiveText);
end;
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText:='Connect';
end;
procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText:='Disconnect';
end;
end.
Все, пока наш клиент подходит для большинства целей. Откомпилируем этот проект, зайдем в
директорию с нашим проектом любой оболочкой и запустим нашу программу клиент. Загрузим наш проект
сервер. Из под Делфи запустим на выполнение. Итак, на экране запущены два наших проекта -
Server из Делфи, Client как отдельная программа. В клиенте нажимаем кнопку 'Connect', и
если все сделано правильно и на компьютере установлен протокол TCP/IP, то в статус баре должна
будет появиться надпись 'Connect'. Вписываем в текстовое поле возле кнопки 'Send', слово helo
и нажимаем на кнопку 'Send'. В текстовом поле RichEdit появилась надпись 'Hello, i`m you server'.
Наш сервер нас понимает и отвечает!!. Начало положено. Определим, какие функции должна
выполнять простенькая программа удаленного администрирования.
1. Закачивать, удалять и запускать программы на удаленном компьютере.
2. Просматривать и удалять процессы запущенные на удаленном компьютере.
3. Получать копию экрана с удаленного компьютера.
4. Запускать программы на сервере.
5. По возможности быть невидимой.
Для работы с файловой системой удаленного компьютера я предпочитаю использовать FTP соединение.
На нашей программе-сервере для этого надо установить программу FTPServer. Для этого понадобится
свободно распространяемый компонент для работы с Интернетом от Francois Piette. Установим этот
компонент в Делфи. Я выбрал более простой путь, но можно и самому попытаться написать ФТП сервер,
это требует знаний формата передачи данных по протоколу ФТП и очень хороший опыт работы с сокетом,
а пока при начальной разработке программы нам этого пока не надо, поэтому просто поставим
себе этот компонент и пойдем дальше. Выберем компонент FTPserv из вкладки FPiette и
опустим его на нашу форму. В событиях этого компонента выберем событие OnAuthenticate
и впишем следующие строчки:
Client.HomeDir:='C:\';
Client.Directory:='C:\';
При соединении на сервер, начальной директорией будет главный каталог диска С:. Теперь в
свойстве OnClientRead компонента ServerSocket допишем еще одну строчки:
if a= 'StartFTP' then
begin
FTPServer1.Start;
Socket.SendText('FTP Server started');
end;
if a= 'StopFTP' then
begin
FTPServer1.DisconnectAll;
FTPServer1.Stop;
Socket.SendText('FTP Server stoped');
end;
И запустим проект на выполнение. (Если будет выдаваться ошибка 'неизвестный идентификатор
TFtpCtrlSocket', добавьте в поле uses надпись FTPSRVC ) Программа клиент должна уже быть
запущена. Нажмем кнопку 'Connect' и в поле для передачи текста введем Star[Только модераторы имеют право видеть эту ссылку] Если сервер
ответит 'FTP Server started' значит все работает. Запускаем любой FTP клиент и коннектимся на IP
127.0.0.1 без ввода пароля. При соединении вам будет доступен диск С: полностью, можете удалять,
записывать и читать файлы. Мы получили полный доступ к диску С:. Первое задание готово.
Едем дальше.
Возьмемся за процессы. В системе Win32 каждый процесс работает независимо друг от друга, а это
значит, что нашу программу Windows останавливает каждый раз, когда передает управление другой
программе, и в то время, когда программа стоит, могут появляться и исчезать процессы, которые
наша программа не сможет увидеть. Но из этого есть выход. В Виндовс есть такая штука как
CreateToolhelp32Snapshot, с помощью этой функции можно снять снимок всех процессов в памяти
в данный момент. Эта функция работает на уровне ядра системы и создана для отладки приложений в
режиме Debug. Воспользуемся ею.
В стандартных юнитах Делфи есть юнит, который содержит в себе объявления этой функции.
Для этого добавим в uses главной формы Form1 строчку tlhelp32. Теперь можно будет воспользоваться
этой функцией. Создадим две новые процедуры listproc и delproc и объявим их в секции private:
private
procedure listproc;
procedure delproc(numb:string);
public
Процедура delproc принимает параметр numb, содержащий номер удаляемого процесса. Опишем эти
процедуры. Начнем с listproc. Текст этой процедуры будет выглядеть так.
procedure TForm1.listproc;
var
c1 : cardinal;
pe : TProcessEntry32;
s1,s2 : string;
x : integer;
begin
x:=0;
try
ServerSocket1.Socket.Connections[0].SendText('Listing processes . . .'+#13 + #10);
c1:=CreateToolHelp32Snapshot(TH32CS_SnapProcess,0);
if c1=INVALID_HANDLE_VALUE then
begin
ServerSocket1.Socket.Connections[0].SendText('Listing processes failed'+#13 + #10);
exit;
end;
try
pe.dwSize:=sizeOf(pe);
if Process32First(c1,pe) then
repeat
inc(x);
s1:=ExtractFileName(pe.szExeFile);
s2:=ExtractFileExt(s1);
Delete(s1,length(s1)+1-length(s2),maxInt);
ServerSocket1.Socket.Connections[0].SendText(IntToStr(x)+' - '+s1+' : '+pe.szExeFile+#13#10);
until not Process32Next(c1,pe);
finally CloseHandle(c1) end;
except end;
end;
Разберем ее по порядку. В секции var мы объявили несколько переменных, с1 - в эту переменную мы
помещаем хэндл, возвращенный функцией CreateToolHelp32Snapshot, хэндл указывает на снимок процессов.
pe : TProcessEntry32, структура, куда будут помещаться данные о процессе, x - счетчик.
Сначала обнуляем счетчик x. Получаем хэндл от CreateToolHelp32Snapshot, и если хэндл не
получен сообщаем об этом клиенту и выход и процедуры. Сообщение выглядит так
ServerSocket1.Socket.Connections[0].SendText('Listing processes . . .'+#13 + #10); Разберем это.
Как было сказано ранее, мы не стали использовать многопользовательское свойство сервера, мы
будем использовать только одно соединение, поэтому мы ввели в тест строчку Connections[0],
указывающую на то, что текст надо передавать в самое первое соединение. Если хэндл получен,
то в структуре TProcessEntry32 в поле dwSize укажем размер структуры в памяти и начнем цикл
repeat для обработки найденных процессов, увеличивая счетчик процессов. При обработки строк,
для более понятного вида выделим имя процесса и передадим клиенту номер процесса, имя и полный
путь к этому процессу. После завершения цикла закрываем хэндл.
Функция DELPROC:
procedure TForm1.delproc(numb:string);
var
c1 : cardinal;
pe : TProcessEntry32;
s1,s2 : string;
x : integer;
begin
x:=0;
try
StrToInt(numb);
except
ServerSocket1.Socket.Connections[0].SendText('Вы ввели неправильное число'+#13 + #10);
exit;
end;
try
ServerSocket1.Socket.Connections[0].SendText('Listing processes . . .'+#13 + #10);
c1:=CreateToolHelp32Snapshot(TH32CS_SnapProcess,0); // Получение хэндля списка процесов
if c1=INVALID_HANDLE_VALUE then // Если по какой либо причине не удалось получить хэндл
begin
ServerSocket1.Socket.Connections[0].SendText('Listing processes failed'+#13 + #10);
exit;
end;
try // Все нормально, хэндл получен
pe.dwSize:=sizeOf(pe);
if Process32First(c1,pe) then
repeat
inc(x); // Увеличиваем счетчик процесов
s1:=ExtractFileName(pe.szExeFile);
s2:=ExtractFileExt(s1);
Delete(s1,length(s1)+1-length(s2),maxInt); // Переменной s1 присваеваем имя процесса
if x = StrToInt(numb) then // сравнение процесса с переданным номером для удаления
if TerminateProcess(OpenProcess(PROCESS_ALL_ACCESS, False, pe.th32ProcessID), 1) then
ServerSocket1.Socket.Connections[0].SendText('Killed '+s1+' : '+ pe.szExeFile +#13 + #10)
else
ServerSocket1.Socket.Connections[0].SendText('Not killed '+s1+' : '+ pe.szExeFile +#13 + #10);
until not Process32Next(c1,pe);
finally CloseHandle(c1) end;
except end;
end;
Эта процедура почти полностью совпадает с процедурой листинга процессов, но добавлена проверка на
дополнительный параметр, номер процесса, который надо удалить из системы. Текст одинаковый поэтому
остановимся только на описании удаления процесса. Win32API функция TerminateProcess берет
переданный ей хэндл процесса и пытается удалить процесс из памяти. Получить хэндл процесса
можно функцией OpenProcess(PROCESS_ALL_ACCESS, False, pe.th32ProcessID), где в параметрах
указываем индентификатор процесса pe.th32ProcessID, и PROCESS_ALL_ACCESS все флаги доступа
к процессу. После вызова проверяем, если вызов прошел успешно, то передаем клиенту, что
процесс уничтожен, иначе передаем сообщение об ошибке.
Теперь в свойстве OnClientRead прописываем вызов этих процедур:
if a = 'lp' then listproc;
if copy(a,1,2) = 'dp' then delproc(copy(a,4,Length(a)-3));
С первой строчкой все понятно, а во второй строчке функцией copy выделяем первые две буквы,
проверяем их на строчку типа 'dp', и, если совпадает, то передаем в процедуру delproc оставшуюся
половину строки, содержащую номер процесса в системе. Запускаем программу на выполнение.
Переключаем задачу на программу клиент и нажимаем кнопку connect. Вводим строчку lp и передаем
это значение нашему серверу. В ответ мы получим пронумерованный список процессов. Используем этот
номер для удаления процесса. Запустим любую программу, например, "Пасьянс косынка" . Просмотрим
список процессов. Пошлем серверу строчу "lp". Ищем в списке процессов процесс 19 - SOL : C:\WINDOWS\SOL.EXE,
у меня он в списке под номером девятнадцать. Попытаемся удалить этот процесс.
Пишем dp 19 и нажимаем кнопку Send. Получили строчку "Killed SOL : C:\WINDOWS\SOL.EXE",
значит, все ОК, процесс удален. Со второй задачей справились.
Задание 3. Получить копию экрана с удаленного компьютера.
В OnClientRead прописываем вызов:
if a = 'scr' then getscreen;
Объявляем эту процедуру в секции private:
procedure getscreen;
Добавляем в uses строчку JPEG, чтоб можно было работать с файлами JPEG формата, и ExtCtrls,
чтоб можно было объявить TImage.
Теперь описываем саму процедуру.
procedure TForm1.getscreen;
var
bmp: Graphics.TBitmap;
DC: HDC;
MyJpeg: TJpegImage;
Image1: TImage;
begin
try
bmp:=Graphics.TBitmap.Create;
bmp.Height:=Screen.Height;
bmp.Width:=Screen.Width;
DC:=GetDC(0); //Дескpиптоp экpана
bitblt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY);
Image1:= TImage.Create(self);
MyJpeg:= TJpegImage.Create;
bmp.IgnorePalette:=true;
Image1.Picture.Assign(bmp);
MyJpeg.Assign(Image1.Picture.Bitmap);
MyJpeg.SaveToFile('c:\Screen.jpg');
ReleaseDC(0, DC);
ServerSocket1.Socket.Connections[0].SendText(windir+'\Screen.jpg created (use ftp)'+#13 + #10);
Image1.free;
MyJpeg.free;
except
ServerSocket1.Socket.Connections[0].SendText('Screen bitmap not created '+#13 + #10);
end;
end;
Распишем поподробнее. Чтоб создать копию экрана, надо сначала получить указатель на этот экран,
и тогда уже с ним и работать. Этим заведуют эти функции
DC:=GetDC(0); //Дескpиптоp экpана
bitblt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY); // копирование экрана в TBitmap
Далее идет простенькая программка преобразования файла формата BMP в JPG, и, если произошла ошибка,
то сообщается об этом. Запускаем на выполнение и в клиенте вводим строчку 'scr' и, если не
возникнет каких-либо непредвиденных ошибок, то на диске С создастся файл Screen.jpg, содержащий
копию экрана в данный момент времени, и его можно будет забрать с помощью FTP клиента.
(запустив предварительно перед этим сервер, который мы уже себе поставили)
Теперь немного поговорим о том, как можно спрятаться из панели задач (TaskBar).
В метод onCreate Form1 добавляем две строчки
ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,GetWindowLong(Application.Handle, GWL_EXSTYLE) or
WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);
В OnClientRead прописываем две строчки для управления видимостью нашего сервера:
if a = 'show' then Form1.Visible:=true;
if a = 'hide' then Form1.Visible:=false;
В Делфи в меню Project выбрать меню View Source, откроется файл dpr вашего проекта, и после
строчки Application.Initialize добавляем строчку Application.ShowMainForm:=False;. Все, теперь
при запуске программы ее не будет видно. Чтоб увидеть, надо будет дать команду серверу 'show',
а чтоб спрятать 'hide'.
Ну теперь надо маленькой программе удаленного администрирование научиться запускать какие-нибудь
программы на сервере. Для этого воспользуемся стандартной функцией Виндовс ShellExecute, ее полное
описание представлено в справке по Win32, которая входит в комплект с Делфи, мы будем
использовать ее так:
ShellExecute (0, 'open', FILE, PARAM, 'c:\', 1);
где FILE запускаемый файл, который может быть как EXE, так и например DOC, Windows запустит его
с помощью программ, на которые зарегистрировано данное расширение, на DOC, например,
Microsoft Word. А PARAM параметр к запускаемой программе, если это выполняемый модуль,
такой как EXE.
В OnClientRead прописываем строчку для запуска программ:
var
filepath: string;
param: string;
после строчки begin
if copy(a,1,6) = 'start ' then
begin
a:= copy(a,7,Length(a)-6); //получаем строку без start
if pos(' ',a)> 0 then filepath:= copy(a,1,pos(' ',a)-1) // Если передано без параметров то просто присвоим
else filepath:=a; //значение переменной filepath
if filepath <> a then param:= copy(a,pos(' ',a)+1,Length(a)-pos(' ',a));
ServerSocket1.Socket.Connections[0].SendText('Start: '+filepath);
ShellExecute (0, 'open', PChar(filepath), PChar(param), '', 1);
end;
Для законченного вида программы вставляем маленький HELP и команду остановки сервера:
if a = 'stopserver' then Form1.close;
if a = 'help' then
begin
Socket.SendText('Программа удаленного администрирования v 1.0');
Socket.SendText('help - этот экран помощи');
Socket.SendText('StartFTP - запуск FTP сервера');
Socket..SendText('StopFTP - остановка FTP сервера');
Socket..SendText('lp - показать все процессы в системе');
Socket..SendText('dp - удалить процесс под номером указанным после запятой');
Socket.SendText('scr - создать графический файл с копией экрана');
Socket.SendText('show - показать программу сервер на сервере');
Socket.SendText('hide - спрятать программу сервер на сервере');
Socket..SendText('stop - остановка сервера');
end;
Ну вроде ВСЕ, программа работает и выполняет некоторые функции, правда, небольшие, но зато
написанные своими руками! На этом пока все, но это еще не конец, со временем будем дорабатывать
программу!!!!
В Винде должен быть установлен протокол TCP/IP. Это все должно работать
и на Делфи 4 и 5, а на Делфи 3 не проверял. После запуска Делфи создаем новый проект. Во вкладке
"Internet" выбираем компонент Server Socket и кидаем его на форму. В свойстве компонента
ServerSocket1 "port", в объект-инспекторе, установите по вкусу, но учтите, что порты примерно до
1000 уже заняты сервисными программами Интернета, например порт 80, это WWW сервер, порт 21 FTP
сервер, 110 и 25 для работы с почтой и так далее, мы возьмём 33333. Во вкладке Win32 выберем
компонент RichEdit и скидываем его на форму. В свойстве RichEdit Algin выбираем Client. Во
вкладке инспектора выберем объект Form1 и во вкладке Events выберем событие onCreate,
происходящее при создании формы. Впишем строчку
ServerSocket1.Active:=True;
Теперь, при запуске приложения наш сервер будет активизироваться на порту 33333.
У нашего компонента ServerSocket1 выберем событие ОnClientRead, происходящее при
передаче на сервер информации. Объявим переменную а : string , и в секции begin end;
напишем:
a:=Socket.ReceiveText;
RichEdit1.Lines.Add(a);// Ведем лог сообщений
if a = 'helo' then ServerSocket1.Socket.Connections[0].SendText('Hello, i`m you server');
Все будет выглядеть примерно так:
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
a:string;
begin
a:=Socket.ReceiveText;
RichEdit1.Lines.Add(a);
if a = 'helo' then Socket.SendText('Hello, i`m you server');
end;
Разберем немного эту программу. При получении сообщения ServerSocket вызывает событие OnClientRead,
передовая переменную Socket, имеющую тип TCustomWinSocket. В Socket.ReceiveText находится текст,
переданный серверу. Выводим текст, переданный нам в окно лога, которое представляет собой
компонент RichEdit. Далее идет проверка полученных данных, и если полученный текст совпадает
с какой-либо командой сервера, в нашем случае, пока одна команда 'helo', тогда клиенту передается
текст 'Hello, i`m you server'. Socket.SendText('Hello, i`m you server') - передает текст в то
соединение, из которого был получен запрос. ServerSocket может поддерживать несколько соединений,
но в данной статье мы это не будем рассматривать. Полный текст программы выглядит так:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
RichEdit1: TRichEdit;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Active:=true;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
a:string;
begin
a:=Socket.ReceiveText;
RichEdit1.Lines.Add(a);
if a = 'helo' then Socket..SendText('Hello, i`m you server');
end;
end.
Работающая программа сервер готова, теперь напишем универсальную программу-клиент.
Создаем новый проект и на форму выложим компонент StatusBar, он будет служить нам
информационной строкой сообщающей, соединен клиент с сервером или нет. Во вкладке
Standart выбираем компонент Panel и кидаем его на на форму. Свойству Algin этого компонента
присваиваем параметр alBotton. Далее кладем на эту Панель сначала компонент Edit, его свойству
Text присваиваем значение '127.0.0.1', это локальный IP нашего компьютера ( для испытания программы на нашем компе),
затем кладем кнопочку Button, свойству Caption присваиваем 'Connect', еще один компонент Edit, и
кнопочку с надписью 'Send', располагаем все это друг за другом. Далее на форму опускаем
компонент RichEdit, здесь мы будем просматривать ответ от сервера. Добавляем в любое место
формы компонент ClientSocket, и параметр 'Port' устанавливаем равный 33333, как и в нашем
сервере. В Инспекторе объектов (Object Inspector) выбираем вкладку Events. Щелкаем мышой два
раза на событии OnConnect. Вписываем строчку "StatusBar1.SimpleText:='Connect'";, выбираем
событие OnDisconnect и вписываем строчку "StatusBar1.SimpleText:='Disconnect';". Выбираем
событие OnRead и вписываем 'RichEdit1.Lines.Add(Socket.ReceiveText);'. Два раза нажимаем на
кнопке 'Connect' и в появившемся событии onClick вписываем текст:
if not constat then
begin
ClientSocket1.Address:=Edit1.text;
ClientSocket1.Active:=true;
Button2.Caption:='Disconnect';
constat:= not constat;
end
else
begin
ClientSocket1.Active:=false;
Button2.Caption:='Connect';
constat:= not constat;
end;
Переменная 'constat' показывает нам наше состояние, соединены мы с сервером или нет, и ее надо
объявить как глобальную переменную ' constat:boolean = false;' в поле var до implementation.
Нажимаем два раза на кнопку 'Send' и вписываем строчку: "ClientSocket1.Socket.SendText(Edit2.text);".
Сохраним проект. Юнит сохраним как cliUnit1, а имя проекту дадим Client. Итак, весь текст должен
выглядеть так:
unit cliUnit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, ComCtrls, ScktComp;
type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
RichEdit1: TRichEdit;
Panel1: TPanel;
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Button1: TButton;
Button2: TButton;
StatusBar1: TStatusBar;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
constat:boolean = false;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Socket.SendText(Edit2.text);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if not constat then
begin
ClientSocket1.Address:=Edit1.text;
ClientSocket1.Active:=true;
Button2.Caption:='Disconnect';
constat:= not constat;
end
else
begin
ClientSocket1.Active:=false;
Button2.Caption:='Connect';
constat:= not constat;
end;
end;
procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
begin
RichEdit1.Lines.Add(Socket.ReceiveText);
end;
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText:='Connect';
end;
procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText:='Disconnect';
end;
end.
Все, пока наш клиент подходит для большинства целей. Откомпилируем этот проект, зайдем в
директорию с нашим проектом любой оболочкой и запустим нашу программу клиент. Загрузим наш проект
сервер. Из под Делфи запустим на выполнение. Итак, на экране запущены два наших проекта -
Server из Делфи, Client как отдельная программа. В клиенте нажимаем кнопку 'Connect', и
если все сделано правильно и на компьютере установлен протокол TCP/IP, то в статус баре должна
будет появиться надпись 'Connect'. Вписываем в текстовое поле возле кнопки 'Send', слово helo
и нажимаем на кнопку 'Send'. В текстовом поле RichEdit появилась надпись 'Hello, i`m you server'.
Наш сервер нас понимает и отвечает!!. Начало положено. Определим, какие функции должна
выполнять простенькая программа удаленного администрирования.
1. Закачивать, удалять и запускать программы на удаленном компьютере.
2. Просматривать и удалять процессы запущенные на удаленном компьютере.
3. Получать копию экрана с удаленного компьютера.
4. Запускать программы на сервере.
5. По возможности быть невидимой.
Для работы с файловой системой удаленного компьютера я предпочитаю использовать FTP соединение.
На нашей программе-сервере для этого надо установить программу FTPServer. Для этого понадобится
свободно распространяемый компонент для работы с Интернетом от Francois Piette. Установим этот
компонент в Делфи. Я выбрал более простой путь, но можно и самому попытаться написать ФТП сервер,
это требует знаний формата передачи данных по протоколу ФТП и очень хороший опыт работы с сокетом,
а пока при начальной разработке программы нам этого пока не надо, поэтому просто поставим
себе этот компонент и пойдем дальше. Выберем компонент FTPserv из вкладки FPiette и
опустим его на нашу форму. В событиях этого компонента выберем событие OnAuthenticate
и впишем следующие строчки:
Client.HomeDir:='C:\';
Client.Directory:='C:\';
При соединении на сервер, начальной директорией будет главный каталог диска С:. Теперь в
свойстве OnClientRead компонента ServerSocket допишем еще одну строчки:
if a= 'StartFTP' then
begin
FTPServer1.Start;
Socket.SendText('FTP Server started');
end;
if a= 'StopFTP' then
begin
FTPServer1.DisconnectAll;
FTPServer1.Stop;
Socket.SendText('FTP Server stoped');
end;
И запустим проект на выполнение. (Если будет выдаваться ошибка 'неизвестный идентификатор
TFtpCtrlSocket', добавьте в поле uses надпись FTPSRVC ) Программа клиент должна уже быть
запущена. Нажмем кнопку 'Connect' и в поле для передачи текста введем Star[Только модераторы имеют право видеть эту ссылку] Если сервер
ответит 'FTP Server started' значит все работает. Запускаем любой FTP клиент и коннектимся на IP
127.0.0.1 без ввода пароля. При соединении вам будет доступен диск С: полностью, можете удалять,
записывать и читать файлы. Мы получили полный доступ к диску С:. Первое задание готово.
Едем дальше.
Возьмемся за процессы. В системе Win32 каждый процесс работает независимо друг от друга, а это
значит, что нашу программу Windows останавливает каждый раз, когда передает управление другой
программе, и в то время, когда программа стоит, могут появляться и исчезать процессы, которые
наша программа не сможет увидеть. Но из этого есть выход. В Виндовс есть такая штука как
CreateToolhelp32Snapshot, с помощью этой функции можно снять снимок всех процессов в памяти
в данный момент. Эта функция работает на уровне ядра системы и создана для отладки приложений в
режиме Debug. Воспользуемся ею.
В стандартных юнитах Делфи есть юнит, который содержит в себе объявления этой функции.
Для этого добавим в uses главной формы Form1 строчку tlhelp32. Теперь можно будет воспользоваться
этой функцией. Создадим две новые процедуры listproc и delproc и объявим их в секции private:
private
procedure listproc;
procedure delproc(numb:string);
public
Процедура delproc принимает параметр numb, содержащий номер удаляемого процесса. Опишем эти
процедуры. Начнем с listproc. Текст этой процедуры будет выглядеть так.
procedure TForm1.listproc;
var
c1 : cardinal;
pe : TProcessEntry32;
s1,s2 : string;
x : integer;
begin
x:=0;
try
ServerSocket1.Socket.Connections[0].SendText('Listing processes . . .'+#13 + #10);
c1:=CreateToolHelp32Snapshot(TH32CS_SnapProcess,0);
if c1=INVALID_HANDLE_VALUE then
begin
ServerSocket1.Socket.Connections[0].SendText('Listing processes failed'+#13 + #10);
exit;
end;
try
pe.dwSize:=sizeOf(pe);
if Process32First(c1,pe) then
repeat
inc(x);
s1:=ExtractFileName(pe.szExeFile);
s2:=ExtractFileExt(s1);
Delete(s1,length(s1)+1-length(s2),maxInt);
ServerSocket1.Socket.Connections[0].SendText(IntToStr(x)+' - '+s1+' : '+pe.szExeFile+#13#10);
until not Process32Next(c1,pe);
finally CloseHandle(c1) end;
except end;
end;
Разберем ее по порядку. В секции var мы объявили несколько переменных, с1 - в эту переменную мы
помещаем хэндл, возвращенный функцией CreateToolHelp32Snapshot, хэндл указывает на снимок процессов.
pe : TProcessEntry32, структура, куда будут помещаться данные о процессе, x - счетчик.
Сначала обнуляем счетчик x. Получаем хэндл от CreateToolHelp32Snapshot, и если хэндл не
получен сообщаем об этом клиенту и выход и процедуры. Сообщение выглядит так
ServerSocket1.Socket.Connections[0].SendText('Listing processes . . .'+#13 + #10); Разберем это.
Как было сказано ранее, мы не стали использовать многопользовательское свойство сервера, мы
будем использовать только одно соединение, поэтому мы ввели в тест строчку Connections[0],
указывающую на то, что текст надо передавать в самое первое соединение. Если хэндл получен,
то в структуре TProcessEntry32 в поле dwSize укажем размер структуры в памяти и начнем цикл
repeat для обработки найденных процессов, увеличивая счетчик процессов. При обработки строк,
для более понятного вида выделим имя процесса и передадим клиенту номер процесса, имя и полный
путь к этому процессу. После завершения цикла закрываем хэндл.
Функция DELPROC:
procedure TForm1.delproc(numb:string);
var
c1 : cardinal;
pe : TProcessEntry32;
s1,s2 : string;
x : integer;
begin
x:=0;
try
StrToInt(numb);
except
ServerSocket1.Socket.Connections[0].SendText('Вы ввели неправильное число'+#13 + #10);
exit;
end;
try
ServerSocket1.Socket.Connections[0].SendText('Listing processes . . .'+#13 + #10);
c1:=CreateToolHelp32Snapshot(TH32CS_SnapProcess,0); // Получение хэндля списка процесов
if c1=INVALID_HANDLE_VALUE then // Если по какой либо причине не удалось получить хэндл
begin
ServerSocket1.Socket.Connections[0].SendText('Listing processes failed'+#13 + #10);
exit;
end;
try // Все нормально, хэндл получен
pe.dwSize:=sizeOf(pe);
if Process32First(c1,pe) then
repeat
inc(x); // Увеличиваем счетчик процесов
s1:=ExtractFileName(pe.szExeFile);
s2:=ExtractFileExt(s1);
Delete(s1,length(s1)+1-length(s2),maxInt); // Переменной s1 присваеваем имя процесса
if x = StrToInt(numb) then // сравнение процесса с переданным номером для удаления
if TerminateProcess(OpenProcess(PROCESS_ALL_ACCESS, False, pe.th32ProcessID), 1) then
ServerSocket1.Socket.Connections[0].SendText('Killed '+s1+' : '+ pe.szExeFile +#13 + #10)
else
ServerSocket1.Socket.Connections[0].SendText('Not killed '+s1+' : '+ pe.szExeFile +#13 + #10);
until not Process32Next(c1,pe);
finally CloseHandle(c1) end;
except end;
end;
Эта процедура почти полностью совпадает с процедурой листинга процессов, но добавлена проверка на
дополнительный параметр, номер процесса, который надо удалить из системы. Текст одинаковый поэтому
остановимся только на описании удаления процесса. Win32API функция TerminateProcess берет
переданный ей хэндл процесса и пытается удалить процесс из памяти. Получить хэндл процесса
можно функцией OpenProcess(PROCESS_ALL_ACCESS, False, pe.th32ProcessID), где в параметрах
указываем индентификатор процесса pe.th32ProcessID, и PROCESS_ALL_ACCESS все флаги доступа
к процессу. После вызова проверяем, если вызов прошел успешно, то передаем клиенту, что
процесс уничтожен, иначе передаем сообщение об ошибке.
Теперь в свойстве OnClientRead прописываем вызов этих процедур:
if a = 'lp' then listproc;
if copy(a,1,2) = 'dp' then delproc(copy(a,4,Length(a)-3));
С первой строчкой все понятно, а во второй строчке функцией copy выделяем первые две буквы,
проверяем их на строчку типа 'dp', и, если совпадает, то передаем в процедуру delproc оставшуюся
половину строки, содержащую номер процесса в системе. Запускаем программу на выполнение.
Переключаем задачу на программу клиент и нажимаем кнопку connect. Вводим строчку lp и передаем
это значение нашему серверу. В ответ мы получим пронумерованный список процессов. Используем этот
номер для удаления процесса. Запустим любую программу, например, "Пасьянс косынка" . Просмотрим
список процессов. Пошлем серверу строчу "lp". Ищем в списке процессов процесс 19 - SOL : C:\WINDOWS\SOL.EXE,
у меня он в списке под номером девятнадцать. Попытаемся удалить этот процесс.
Пишем dp 19 и нажимаем кнопку Send. Получили строчку "Killed SOL : C:\WINDOWS\SOL.EXE",
значит, все ОК, процесс удален. Со второй задачей справились.
Задание 3. Получить копию экрана с удаленного компьютера.
В OnClientRead прописываем вызов:
if a = 'scr' then getscreen;
Объявляем эту процедуру в секции private:
procedure getscreen;
Добавляем в uses строчку JPEG, чтоб можно было работать с файлами JPEG формата, и ExtCtrls,
чтоб можно было объявить TImage.
Теперь описываем саму процедуру.
procedure TForm1.getscreen;
var
bmp: Graphics.TBitmap;
DC: HDC;
MyJpeg: TJpegImage;
Image1: TImage;
begin
try
bmp:=Graphics.TBitmap.Create;
bmp.Height:=Screen.Height;
bmp.Width:=Screen.Width;
DC:=GetDC(0); //Дескpиптоp экpана
bitblt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY);
Image1:= TImage.Create(self);
MyJpeg:= TJpegImage.Create;
bmp.IgnorePalette:=true;
Image1.Picture.Assign(bmp);
MyJpeg.Assign(Image1.Picture.Bitmap);
MyJpeg.SaveToFile('c:\Screen.jpg');
ReleaseDC(0, DC);
ServerSocket1.Socket.Connections[0].SendText(windir+'\Screen.jpg created (use ftp)'+#13 + #10);
Image1.free;
MyJpeg.free;
except
ServerSocket1.Socket.Connections[0].SendText('Screen bitmap not created '+#13 + #10);
end;
end;
Распишем поподробнее. Чтоб создать копию экрана, надо сначала получить указатель на этот экран,
и тогда уже с ним и работать. Этим заведуют эти функции
DC:=GetDC(0); //Дескpиптоp экpана
bitblt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY); // копирование экрана в TBitmap
Далее идет простенькая программка преобразования файла формата BMP в JPG, и, если произошла ошибка,
то сообщается об этом. Запускаем на выполнение и в клиенте вводим строчку 'scr' и, если не
возникнет каких-либо непредвиденных ошибок, то на диске С создастся файл Screen.jpg, содержащий
копию экрана в данный момент времени, и его можно будет забрать с помощью FTP клиента.
(запустив предварительно перед этим сервер, который мы уже себе поставили)
Теперь немного поговорим о том, как можно спрятаться из панели задач (TaskBar).
В метод onCreate Form1 добавляем две строчки
ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,GetWindowLong(Application.Handle, GWL_EXSTYLE) or
WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW);
В OnClientRead прописываем две строчки для управления видимостью нашего сервера:
if a = 'show' then Form1.Visible:=true;
if a = 'hide' then Form1.Visible:=false;
В Делфи в меню Project выбрать меню View Source, откроется файл dpr вашего проекта, и после
строчки Application.Initialize добавляем строчку Application.ShowMainForm:=False;. Все, теперь
при запуске программы ее не будет видно. Чтоб увидеть, надо будет дать команду серверу 'show',
а чтоб спрятать 'hide'.
Ну теперь надо маленькой программе удаленного администрирование научиться запускать какие-нибудь
программы на сервере. Для этого воспользуемся стандартной функцией Виндовс ShellExecute, ее полное
описание представлено в справке по Win32, которая входит в комплект с Делфи, мы будем
использовать ее так:
ShellExecute (0, 'open', FILE, PARAM, 'c:\', 1);
где FILE запускаемый файл, который может быть как EXE, так и например DOC, Windows запустит его
с помощью программ, на которые зарегистрировано данное расширение, на DOC, например,
Microsoft Word. А PARAM параметр к запускаемой программе, если это выполняемый модуль,
такой как EXE.
В OnClientRead прописываем строчку для запуска программ:
var
filepath: string;
param: string;
после строчки begin
if copy(a,1,6) = 'start ' then
begin
a:= copy(a,7,Length(a)-6); //получаем строку без start
if pos(' ',a)> 0 then filepath:= copy(a,1,pos(' ',a)-1) // Если передано без параметров то просто присвоим
else filepath:=a; //значение переменной filepath
if filepath <> a then param:= copy(a,pos(' ',a)+1,Length(a)-pos(' ',a));
ServerSocket1.Socket.Connections[0].SendText('Start: '+filepath);
ShellExecute (0, 'open', PChar(filepath), PChar(param), '', 1);
end;
Для законченного вида программы вставляем маленький HELP и команду остановки сервера:
if a = 'stopserver' then Form1.close;
if a = 'help' then
begin
Socket.SendText('Программа удаленного администрирования v 1.0');
Socket.SendText('help - этот экран помощи');
Socket.SendText('StartFTP - запуск FTP сервера');
Socket..SendText('StopFTP - остановка FTP сервера');
Socket..SendText('lp - показать все процессы в системе');
Socket..SendText('dp - удалить процесс под номером указанным после запятой');
Socket.SendText('scr - создать графический файл с копией экрана');
Socket.SendText('show - показать программу сервер на сервере');
Socket.SendText('hide - спрятать программу сервер на сервере');
Socket..SendText('stop - остановка сервера');
end;
Ну вроде ВСЕ, программа работает и выполняет некоторые функции, правда, небольшие, но зато
написанные своими руками! На этом пока все, но это еще не конец, со временем будем дорабатывать
программу!!!!
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения
Вс Ноя 02 2014, 14:18 автор dimka
» Исходники игр на Паскале
Чт Окт 16 2014, 13:18 автор tqq
» Помогите разблокировать smartbuy micro CD.
Ср Сен 24 2014, 14:40 автор Unearthly
» Исходники программ на Делфи для скачивания
Ср Июл 16 2014, 08:15 автор aleator
» Как прошить телефон Nokia?
Вт Май 06 2014, 12:42 автор vovan17
» Самопроизвольное отключение ноутбука
Вт Июл 09 2013, 21:17 автор Aleksei
» МР3-плеер NEXX nf-810
Пн Июл 01 2013, 09:11 автор Vitaliy_82
» Как снять защиту от записи на MicroSD
Вт Мар 26 2013, 16:25 автор katja*****
» Как передавать большие файлы с одного компьютера на другой быстро?
Пн Окт 01 2012, 20:07 автор irko