Я хотел увидеть настоящую программу-вымогатель в действии, поэтому взял образец LockerGoga из app.any.run. Затем я запустил исполняемый файл с открытыми ProcessExplorer и ProcessMonitor в фоновом режиме, чтобы увидеть, что он действительно будет делать в моей системе виртуальной машины.

Образец файла создал еще один исполняемый файл в каталоге C:\Users\IEUser\AppData\Local\Temp с именем файла, начинающимся с tgytutrc. Затем ProcessMonitor показал мне вызов «Process Create», который запустил cmd.exe так, как вы можете видеть ниже.

C:\Windows\system32\cmd.exe /c move /y C:\Users\IEUser\playground\malware\LockerGoga.exe C:\Users\IEUser\AppData\Local\Temp\tgytutrc8597.exe

Изначально я подумал, что файл tgytutrc8597.exe был распакован из оригинального бинарника LockerGoga.exe, но потом я увидел эту команду в действии, и мне стало понятно, почему оригинальный файл — в данном случае LockerGoga.exe — исчез. Его просто перенесли в другое место. Ниже вы также можете ознакомиться с функцией, отвечающей за подготовку полного пути к cmd.exe.

Сначала GetSystemDirectoryW(), которая в этом случае вернет C:\Windows\system32, а затем к пути добавляется строка «cmd.exe».

Входные аргументы LockerGoga

Поскольку я экспериментировал с образцом, я обнаружил одну интересную вещь во время его отладки. Если вы запустите дроппер без каких-либо параметров, он спрячется в каталоге %Temp% и начнет шифровать ваши драгоценные файлы. Но если вы запустите дроппер с параметром «-m», он никуда не спрячется. Он начнет свои действия в том же месте, где хранится в данный момент — команда перемещения в этом случае будет опущена. Тем не менее, он будет шифровать файлы. Интересно, что всякий раз, когда дроппер вызывается с параметром «-m», он становится родительским для дочерних процессов, запущенных с другим набором параметров «-i SM-tgytutrc -s». Таким образом, большую часть времени LockerGoga запускает 3 процесса.

C:\Users\IEUser\playground\malware\LockerGoga.exe -m
        C:\Users\IEUser\playground\malware\LockerGoga.exe -i SM-tgytutrc -s 
        C:\Users\IEUser\playground\malware\LockerGoga.exe -i SM-tgytutrc -s

Но если вы хотите вызвать дроппер только с параметрами «-i SM-tgytutrc -s», то ничего не происходит. Процесс запускается, проверяет некоторую системную информацию, запрашивает некоторые ключи реестра и затем завершает свою работу. Одно из предположений, которые вытекают из этого, может заключаться в том, что LockerGoga работает в двух разных режимах: главном и подчиненном. Поэтому, если подчиненный не находит своего хозяина, он выходит.

Сначала назовем его подчиненным процессом, создающим файл README_LOCKED.txt на рабочем столе.

Во время отладки я дошел до того, что после создания файла readme ведомый процесс завершился. Также похоже, что мастер-процесс отвечает за шифрование файлов — в ProcessMonitor видно, что мастер-процесс создает множество файлов с расширением *.locked. Также будьте осторожны во время отладки, потому что вызов IsDebuggerPresent() проверяется в начале выполнения основного потока — измените результат этого системного вызова с 1 на 0 в регистре eax сразу после вызова, это позволит вам отладить его так, как он должен обычно Работа.

Отладка примера в мастер-режиме привела меня к выводу, что один из вызовов, который в конечном итоге создает дочерние процессы, был не просто вызовом статического адреса из адресного пространства процесса — было бы легко следовать потоку инструкций в Иде. Это был адрес в рамках адресного пространства процесса, но для его вызова процессору необходимо было перейти на адрес в регистре ESI. Вероятно, это одна из техник запутывания, используемая для сокрытия от реверсивных инструментов.

Другое дело, что отладка привела меня к парсеру опций IMO. Ниже вы можете увидеть скрины из моего окна OllyDBG.

Имея это в виду, а также проверив параметры командной строки запущенных процессов, я пришел к выводу, что эти процессы работают в режиме master-slave.

