Delphi: Как я делал убийцу червей со съемных носителей…

altAutoRunKiller II

К новому 2011 году, я написал AutoRunKiller II, правда идея появилась не сразу, началось все с написания вредилки-червя, на её основе (практически половина функций) я сделал AutoRunKiller, но это была только первая версия, её можно назвать «наброском», ну а теперь я расскажу, как можно в домашних условиях изготовить убийцу червячков и не платить за платные аналоги…

Очень благодарен нашему форумчанину WhiteP, генератор идей, также помогал библиотеками на C++ и вообще помогал мне, респект ему, очень хороший и отзывчивый парень!

Ингридиенты:
— Delphi 2010 или выше, 1-на сцуко
— голова, 1-на тыква
— руки, 2-ве тяпки

С чего начать? Учим сворачиваться в трей и определять момент подключения съемного накопителя…
Начать надо с простых вещей, надо научить программу сворачиваться в трей и подключить для трея контекстное меню…
Бросим PopupMenu1 и создадим меню с двумя надписями: «восстановить» и «закрыть», ниже код для нажатий:
procedure TAutoRunKiller.N1Click(Sender: TObject);
begin
mayClose:=False; //теперь снова нельзя закрыть программу
AutoRunKiller.Show; //восстанавливаем окно
Application.Restore;
Application.BringToFront; //помещаем его поверх всех окон
Application.ProcessMessages;//на всякий случай обрабатываем системные сообщения
end;
procedure TAutoRunKiller.N3Click(Sender: TObject);
begin
AutoRunKiller.Close; //закрываем программу — для этого все готов
end;

Для TrayIcon1 присвоим обработчик нажатия кнопки «восстановить»…
Теперь, пользователи очень любят когда программы автоматически сворачиваются в трей после запуска, моя программа после запуска, прячется через 1-ну секунду в трей…
procedure TAutoRunKiller.OnMinimizeProc(Sender: TObject);
begin
AutoRunKiller.Close;
end;
procedure TAutoRunKiller.FormCreate(Sender: TObject);
begin
//первичные настройки
TrayIcon1.Visible:=true;
AutoRunKiller.ClientHeight:=401;
AutoRunKiller.ClientWidth:=699;
//перехватываем событие сворачивания, а при сворачивании выполняем код: Close;
Application.onMinimize:=OnMinimizeProc;
//учим программу определять момент подключения съемного накопителя
Result := False;
Size := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
ZeroMemory(@dbi, Size);
dbi.dbcc_size := Size;
dbi.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
dbi.dbcc_reserved := 0;
dbi.dbcc_classguid := GUID_DEVINTERFACE_USB_DEVICE;
dbi.dbcc_name := 0;
r := RegisterDeviceNotification(AutoRunKiller.Handle, @dbi, DEVICE_NOTIFY_WINDOW_HANDLE);
if not Assigned(r) then ShowMessage(‘Error Register Message’);
//прячем в трей программу, у таймера интервал = 1000, выполняет код: Close;
Timer3.Enabled:=true;
end;
Вроде основное есть, теперь необходимо набросать функцию поиска файла-червя, для этого необходимо исследовать файл AutoRun.inf…

Ищим червя…

Для начала, нам необходимо объявить 2-ве функи:
private
{ Private declarations }
procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
procedure OnMinimizeProc(Sender:TObject)

Теперь мы можем смело писать функу поиска, но…
…что же это, при попытке вылечить диск после его подключения, у нас происходит исключение….. =\
На сколько я понял, все дело в том, что сигнал о подключении поступил нашей программе, но само оборудование еще не готово к эксплуатации (по сути, даже буква еще не присвоена), поэтому, необходимо произвести лечение диска, через какую-то задержку, с этим проще справится таймер…
procedure TAutoRunKiller.WMDeviceChange(var Msg: TMessage);
var
devType: Integer;
Datos: PDevBroadcastHdr;
begin
if (Msg.wParam = DBT_DEVICEARRIVAL) or (Msg.wParam = DBT_DEVICEREMOVECOMPLETE) then
begin
Datos := PDevBroadcastHdr(Msg.lParam);
devType := Datos^.dbch_devicetype;
if devType = DBT_DEVTYP_DEVICEINTERFACE then
begin // USB Device
if Msg.wParam = DBT_DEVICEARRIVAL then
begin
//ShowMessage(‘Устройство подключено!’);
Timer1.Enabled:=true;
end else
begin
//ShowMessage(‘Устройство отключено!’);
end;
end;
end;
end;
procedure TAutoRunKiller.Timer1Timer(Sender: TObject);
var
d: dword;
i: byte;
s: string;
fin: boolean;
begin
Timer1.Enabled:=false;
d := GetLogicalDrives;
for i := 2 to 26 do
if 1 shl i and d > 0 then //получаем букву съемного диска
if GetDriveType(PChar(chr(i+65)+’:\’)) = DRIVE_REMOVABLE then begin
s := LowerCase(chr(i+65));
s:=s+’:\’;
try
//процедура лечение съемного накопителя
AutoRunKill(s,fin);
except
fin:=false;
end;
end;
end;
Закругляемся…

