Распаковка исполняемых файлов — одна из задач, возникающих при реверсе. И если наш объект — это малварь, то зачастую приходится сталкиваться с кастомными упаковщиками. В этой статье я покажу, как справиться с защитными механизмами банкера GootKit, который постоянно развивается и апгрейдится, к тому же использует разные методы сопротивления отладке.

INFO

В прошлой статье мы пробежались по азам вскрытия кастомных пакеров, взяв для примера вымогатель GlobeImposter 2.0. Он практически не сопротивлялся распаковке и кое-чем даже помогал в этом деле.

Из инструментария мы будем использовать отладчик x64dbg (его 32-битную версию x32dbg), интерактивный дизассемблер IDA, шестнадцатеричный редактор HxD и детектор пакеров и протекторов DiE. Мы будем противостоять антиотладке при помощи мьютексов и разберемся с нестандартными параметрами функции CreateFileA.

WARNING

Все описанные в статье действия выполнялись внутри виртуальной машины, которая была изолирована от сети. Повторение действий на основном компьютере может привести к заражению банкером GootKit, способным похитить твои данные.

Для начала давай посмотрим на GootKit через программу Detect it Easy.

Нераспакованный образец GootKit
Нераспакованный образец GootKit

Детектор не определяет никакой навесной защиты, зато энтропия файла зашкаливает.

Энтропия GootKit
Энтропия GootKit

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


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

Чтобы самостоятельно убедиться в этом, можешь скомпилировать и посмотреть в IDA простую программу, которая использует эту технику вызовов. Конечно, код будет более «чистый» и понятный, но общая суть очевидна.

int main()
{

  typedef NTSTATUS(WINAPI *pNtQueryInformationProcess)(HANDLE, UINT, PVOID, ULONG, PULONG);
  ULONG dProcessInformationLength = 0;
  PVOID DbgPort;

  pNtQueryInformationProcess pNtQueryInfoProcess = (pNtQueryInformationProcess)GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtQueryInformationProcess");
  NTSTATUS Status = pNtQueryInfoProcess(GetCurrentProcess(),7,&DbgPort,dProcessInformationLength,NULL);
  if (Status == 0x00000000) return 0;

    return 0;
}

Давай переключимся в псевдокод, нажав кнопку F5, так будет еще очевиднее.

Псевдокод
Псевдокод

Инициализация и вызов функций выглядит таким образом:

v3 = v1(byte_41F00C, byte_41F0F8);
v33 = (void (__stdcall *)(char *, char *))v2(v3);
v4 = v1(byte_41F00C, byte_41F0EC);
v32 = (int (__stdcall *)(char *))v2(v4);
v5 = v1(byte_41F0A4, byte_41F0B0);

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


Очевидно, применяется шифрование строк при помощи XOR по ключу 89798798798g79er$. Видим шифротекст byte_41F000[edi].


Псевдокод этого алгоритма такой:

do
  {
    byte_41F000[v30] ^= a89798798798g79[v30 % v29];
    ++v30;
  }
  while ( v30 < 11 );
  v31 = strlen(a89798798798g79);

Зная ключ, попробуем расшифровать содержимое буфера средствами Python, который встроен в IDA. Набираем

x = idc.GetManyBytes(0x41F0EC, 0x0B)

Пишем байты по адресу 0x41F0EC в количестве 0x0B в переменную encrypt. Проверим, просто введя имя переменной и нажав Enter:

Python>encrypt = idc.GetManyBytes(0x41F000, 0x9)
Python>encrypt
hJVIQl]T[

Все верно: это именно то, что мы видели в IDA. Теперь присвоим переменной y известный нам пароль и зададим переменную decrypt для выходных данных:

Python>y = "89798798798g79er$"
Python>decrypt = ""

Теперь приступим к циклу дешифровки.

Продолжение доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все материалы на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи один материал

Заинтересовала информация, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для материалов, опубликованных более двух месяцев назад.


3 комментария

  1. AseN

    13.08.2018 at 23:38

    «Найдем код создания процесса, который создается копией процесса с параметром -1»
    Что подсказало вам, что нужно искать xrefs`ы на CreateProcessA, а не ShellExecute, например? Интуиция?

    • hiddy

      15.12.2018 at 23:46

      Функция ShellExecute находится в Shell32.dll, и стучит в CreateProcess kernel32.dll, которая в свою очередь стучит в ntdll.dll NtCreateProcess. Таким образом, если поставить бряк на CreateProcess, мы ловим и ShellExecute.

  2. AseN

    13.08.2018 at 23:41

    «Да, это тот процесс, который порождается экземпляром приложения, запущенного с параметром -l»
    Опять же, как вы это поняли?

Оставить мнение

Check Also

Для шифровальщиков семейства Hidden Tear появился бесплатный дешифровщик HT Brute Forcer

ИБ-специалист Майкл Гиллеспи (Michael Gillespie) создал универсального дешифровщика данных…