Также мне было интересно, за что может отвечать опция «-i». Похоже, это для связи IPC — см. скриншот ниже.

Возвращаясь к опции журнала. В поисках подсказок я прошел через строки в Иде. Угадайте, что там было?

Чтобы не думать слишком много, я запускаю дроппер с опциями «-m -l». И файл журнала начал заполняться журналами, связанными с определенными путями к файлам.

Вы можете видеть, что каждый подчиненный процесс запускается, обрабатывает некоторые файлы и затем завершается. Раз уж нашел где хранятся логи, то поискал ссылки на лог, может быть что-то интересное найду там? Я решил перейти ко второй внешней ссылке, найденной Идой, так как первая показалась мне очень интересной. Это привело меня к одной огромной функции со множеством подпрограмм. В конце этого кода были довольно интересные блоки. Давайте посмотрим на это.

Если вы сравните экран с выводом журнала, вы увидите, что строка «‹ProcId› exiting», по-видимому, сгенерирована этим блоком кода. Поскольку у нас есть журналы, теперь это больше похоже на задачу печати-отладки-реверсирования. Вся функция довольно сложная, я бы пока ее оставил. Мне кажется, что большую часть ведомого кода можно найти здесь.

Я хотел бы вернуться к файлу журнала извлечения. Посмотрим, что у него в начале?

scanning...
[1/0/330]>C:\a9f8e999f736c8dc9221\1032\LocalizedData.xml
[2/0/329]>C:\a9f8e999f736c8dc9221\1053\LocalizedData.xml
[1/1/329]+C:\a9f8e999f736c8dc9221\1032\LocalizedData.xml
[2/1/328]>C:\a9f8e999f736c8dc9221\1055\LocalizedData.xml
[1/2/328]+C:\a9f8e999f736c8dc9221\1053\LocalizedData.xml
[2/2/327]>C:\a9f8e999f736c8dc9221\Strings.xml
[1/3/327]+C:\a9f8e999f736c8dc9221\1055\LocalizedData.xml
...
[1/382/2163]>C:\ProgramData\Microsoft\Windows\Caches\{6AF0698E-D558-4F6E-9B3C-3716689AF493}.2.ver0x0000000000000005.db
scan finised
[0/382/2164]-C:\ProgramData\Microsoft\Windows\Caches\{6AF0698E-D558-4F6E-9B3C-3716689AF493}.2.ver0x0000000000000005.db

С моей точки зрения, эти две строки «сканирование…» и «сканирование завершено» могли бы быть важны при дальнейшем анализе (не говоря уже о типе — возможно, кто-то торопился

). Давайте выясним, смогу ли я найти их в Иде.

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

В то время как я хотел вникнуть в детали функции, которая, кажется, отвечает за связь IPC (я перешел к двоичному сегменту, где находилась строка «MX-tgytutrc»), который мне показался очень интересным, я обнаружил список расширения файлов — вероятно, те, которые должны быть зашифрованы.

Хорошо. Давайте вернемся к функции, которая, как я думаю, выполняет связь IPC. Он имеет множество локальных переменных, которые используются в рамках этой функции.

Давайте начнем взламывать эту функцию по частям. Сначала Ида показывает вызов OpenMutexA().

Поскольку я не из тех, кто работает с Windows, мне понадобится помощь MSDN. Там я нашел больше информации об этой конкретной функции. Посмотрим.

Как видите, функция имеет 3 аргумента: requiredAccess, inheritHandle и name. Поскольку это соглашение stdcall, эти три аргумента передаются функции, использующей стек, таким образом, что первый аргумент помещается в стек последним. В этом случае name=”MX-tgytutrc”, inheritHandle=false (поскольку регистр esi был связан с самим собой, и это в конечном итоге обнулит регистр esi), requiredAccess=0x1F0001(MUTEX_ALL_ACCESS). Затем дескриптор мьютекса (конечно, его адрес) считывается из регистра eax и попадает в локальную переменную hHandle.

Таким образом, «MX-tgytutrc» оказалось именем объекта мьютекса. Затем есть некоторый блок кода, который трудно проанализировать без отладчика, а затем hHandle, возвращаемый вызовом OpenMutex(), используется в качестве аргумента для вызова WaitForSingleObject().