Ну вот, тепперь ваша программа может сворачиваться, разворачиваться и главное, лечить съемные диски, но это далеко еще не все, для большего функционала, необходимо еще многое реализовать:
+ Реализовать возможность отключения защиты
+ Т.к. после лечения флэх, изменения приходят после «перевтыкании» флэшки, возможность указания пользователем, автоматического извлечения (если было произведено лечение)
+ Создавать «неудаляемые» файлы на съемном диске, что позволяет не заражаться червями
+ Реализовать возможность автоматического (программного) открытия флэшки проводником, что полностью безопасно
+ Реализовать возможность отключения «Автозапуск Windows»
+ Реализовать «белый список» (позволяет указать, например, имя программы вашего инсталятора софта, который удалять незя)
+ Реализовать «черный список» (шатать хлам на съемном накопителе, позволяет указывать папки/файлы на постоянное вшатывание при обнаружении, например, папка «Reciler» создающаяся каким-то вирусом)
+ Добавить возможность включения/отключения автозапуска
+ Реализовать возможность тихого режима защиты
+ Запуск служебного ПО
+ Разблокировка Реестра/Диспетчера задач
+ Поддержку скинов (т.к. еслиб я это не сделал, меня бы убили за плагиат шкурки от Kav7 )
+ И многое другое
+ Учесть это все и переработать процесс лечения

Что у нас получилось в итоге?




Забавно, не так-ли?

А вот какой он получился в итоге алгоритм лечения:

ЗЫ — Незнаю как прятать под спойлер, помогите мне модераторы или админы…

