Ломаем с IDA PRO #3 Unpacking Smoke Loader

Кто-то из читателей просил сделать разбор боевой малвари, так что получите и рапишитесь!

Для начала обзаведитесь своей копией семпла, стандартный пароль: infected
Для лучшего понимая стоит загрузить образ в IDA и пройти с ним по ходу статьи.

Снимаем слой протектора

С порога видим морфленный стаб упаковщика с парой антиотладочных трюков. В обоих случаях код ксорит адрес перехода на поля из PEB (а точнее BeingDebugged и NtGlobalFlag), которые без отладчика должны быть равны нулю.

smoke-loader-antidebug

Антиотладка на PEB довольно частый кейс, доработаем скрипт из прошлых частей:

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

smoke-loader-unpack-data

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

На первый взгляд внутри лежит мешанина из байт, однако опытный глаз сразу приметит что подозрительно плотный блок данных начинается со смещения 0x400, там же где обычно начинается секция кода!

smoke-loader-raw_body

Но это пока лишь предположение, давайте посмотрим что будет дальше! Выделяется второй блок памяти и код приступает к парсингу модифицированных хидеров. В моём случае адрес первого блока 0x20000, а второго 0x30000. Команда rep movsb копирует байты по адресу ESI в память по адресу EDI, количество указано в ECX:

smoke-loader-section

Теперь понятно зачем нужен второй блок памяти, в него разбазируется модифицированный pe32 из первого блока! Обратите внимание, регистр ESI увеличивается на 0x28, что точно совпадает с размером IMAGE_SECTION_HEADER.

Похоже что автор слегка модифицировал сырой загрузчик pe32, изменив константы и смещения опорных точек e_lfanew и Magic, по которым обычно проверяется валидность хидеров. Новая структура секций:

После копирования секций отрабатываются релоки. Их легко узнать по проверке старших 4 бит на равенство IMAGE_REL_BASED_HIGHLOW = 3 (test eax, 3000h) и получением оффсета без этих бит (and eax, 0FFFh).
Структура релоков осталась прежней, напомню:

При обработке релоков к каждому адресу из списка прибавляется дельта-смещение, разница между ImageBase при сборке и фактическим. Запоминаем оригинальный ImageBase = 0x10000000.

smoke-loader-reloc

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

smoke-loader-get_ep

В стек помещаются 2 переменные — адрес первого блока памяти и ссылка на строку — скорее всего это идентификатор «компании», своего рода реферер, говорящий откуда пришёл бот.

Шагаем внутрь CALL EDX и оказываемся на точке входа основного тела.

smoke-loader-protector_end

Протектор повержен!

Восстанавливаем заголовки pe32

Наверняка можно написать скрипт распаковки, но скорее всего смещения меняются от семпла к семплу и смысла в этом нет. Всё что нам нужно знать мы подсмотрели в отладчике!

По смещению 0x1CC начинается импровизированная таблица секций, зная её структуру легко подсчитать, что их всего четыре. При помощи хекс-редактора копируем первые 0x200 байт из оригинального тела Smoke Loader поверх дампа. Теперь с этим можно работать, открываем дамп в CFF-explorer и ставим FileHeader.NumberOfSections = 4. Заполняем таблицу секций вручную:

smoke-loader-recovery_section

Осталось только выставить поля:

  • OptionalHeader.ImageBase = 10000000
  • OptionalHeader.SizeOfImage = A000
  • OptionalHeader.AddressOfEntryPoint = 3A23
  • DataDirectories.Relocation.RVA = 9000
  • DataDirectories.Relocation.SIZE = 600
smoke-loader-dump_work

Наш дамп работает в X64dbg!

Осталась одна небольшая проблема, функция на точке входа принимает 2 параметра через стек, благо автор оставил для нас часть отладочного кода и мне не пришлось править бинарь.

smoke-loader-new_ep

Меняем точку входа на 0x3B0D и получаем рабочий семпл.

Забегая вперёд скажу, что параметры определяют как будет вести себя код, если передать адрес неразбазированного модуля, код инжектирует его (по сути самого себя) в explorer, в противном случае он будет работать как уже внедрённый модуль.

Рекламная пауза

Хотите видеть посты чаще? Обратная связь мотивирует авторов продолжать свою работу:
делайте репосты (в твиттере и телеграмме), оставляйте ссылку на блог у себя на форумах, ставьте лайки и пишите комментарии в блоге. Вы можете предложить интересную тему или дополнить статьи своей информацией. Ну и совсем отлично будет выйти на окупаемость блога: желающие могут подогреть нас донатами на хостинг.

Смотрите в следующих сериях

Распаковка Smoke Loader только первый шаг в его анализе, в следующей части мы отломаем его защиту от виртуальных машин и разберёмся как он умудряется инжектировать код в другие процессы!

14 thoughts on “Ломаем с IDA PRO #3 Unpacking Smoke Loader

  1. > как он умудряется инжектировать код в другие процессы!

    Старый процесс холлоинг, новый методом из PowerLoader в эксплорер код инжектит (NtSetWindowLong)

    1. Будет подробный разбор, кстати можно предложить интересный семпл для будущих выпусков

      1. Увидел мой коммент? А то мало ли анти-спам убил из-за множества ссылок на сэмплы.

    1. На эту версию уже существует аналитика, так что ни автору ни клиентам ничего не грозит, но я готов обсудить детали в джаббере. Оставь свои контакты если есть о чем говорить.

      1. Нее, я не с угрозами, я с предупреждением. Тоже когда-то реверсил и делал блог пост об этом, автор быстро мне начал писать с угрозами и пытаться деанонить, пришлось удалить.

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

  2. Автор, подскажи. А как делается обфускация всяких переходов и вызовов, если малварь на си, а не на асме?

    Я перешел с ассемблера и не понимаю как это делать все на си. Неприятно, что код компилируется в читаемую конфетку, хочется чего-нибудь сложнее….

      1. Спасибо большое за ответ. Не знаю, отправился ли мой комментарий, так как я ехал в метро и в этот момент пропала связь. Поэтому дублирую.

        Какие алгоритмы юзать для генерации си-кода? Все-таки, как никак, си код — это сложнее, чем ассемблерные мнемоники. Там различные блоки, связи внутри кода и прочее. Какой алгоритм для трэшгена юзать, чтобы он не превратился в ад из 1000 строк говнокода?

        Спасибо.

        1. Ребят, засыпали вопросами про си-трешген. Я напишу пост, но как будет время.
          И там пишет «комментарий отправлен» по идее, это значит что я его увижу.

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