Это еще одна функция, которую мне нужно проверить в MSDN.

Интервал ожидания в миллисекундах. Если указано ненулевое значение, функция ожидает, пока объект не получит сигнал или пока не истечет интервал. Если dwMilliseconds равно нулю, функция не переходит в состояние ожидания, если объект не сигнализируется; он всегда возвращается немедленно. Если dwMilliseconds равно INFINITE, функция вернется только тогда, когда объект получит сигнал.

Я выделил жирным самую важную часть. Поток будет ждать не более 10 с (0x2710 = 10000 мс), пока объект мьютекса не сообщит о своем состоянии. По моим собственным словам, это будет мьютекс, который заблокирован и не был освобожден в течение 10 секунд. Затем, в зависимости от возвращаемого значения WaitForSingleObject(), код перейдет в конец функции, если результатом функции будет 0x80(WAIT_ABANDONED). Следующий блок проверяет, равен ли регистр edi (в котором хранится результат функции) нулю — сигнал поступил от объекта мьютекса.

Настоящий вопрос заключается в том, для чего используется этот мьютекс? Что защищает? Перейдем к месту создания этого мьютекса — его можно легко найти, ища еще одну ссылку на строку «MX-tgytutrc».

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

Как видите, это аргументы, с которыми была вызвана функция CreateFileMappingA. Особенно интересен аргумент MapName. Кажется, что «SM-tgytutrc» исходит из SharedMemory? Подождем вызова OpenFileMapping и его аргументов. Хорошо. Есть так много вызовов OpenFileMapping, что, возможно, мне нужно было бы установить условную точку останова, но тем временем у меня появилась другая идея. Я попытался заглянуть в ProcessExplorer, чтобы проверить, могу ли я найти сопоставление файлов. И да, это так. Ниже вы можете увидеть, как выглядит раздел памяти в ProcessExplorer.

Один и тот же раздел доступен как в главном, так и в подчиненном процессах. Итак, давайте выясним, что там внутри — чем эти процессы обмениваются друг с другом. Я начал с некоторого кода из MSDN для чтения памяти из сопоставления общих ресурсов. Мое сопоставление файлов называется «SM-tgytutrc».

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#define BUF_SIZE 1048576
TCHAR szName[]=TEXT("SM-tgytutrc");
int _tmain()
{
   HANDLE hMapFile;
   LPCTSTR pBuf;
   hMapFile = OpenFileMapping(
                   FILE_MAP_ALL_ACCESS,   // read/write access
                   FALSE,                 // do not inherit the name
                   szName);               // name of mapping object
   if (hMapFile == NULL)
   {
      _tprintf(TEXT("Could not open file mapping object (%d).\n"),
             GetLastError());
      return 1;
   }
   pBuf = (LPTSTR) MapViewOfFile(hMapFile, // handle to map object
               FILE_MAP_ALL_ACCESS,  // read/write permission
               0,
               0,
               BUF_SIZE);
   if (pBuf == NULL)
   {
      _tprintf(TEXT("Could not map view of file (%d).\n"),
             GetLastError());
      CloseHandle(hMapFile);
      return 1;
   }
   char outputBuffer[100000] = {0};
   int j = 0;
   for(int i = 0; i < BUF_SIZE; i++) {
	   if (pBuf[i] != 0) {
		   outputBuffer[j] = pBuf[i];
		   j++;
	   }
   }
   printf("%s", outputBuffer);
   UnmapViewOfFile(pBuf);
   CloseHandle(hMapFile);
   return 0;
}

Я получил размер буфера из окна просмотра ручек из ProcessExplorer.

Код просто выводит все ненулевые байты из этого файла сопоставления памяти на консоль в виде строки. Буфер составляет 1 МБ, поэтому я решил пока печатать только ненулевые байты. И вот, в этой памяти что-то есть, какие-то строки в кодировке Base64.

Затем я расшифровал эти строки с помощью модуля python base64, и это результат.