Procedure AutoRunKill(s: string; var fin: boolean);
var
mi,mj,mij,ms: integer;
mNameVir, mNameDir: array[1..40] of string;
mni,mnv,mnd: shortInt;
virName,lineAR,NameAR,DelDir,s1,s2: string;
MyEXE,MyMid: string[5];
DesctopHandle: HWND;
DesctopDC: HDC;
thisFirst, finWL, mnb, witeLst: boolean;
label MyJump;
begin
fin:=false;
witeLst:=false;
//очищаем массивы
mnv:=0;
mnd:=0;
//увеличиваем счетчик: «Проверено»
AutoRunKiller.QPanel1.Edit;
AutoRunKiller.QPanel1.Fields.Fields[1].Value:=AutoRunKiller.QPanel1.Fields.Fields[1].Value+1;
AutoRunKiller.QPanel1.Post;
//начинаем лечить
NameAR:=’autorun.inf’;
if FileExists(s+NameAR) then begin
AutoRunKiller.Memo2.Lines.Clear;
AutoRunKiller.Memo2.Lines.LoadFromFile(s+NameAR);
virName:=»; fin:=true;
mi:=1; //индекс строки текста авторана
AutoRunKiller.Faily.First;
while AutoRunKiller.Faily.Eof=false do begin
if AutoRunKiller.Faily.Fields.Fields[1].Value=Null then MyEXE:=» else
MyEXE:=AutoRunKiller.Faily.Fields.Fields[1].Value; //искомое расширение файла
if MyEXE» then repeat //если искать есть что, продолжаем
mj:=0; //точка отсчета mid
lineAR:=AutoRunKiller.Memo2.Lines[mi]; //строка авторана
repeat
MyMid:=MidStr(lineAR,mj,Length(MyEXE)); //отрезок строки авторана
if MyMid=MyEXE then begin
mij:=mj-2; //захватим уменьшенный на 2 индекс точки отсчета
repeat //будем искать индекс, стоящий перед именем файла
MyMid:=MidStr(lineAR,mij,1); //получаем символ
DelDir:=»; //сбрасываем память переменной «директория на удаление»
if MyMid=’=’ then begin //если мы наткнулись на возможное завершение имени файла
ms:=mij+1; //возможная начальная точка, содержащая начало имени файла/директории
thisFirst:=true;
while ms if (MyMid=’ ‘) then begin
if (thisFirst=true) then begin
mij:=mij+1;
end else thisFirst:=false
end else if (MyMid=’\’) then begin //если он означает конец имени директории
DelDir:=MidStr(lineAR,mij+1,ms-mij-1); //выдираем папку из корня диска
Break; //прекращаем цикл, цель достигнута
end else thisFirst:=true;
ms:=ms+1;
end;
mij:=mij+1;
finWL:=false;
virName:=MidStr(lineAR,mij,mj+Length(MyEXE)-1);
//———————-создание списка файлов на удаление
if FileExists(s+virName) then begin
if AutoRunKiller.QPanel6.Fields.Fields[0].Value=true then begin
//белый лист
AutoRunKiller.QPanelTable6.First;
while AutoRunKiller.QPanelTable6.Eof=false do begin
s1:=AutoRunKiller.QPanelTable6.Fields.Fields[0].Value;
s2:=virName;
MyUpperCase(s1);
MyUpperCase(s2);
if s1=s2 then begin
finWL:=true;
witeLst:=true;
Break;
end;
AutoRunKiller.QPanelTable6.Next;
end;
end;
//если нет в белом листе
if finWL=false then begin
virName:=s+virName;
mnb:=false;
for mni := 1 to mnv do if mNameVir[mni]=virName then begin
mnb:=true;
Break;
end;
//добавляем в список на удаление
if mnb=false then begin
mnv:=mnv+1;
mNameVir[mnv]:=virName;
mnb:=false;
if DelDir» then begin
for mni := 1 to mnd do if mNameDir[mni]=DelDir then begin
mnb:=true;
Break;
end;
if mnb=false then begin
mnd:=mnd+1;
mNameDir[mnd]:=DelDir;
end;
end;
end;
end;
end;
//———————————————————
goto MyJump;
end;
mij:=mij-1;
until mij=0;
end;
mj:=mj+1;
until mj>length(lineAR)-length(MyEXE)+1;
MyJump:
mi:=mi+1; //следующая строка
until mi>=AutoRunKiller.Memo2.Lines.Capacity-1;
AutoRunKiller.Faily.Next;
end;
//добавляем в список имя самого авторана
if witeLst=false then begin
mnv:=mnv+1;
mNameVir[mnv]:=s+NameAR;
end;
//начинаем удалять файлы по списку
for mni := 1 to mnv do begin
if AutoRunKiller.QPanel3.Fields.Fields[0].Value=false then begin
Form6.Label2.Caption:=’Имя файла:’;
Form6.Label3.Caption:=mNameVir[mni];
DesctopHandle := GetDesktopWindow;
DesctopDC := GetDC(DesctopHandle);
try
Form6.Left := GetDeviceCaps(DesctopDC, HORZRES) — Form6.Width;
Form6.Top := GetDeviceCaps(DesctopDC, VERTRES) — Form6.Height;
finally
if ReleaseDC(DesctopHandle, DesctopDC) = 0 then RaiseLastOSError;
end;
AutoRunKiller.Timer2.Enabled:=true;
if mrOk=Form6.ShowModal then begin
SetFileAttributes(PChar(mNameVir[mni]),FILE_ATTRIBUTE_NORMAL);
DeleteFile(mNameVir[mni]);
end;
end else begin
if mni=1 then AutoRunKiller.Timer2.Enabled:=true;
SetFileAttributes(PChar(mNameVir[mni]),FILE_ATTRIBUTE_NORMAL);
DeleteFile(mNameVir[mni]);
end;
end;
//начинаем удалять директории по списку
for mni := 1 to mnd do begin
if AutoRunKiller.QPanel3.Fields.Fields[0].Value=false then begin
Form6.Label2.Caption:=’Имя директории:’;
Form6.Label3.Caption:=mNameDir[mni];
DesctopHandle := GetDesktopWindow;
DesctopDC := GetDC(DesctopHandle);
try
Form6.Left := GetDeviceCaps(DesctopDC, HORZRES) — Form6.Width;
Form6.Top := GetDeviceCaps(DesctopDC, VERTRES) — Form6.Height;
finally
if ReleaseDC(DesctopHandle, DesctopDC) = 0 then RaiseLastOSError;
end;
if mrOk=Form6.ShowModal then begin
RemoveAll(s+mNameDir[mni]+’\’);
end;
end else begin
RemoveAll(s+mNameDir[mni]+’\’);
end;
end;
end;
//автономное удаление каталогов и файлов (black list)
AutoRunKiller.QPanelTable5.First;
if AutoRunKiller.QPanel5.Fields.Fields[0].Value=true then
while AutoRunKiller.QPanelTable5.Eof=false do begin
if (AutoRunKiller.QPanelTable5.Fields.Fields[0].ValueNull) and (AutoRunKiller.QPanelTable5.Fields.Fields[0].Value») then begin
DelDir:=AutoRunKiller.QPanelTable5.Fields.Fields[0].Value;
if DirectoryExists(s+DelDir) then RemoveAll(s+DelDir+’\’); //если папка
if FileExists(s+DelDir) then begin //если файл
SetFileAttributes(PChar(s+DelDir),FILE_ATTRIBUTE_NORMAL);
DeleteFile(s+DelDir)
end;
end;
AutoRunKiller.QPanelTable5.Next;
end;
end

Понравилась статья? Поделиться с друзьями: