Ломаем с IDA PRO #2

Очередная часть про IdaPython. Разбираемся c Api Иды. Пишем свой WinApi Logger.

При внушительном размере исследуемого файла, рассматривать под лупой каждый opcode просто нет времени. Зачастую (даже оптимизирующий) компилятор собирает выходной файл довольно близко к исходным текстам. Давайте посмотрим как сохраняется структура функций, собрав следующий код в MSVC с флагом Minimize Size (/O1):

Пропустим полученный файл через IDA:

Что сделал компилятор?

  • Оптимизировал сложение двух DWORD в одном opcode (Sub_401000)
  • Встроил параметр 0Ah = 10 в тело функции (sub_401004)
  • Передал аргументы через регистры вместо стека (sub_401004)
  • Заменил call на jmp, использовав чужой retn (sub_401004)

Впечатляет. Получилось похоже на ручную оптимизацию ассемблерного кода!

Покуда компилятор сохраняет структуру функций, удобно рассматривать функцию как чёрную коробку, отмечая что подаётся на вход и получается на выходе. Порой, чтобы узнать что делает новая функция, достаточно знать какие известные нам функции она вызывает.

Одним из моих любых инструментов в OllyDbg был Conditional log, который позволял поставить в теле функции условную точку останова и логировать все параметры. Ближе к концу статьи мы сделаем его аналог на IdaPython.

Где брать примеры?

Отсутствие внятной документации — серьёзный мотиватор для покупки лицензии дающей быстрое решение всех вопросов через саппорт. Похоже, что монопольный доступ к нормальной документации — основа их бизнеса.

IdaPython — не более чем тонкая прослойка до си-функций доступных плагинам.

  • Примеры готовых скриптов можно найти на github.
  • Большая часть дальнейшего кода основана на DIE.
  • Если вы не понимаете что здесь происходит, читайте цикл «От зелёного к красному»
  • Все дальнейшие скрипты работают в Ida6.8 для 32 бит. Младшие версии не проверял!

Устанавливаем хуки

Представим, что исследуемый код вызывает функцию Sleep, принуждая текущий поток заснуть на длительное время. Каждый раз ловить его руками не представляется возможным.

Мы подменяем параметр функции на лету, это SpeedHack в чистом виде.

Парсим импорт

Если Вы обратите внимание, в прошлом листинге мы запрашиваем адрес функции Sleep с префиксом «kernel32». Ida автоматически назначает имена:

sleep.api.2

  1. Функция внутри кода, скорее всего часть стандартной либы GCC
  2. Ссылка на функцию в IAT
  3. Непосредственно функция в Kernel32

Как же нам найти правильную функцию? Через перечисление импорта:

Остановимся на именовании. GetFunctionName получает уже назначенное имя, а idc.Name просит иду придумать новое. Demangle приводит в читаемый вид имена вроде:

Получаем параметры

WinApi использует __stdcall, все параметры передаются через стек, а ответ возвращает EAX. Зная количество параметров, мы можем прочитать их из стека.

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

Помните, в прошлой статье мы назначали прототип функции с __usercall? Api Иды позволяет как получать прототип функции, так и его парсить!

После запуска скрипта, в текущий Instance пайтона будут добавлены все наши функции и мы сможем вызывать их из консоли IdaPython. Во время отладки, зайдём внутрь любой функции имеющей прототип:

Весьма недурно! Наш код умеет воровать параметры из стека и регистров.

Копируем прототипы

Это магия работает только при условии, что функции назначен верный прототип. Ida автоматически назначает их IAT-ссылкам, так что просто скопируем их адресам внутри системных библиотек.

Вы знаете способ лучше? Напишите в комментах!

GetType возвращает строку с прототипом функции, но без указания имени. В ряде случаев (с mangled именами) она возвращает ошибку. Вы видели полную документацию по IdaPython? И я не видел. Таким грязным трюком мы формируем прототип с новым именем:

К сожалению, без ошибок в самой IDA, тоже не обошлось:

LetsFuckIlfak

LetsFuckIlfak

Удаляем невалидные хуки

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

Финальный скрипт

Скрипт пока очень сырой, так что не даю никаких гарантий касательно его работы.
Возможно из этого вырастет полноценный инструмент, как это было c SignFinder.
Скорее всего, публичных обновлений для SignFinder больше не будет, мы видели чем закончился его релиз.

ida_parse_api68.py

Давайте посмотрим на возможности нашего скрипта:

IdaPython

Лоадер проверяет наличие антивирусов

Включив логирование интересующих нас WinApi мы легко узнаем что делает функция.

Ключевое отличие нашего скрипта в том что мы можем набить прототип любой функции внутри пользовательского кода и вместо WinApi получать чистую логику приложений!

P/S Если у вас есть интересные семплы, буду рад принять их в комментариях.

2 thoughts on “Ломаем с IDA PRO #2

  1. Автор, напишите статью как преобразовывать тонну асм кода в простой понятный псевдокод с помощью иды и питона, на примере vmprotect.

Добавить комментарий