>>> base64.b64decode('!FzpcQ29uZmlnLk1zaVw1NWZmZi5yYmY=')
b'\x17:\\Config.Msi\\55fff.rbf'
>>> base64.b64decode('dHVwRW5naW5lLmRsbA==')
b'tupEngine.dll'

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

>>> base64.b64decode('QzpcQ29uZmlnLk1zaVw1Njc2YS5yYmY=')
b'C:\\Config.Msi\\5676a.rbf'
>>> base64.b64decode('dHVwRW5naW5lLmRsbA==')
b'tupEngine.dll'
>>> base64.b64decode('c3A=')
b'sp'
>>> base64.b64decode('bWw=')
b'ml'
>>> base64.b64decode('dhVwVWkuZGxsLmRsbA==')
b'v\x15pUi.dll.dll'
>>> 
>>> base64.b64decode('c3A=')
b'sp'
>>> base64.b64decode('bWw=')
b'ml'
>>> base64.b64decode('QzpcQ29uZmlnLk1zaVw1NjczYy5yYmY=')
b'C:\\Config.Msi\\5673c.rbf'
>>> base64.b64decode('NDlcZXVsYS5ydGY=')
b'49\\eula.rtf'
>>> base64.b64decode('zpcQ29uZmlnLk1zaVw1Njc5Ny5yYmY==MzNcZXVsYS5ydGY=')
b'\xce\x97\x10\xdb\xdb\x99\x9aY\xcb\x93\\\xdaW\rM\x8d\xceM\xcb\x9c\x98\x99'
>>> base64.b64decode('bXA=')
b'mp'
>>> base64.b64decode('(QzpcQm9vdFxjcy1DWlxib290bWdyLmV4ZS5tdWk=')
b'C:\\Boot\\cs-CZ\\bootmgr.exe.mui'
>>> base64.b64decode('ay5ibXA=')
b'k.bmp'
>>> base64.b64decode('QzpcQ29uZmlnLk1zaVw1NjY3Yy5yYmY=')
b'C:\\Config.Msi\\5667c.rbf'
>>> base64.b64decode('XEFzc2lzdGFuY2VcQ2xpZW50XDEuMFxlbi1VU1xIZWxwX01LV0RfQmVzdEJldC5IMVc=')
b'\\Assistance\\Client\\1.0\\en-US\\Help_MKWD_BestBet.H1W'
>>> base64.b64decode('Ny04RTdGLUJBM0YyNDczMkQ5NX0uSDFR')
b'7-8E7F-BA3F24732D95}.H1Q'
>>>
base64.b64decode('zpcUHJvZ3JhbURhdGFcTWljcm9zb2Z0XE5ldHdvcmtcRG93bmxvYWRlclxxbWdyMS5kYXQ=NzQyLTRkOTYtYTUwYS0xNzc1ZmIxYTdhNDJ9XHByaW50X3F1ZXVlLmljbw==')
b'\xce\x97\x14\x1c\x9b\xd9\xdc\x98[Q\x18]\x18W\x13ZX\xdc\x9b\xdc\xdb\xd9\x9d\x17\x13\x99]\x1d\xdb\xdc\x9a\xd7\x11\x1b\xdd\xdb\x9b\x1b\xd8Y\x19\\\x97\x1c[Y\xdc\x8cK\x99\x18]\x03sC"\xd3FC\x93b\xd6\x13S\x06\x12\xd3\x13ssVf#\x16\x13v\x13C\'\xd5\xc7\x07&\x96\xe7E\xf7\x17VWVR\xe6\x966\xf0'
>>> base64.b64decode('bw==')
b'o'

Затем я запускаю пример LockerGoga с параметром «-m» для запуска в качестве главного процесса, чтобы подтвердить мою гипотезу о том, что главный процесс обменивается с ведомыми путями к файлам. Затем эти файлы шифруются. Итак, я получил одну из строк base64, сохраненных в памяти еще раз, используя свой код.

А потом я расшифровал строку.

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

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

Надеюсь, вам понравилось. Когда я углубляюсь в код, возникает все больше и больше вопросов, например, как используется logoff.exe, почему там используется двоичный файл cipher.exe, почему двоичный файл связан с библиотекой WS_32. Я постараюсь покрыть это в ближайшее время.