Доброго времени суток. Разговор сегодня пойдёт о техниках антидизассемлировании. Надеюсь, что будет интересно 
План рассказа:
Чем отличается "линейный дизассембрер" от "поточного"
Дизассемблер - это инструмент, преобразующий машинный код, объектный файл или библиотечные модули в текст программы на языке ассемблера. По режиму работы с пользователем делятся на автоматические ("Линейные") и интерактивные ("Поточные"). Основная трудность для дизассемлера - это отличить код от данных.
"Линейные дизассемблеры" последовательно дизассемблируют каждую отдельную инструкцию не думая о какой-либо логике. Алгоритмы линейного дизассемблирования часто неспособны отличить код от данных и поддаются искажению сильнее, чем поточные.
Поточные дизассемблеры ( например IDA Pro ) не перебирают код инструкций "линейно", предполагая, что в коде находятся "чистые инструкции". Вместо этого они изучают каждую команду и формируют участки, которые подлежат дизассемблированию. Поточные дизассемблеры способны делать выбор и предположения, какие инструкции ему следует обрабатывать в тот или иной момент. Линейные дизассемблеры не могут такого.
Запомните эти факты: В листинге дизассемблера любой байт программы обязан принадлежать только одной инструкции. Любой дизассемблер сначала обрабатывает ложное ответвление при условиях в программе (
Популярные техники антидизассемблирования
Ложные условные переходы и инструкции call ведущие в пустоту
Одна из самых распространенных техник это использование двух инструкций условного перехода, размещенных вплотную друг к другу и указывающих на один и тот же адрес. Сочетание инструкций
Адрес перехода - 0x401519+1, по адресу 401519 находится инструкция
Исправить такие непонятные инструкции помогут клавиши D и C в IDA RPO.
Превратим байт
Иногда могут попадаться вот такие не дизассемблированные байты. Их можно преврать в код, нажав клавишу C.
Второй вариант ложного перехода
Еще один прием антидизассемблирования, который часто встречается в реальном коде, состоит в размещении условного перехода там, где его условие всегда сработает.
На картинке ниже перед переходом
Здесь такая же ситуация с инструкцией
Во всех ложных условных переходах можно заменить некоторые байты на
Исключение не для ошибок, а для маскировки
Теория
В архитектуре x86 существует механизм структурированной обработки исключений (Structured Exception Handling, SEH). Он позволяет управлять потоком выполнения так, чтобы отладчики и дизассемблеры не смогли отследить этот поток.
Цепочку выполнения SEH можно представить, как список функций, предназначенных для обработки исключений в пределах потока выполнения. Постараюсь объяснить SEH как я понимаю.
Например, есть исключение деление на ноль. Исключение попадает в список SEH -> Каждая функция в SEH проверяет, что это исключение подходит для данной функции -> Если никакая функция не смогла обработать исключение, исключение считается не обработанным и появляется диалоговое окно с ошибкой.
OC ищет цепочку SEH таким способом: ОС исследует регистр FS, содержащий сегментный селектор ( для получения доступа к блоку переменных окружения потока (TEB, thread environment block) ) -> исследует первый блок информации потока (TIB, thread information block) -> находит первый элемент внутри TIB, который является указателем на цепочку SEH ( EXCEPTION_REGISTRATION ).
Первый элемент в записи EXCEPTION_REGISTRATION указывает на предыдущую запись ( prev ). Второе поле является указателем на функцию-обработчик ( Handler ). SEH по принципу работы похож на стек.
Как используют уязвимость в SEH авторы вредоносов
Для искажения управления потоком с помощью SEH достаточно лишь уметь добавлять собственные обработчики на вершину списка. Часто в коде, где используется такая техника можно встретить элемент
Этот вариант кода часто можно встретить в вирусах с использованием искажения SEH ( ExceptionHandler может называться по другому ).
Против этой уязвимости компания Microsoft разработала Software Data Execution Prevention (DEB). Её часто называют SAFESEH. Она не позволяет добавлять сторонние обработчики исключений во время выполнения кода. Эту технологию можно обойти. Например в компиляторе от Microsoft отключить SAFESEH можно с помощью параметра
Пример реализации этого способа антидизассемблирования вы можете посмотреть в видео ниже.
Фальшивый адрес возврата для инструкции retn и отрицательный стек
Иногда злоумышленник может подменить адрес возврата (
Инструкция
Иногда авторы вредоносного ПО делают стек в некоторых участках кода нулевым. В такой ситуации IDA PRO может ошибаться в некоторых деталях дизассемблирования. Например: указывать неправильное количество аргументов, которые передаются функции или не указывать перекрёстные ссылки. Чтобы отслеживать стек, перейдите в пункт Options -> General и включите Stack Pointer.
Пример реализации этих способов антидизассемблирования вы можете посмотреть в видео ниже.
Практика
Для практики возьмём программу Lab15-03 из книги Практический анализ вредоносного ПО. В этой программе достаточно интересно изучать техники, описанные выше. Расписывать здесь будет слишком долго и может быть не понятно. Поэтому, я решил попробовать записать видео.
Я описал не все методы. Их намного больше, ведь злоумышленники прокачивают свои навыки, как и мы с вами.
Скоро новый год. Желаю вам не болеть, быть бодрыми, рассудительными и улыбаться чаще. Не натыкаться на фишинг и не стать жертвой хакеров, а самим их ловить.
Спасибо за чтение.
Источник

План рассказа:
- Разберёмся, чем отличается "линейный дизассембрер" от "поточного"
- Изучим популярные техники антидизассемблирования
- Исследуем программу с техниками антидизассемблирования
Чем отличается "линейный дизассембрер" от "поточного"
Дизассемблер - это инструмент, преобразующий машинный код, объектный файл или библиотечные модули в текст программы на языке ассемблера. По режиму работы с пользователем делятся на автоматические ("Линейные") и интерактивные ("Поточные"). Основная трудность для дизассемлера - это отличить код от данных.
"Линейные дизассемблеры" последовательно дизассемблируют каждую отдельную инструкцию не думая о какой-либо логике. Алгоритмы линейного дизассемблирования часто неспособны отличить код от данных и поддаются искажению сильнее, чем поточные.
Поточные дизассемблеры ( например IDA Pro ) не перебирают код инструкций "линейно", предполагая, что в коде находятся "чистые инструкции". Вместо этого они изучают каждую команду и формируют участки, которые подлежат дизассемблированию. Поточные дизассемблеры способны делать выбор и предположения, какие инструкции ему следует обрабатывать в тот или иной момент. Линейные дизассемблеры не могут такого.
Запомните эти факты: В листинге дизассемблера любой байт программы обязан принадлежать только одной инструкции. Любой дизассемблер сначала обрабатывает ложное ответвление при условиях в программе (
if ... else ...
).Популярные техники антидизассемблирования
Ложные условные переходы и инструкции call ведущие в пустоту
Одна из самых распространенных техник это использование двух инструкций условного перехода, размещенных вплотную друг к другу и указывающих на один и тот же адрес. Сочетание инструкций
jz
и jnz
это безусловных переход, который в любом случае ведёт к одному и тому же адресу, но для дизассемблера это вызывает проблемы.Адрес перехода - 0x401519+1, по адресу 401519 находится инструкция
call 40A81588h
. Вызвать что-либо по адресу 40A81588h невозможно. Это тоже приём антидизассемблирования. Первый байт инструкции call это E8 ( 0x401519 ). Этот байт лишний. jz 401519+1
указывает на адрес 0x40151A. Байт E8 можно убрать и ассемблерный код станет более понятным.Исправить такие непонятные инструкции помогут клавиши D и C в IDA RPO.
Клавиша D превращает текущий участок в данные.
Клавиша C превращает текущий участок в код.
Клавиша C превращает текущий участок в код.
Превратим байт
0xE8
в 0x90
(инструкция ничего не делать nop
). Код поменялся и стал понятным.Иногда могут попадаться вот такие не дизассемблированные байты. Их можно преврать в код, нажав клавишу C.
Второй вариант ложного перехода
Еще один прием антидизассемблирования, который часто встречается в реальном коде, состоит в размещении условного перехода там, где его условие всегда сработает.
На картинке ниже перед переходом
jz 4011D4+1
, находится инструкция xor eax, eax
. Результат операции xor для регистра с самим самой будет равен 0. Следовательно переход jz 4011D4+1
будет происходить всегда.Здесь такая же ситуация с инструкцией
call
. Превратим байт 0xE8 в 0x90 (инструкция ничего не делать nop
). Код поменялся и стал понятным.Во всех ложных условных переходах можно заменить некоторые байты на
nop
( 0x90
)или вообще поменять на инструкцию jmp
для более хорошего чтение кода.Исключение не для ошибок, а для маскировки
Теория
В архитектуре x86 существует механизм структурированной обработки исключений (Structured Exception Handling, SEH). Он позволяет управлять потоком выполнения так, чтобы отладчики и дизассемблеры не смогли отследить этот поток.
Цепочку выполнения SEH можно представить, как список функций, предназначенных для обработки исключений в пределах потока выполнения. Постараюсь объяснить SEH как я понимаю.
Например, есть исключение деление на ноль. Исключение попадает в список SEH -> Каждая функция в SEH проверяет, что это исключение подходит для данной функции -> Если никакая функция не смогла обработать исключение, исключение считается не обработанным и появляется диалоговое окно с ошибкой.
OC ищет цепочку SEH таким способом: ОС исследует регистр FS, содержащий сегментный селектор ( для получения доступа к блоку переменных окружения потока (TEB, thread environment block) ) -> исследует первый блок информации потока (TIB, thread information block) -> находит первый элемент внутри TIB, который является указателем на цепочку SEH ( EXCEPTION_REGISTRATION ).
Первый элемент в записи EXCEPTION_REGISTRATION указывает на предыдущую запись ( prev ). Второе поле является указателем на функцию-обработчик ( Handler ). SEH по принципу работы похож на стек.
Как используют уязвимость в SEH авторы вредоносов
Для искажения управления потоком с помощью SEH достаточно лишь уметь добавлять собственные обработчики на вершину списка. Часто в коде, где используется такая техника можно встретить элемент
fs:[0]
( Она указывает на запись, которая находится на вершине стека в данный момент)Этот вариант кода часто можно встретить в вирусах с использованием искажения SEH ( ExceptionHandler может называться по другому ).
C-подобный:
push ExceptionHandler ; функция-обработчик
push fs:[0] ; указатель на следующую запись
mov fs:[0], esp ; пытаемся поместить элемент на вершину цепочки
Против этой уязвимости компания Microsoft разработала Software Data Execution Prevention (DEB). Её часто называют SAFESEH. Она не позволяет добавлять сторонние обработчики исключений во время выполнения кода. Эту технологию можно обойти. Например в компиляторе от Microsoft отключить SAFESEH можно с помощью параметра
/SAFESEH:NO
Пример реализации этого способа антидизассемблирования вы можете посмотреть в видео ниже.
Фальшивый адрес возврата для инструкции retn и отрицательный стек
Иногда злоумышленник может подменить адрес возврата (
retn ...
) из программы. Программа продолжит выполнение в совсем другой функции. Это можно использовать, чтобы замаскировать вредоносную программу под обычную.Инструкция
retn
берёт первую запись из стека для адреса возврата. Обращаете внимание на стек во время инструкции retn
. В функции main инструкцию retn
можно встретить очень редко. Обращаете внимание в каких местах используется retn
.Иногда авторы вредоносного ПО делают стек в некоторых участках кода нулевым. В такой ситуации IDA PRO может ошибаться в некоторых деталях дизассемблирования. Например: указывать неправильное количество аргументов, которые передаются функции или не указывать перекрёстные ссылки. Чтобы отслеживать стек, перейдите в пункт Options -> General и включите Stack Pointer.
Пример реализации этих способов антидизассемблирования вы можете посмотреть в видео ниже.
Практика
Для практики возьмём программу Lab15-03 из книги Практический анализ вредоносного ПО. В этой программе достаточно интересно изучать техники, описанные выше. Расписывать здесь будет слишком долго и может быть не понятно. Поэтому, я решил попробовать записать видео.
Я описал не все методы. Их намного больше, ведь злоумышленники прокачивают свои навыки, как и мы с вами.
Скоро новый год. Желаю вам не болеть, быть бодрыми, рассудительными и улыбаться чаще. Не натыкаться на фишинг и не стать жертвой хакеров, а самим их ловить.
Спасибо за чтение.
Источник
Ссылка скрыта от гостей
Последнее редактирование: