Эта статья представляет собой руководство по x64dbg, в котором объясняется и демонстрируется методика реверс-инжиниринга вредоносных программ. Она является продолжением нашей серии публикаций, посвященных x64dbg: Часть 1. Что такое x64dbg и как им пользоваться? Часть 2. Распаковка вредоносного ПО с помощью x64dbg (мы здесь) Часть 3. Обзор Stack Memory Часть 4. Анализ вредоносного ПО с помощью x64dbg В предыдущей части мы рассмотрели, что такое x64dbg, а также некоторые функции этого инструмента и поговорили о том, в чем заключается их польза для анализа вредоносных программ. Эта статья будет служить руководством по x64dbg, в котором мы расскажем о методике, которую можно использовать при обратной разработке вредоносных программ, и продемонстрируем применение этого инструмента для распаковки вредоносного ПО.   В этой статье мы рассмотрим следующие сценарии использования x64dbg: распаковка вредоносного ПО вручную Загрузка распакованного вредоносного ПО в x64dbg Анализ вредоносного ПО и его функций При использовании x64dbg для реверс-инжиниринга вредоносных программ сначала рекомендуется провести поведенческий анализ двоичного файла с помощью определенных инструментов в свободном доступе. Такой предварительный анализ дает представление о том, что делает вредоносная программа, когда проникает на устройство. На основании этих сведений можно определить некоторые ключевые индикаторы компрометации (indicators of compromise, IOC), такие как сетевой трафик, записанные на диск файлы, а также механизмы персистенции. Также можно получить приблизительное представление о том, какие цели ставит злоумышленник при составлении вредоносной программы: будь это финансовая мотивация (например, как у программ-вымогателей), или желание получить бэкдор-доступ к сети (как в случае с RAT, например). Без этого предварительного сбора фактов мы не рекомендуем открывать вредоносное ПО в x64dbg и вслепую просматривать его ассемблерный код. Другая проблема заключается в том, что без такого базового анализа можно просмотреть запакованный код и не найти ничего интересного. Вредоносное ПО часто имеет очень запутанный код — ведь злоумышленники потратили много времени на его написание и не хотят, чтобы кто-то мог, бегло взглянув на их программу, быстро понять, что она делает и как ее остановить. Запакованное вредоносное ПО, по сути, "обернуто" слоем кода, под которым скрывается код, написанный разработчиком вредоносного ПО: этот метод запутывания известен как "упаковка" вредоносного ПО. Хорошая новость заключается в том, что одна из важных функций x64dbg дает возможность вручную распаковать вредоносное ПО, после чего можно снова загрузить распакованный файл в x64dbg и начать фактический анализ вредоносной программы. Распаковка вредоносных программ — отличный навык, который обязательно нужно иметь в своем арсенале, однако с чего начинать анализ после распаковки двоичного файла? Во-первых, не стоит анализировать каждую строку кода от начала до конца — это просто займет слишком много времени. По результатам предварительного динамического анализа можно выявить определенные особенности поведения вредоносного ПО, требующие дополнительного изучения. Возможно, вредоносная программа генерирует случайные имена файлов на каждом зараженном устройстве. В этом случае полезно разобраться, как генерируются эти имена. Вредоносное ПО включает несколько функций, которые либо были написаны его разработчиком, либо были им импортированы. Например, во вредоносной программе может быть функция, создающая файл на диске. Проанализировав данную функцию с помощью x64dbg, мы можем определить потенциальное место записи и имя этого файла. Разработчик вредоносной программы может написать свою функцию, а может импортировать одну из уже имеющихся функций Windows. Другими словами, в некоторых случаях вместо того, чтобы писать код для конкретной функции, злоумышленники импортируют легитимные функции Windows API, которые могут выполнять часть работы за них. Импортируемые разработчиками вирусов функции являются легитимными функциями Windows, известными как Windows API. В Windows есть несколько библиотек, которые содержат уникальные функции, - DLL (динамически связанные библиотеки). Например, Kernel32.dll содержит API WriteFile, которую может импортировать вредоносная программа, чтобы использовать ее для записи файлов на диск. Когда вредоносное ПО импортирует библиотеки DLL, аналитик вредоносных программ может использовать эту информацию, чтобы получить приблизительное представление о том, что может делать конкретный вирус. Импортируемые Windows API составляют таблицу адресов импорта (Import Address Table, IAT). Анализируя вредоносное ПО в x64dbg, вы начинаете с функции main. Это основная часть кода, написанного разработчиком вредоносной программы. Однако внутри этой функции вредоносное ПО будет вызывать другие функции, созданные разработчиком вируса или представляющие собой Windows API, импортированные вредоносной программой. Например, если вредоносному ПО необходимо создать файл, оно может использовать для этого Windows API CreateFileA. Поскольку это легитимная функция Windows, нам не нужно анализировать ассемблерный код CreateFileA — нас интересует результат этой функции, а также аргументы, передаваемые функции перед ее вызовом или выполнением. Проведя такой анализ, мы можем увидеть, как файл будет вызываться и где он будет записан на диске, а по возвращаемому значению можем определить, успешно ли функция создала файл. На изображении ниже показано, как одни функции вызываются из других. Предположим, что код, который мы хотим проанализировать, — это функция, написанная разработчиком вредоносной программы. В нашем примере представим, что функция, которую мы назвали AAA, была создана разработчиком вируса, и мы хотим детально ее изучить. В x64dbg есть две инструкции, которые вы будете регулярно использовать: step over и step into. Если указатель на следующую ассемблерную инструкцию, которая будет выполняться, установлен на CALL AAA ("вызвать AAA"), мы можем либо "перешагнуть" эту инструкцию, либо "войти" в нее. Если мы "перешагиваем" инструкцию, функция все равно выполняется, однако мы не видим выполняемых инструкций. Если используется step into, мы попадаем в адресное пространство, где начинается эта функция, и видно ее содержимое. Внутри этой функции могут быть другие функции, которые вы захотите исследовать. В нашем примере мы можем войти в функцию CCC и снова перейти в новое адресное пространство, где эта функция начинается. Перемещаясь по коду, в конечном итоге мы добираемся до конца функции, о котором свидетельствует команда return ("возврат"). Сразу после выполнения этой команды переходим к инструкции непосредственно после вызова функции CCC и возвращаемся к функции AAA. Мы снова можем пробежаться по коду и дойти до инструкции return (переходя к инструкции сразу после вызова функции AAA). Вызовы Windows API можно идентифицировать по имени, начинающемся с библиотеки DLL, из которой они загружены, или их зарегистрированного имени Microsoft. В нашем случае мы использовали имя BBB просто в качестве примера; раз это Windows API, нам не нужно входить в эту инструкцию, поскольку она не была написана разработчиком вредоносного ПО. Но нам интересно узнать, что было помещено в стек до вызова функции, а также что возвращает функция после выполнения. Анализ абсолютно каждой функции, созданной разработчиком вредоносного ПО, займет очень много времени. Как мы уже отмечали, предварительный поведенческий анализ вредоносной программы может найти что-то интересное, требующее детального изучения. В нашем примере мы анализируем вредоносное ПО Emotet. Когда оно заражает устройство, оно генерирует для себя случайное имя файла. Поэтому в ходе предварительного анализа мы сосредоточились на вызовах API с соответствующей активностью, а затем изучили действия вредоносного ПО в этот момент времени. Сейчас мы продемонстрируем технику, позволяющую сначала идентифицировать упакованное вредоносное ПО, а затем распаковать его вручную с помощью x64dbg.   Примечание. Не пытайтесь анализировать вредоносное ПО без предварительной настройки безопасной виртуализированной среды. x64dbg не следует устанавливать на вашем хост-компьютере для анализа вредоносных программ. На хост-компьютере должен быть установлен соответствующий антивирус. Пример: b1cad1540ecb290088252635f8e130022eed7486eb128c0ca3d676945d60a9fc Имеется ряд методов, позволяющих определить, упакована ли вредоносная программа. Один из методов заключается в выполнении вредоносной программы на виртуальной машине с запущенным инструментом Process Monitor (ProcMon). ProcMon регистрирует активность файловой системы на компьютере, на котором он запущен, и позволяет просмотреть только новые созданные процессы. Вредоносная программа, которую мы использовали в этой демонстрации, называется 267.exe. На изображении ниже показаны некоторые процессы, которые зафиксировал ProcMon на виртуальной машине, на которой был запущен вирус. Два нижних процесса называются 267.exe. Первый сгенерированный процесс начался в момент запуска вредоносного ПО. На изображении видно, что вредоносная программа затем создала одноименный дочерний процесс. Это вирус, распаковывающийся в память. Такой метод известен под названием "внедрение в процесс" (process injection). Запакованная вредоносная программа была запущена с целью распаковать саму себя; она создает новый процесс — это дочерний процесс, показанный на изображении выше. Затем родительский процесс выделяет в новом дочернем процессе свободное пространство. После этого распакованный код внедряется в свободное пространство внутри этого вновь созданного дочернего процесса (отсюда и произошло его название). В нашем примере мы также можем видеть, что вредоносная программа затем удаляется с рабочего стола, копируется в постоянное местоположение C:\Windows\SysWOW64 и переименовывается в loadatangent.exe. Такой же метод внедрения в процесс используется для самораспаковки, и теперь вредоносная программа работает на диске как процесс loadatangent.exe. Проведя простой поведенческий анализ, мы определили, что вредоносная программа упакована, и у нас есть свидетельства того, что она распаковывается в памяти. Пришло время воспользоваться x64dbg, чтобы выделить распакованное вредоносное ПО для дальнейшего анализа. Перетащив вредоносное ПО на значок x64dbg на рабочем столе, мы загрузим вредоносную программу в x64dbg. Первое, что следует отметить, это заголовок инструмента: Сейчас мы анализируем модуль ntdll.dll. Это DLL Windows, импортированная вредоносным ПО, а не код, написанный его разработчиком. Нас интересует только анализ кода, написанного разработчиком вредоносной программы. Модуль, который нам нужно проанализировать, — это файл, который мы открыли в x64dbg, т. е. 267.exe. Выбрав Debug (отладка), а затем Run (выполнить) на панели инструментов, мы перейдем к точке входа вредоносного ПО. Это функция main, упомянутая выше в разделе "Методология". x64dbg теперь будет работать до точки входа вредоносной программы. Это подтверждается тем, что указанный модуль изменился на 267.exe, а комментарий "EntryPoint" теперь виден в 5-м столбце главного окна ассемблера.   Теперь мы можем приступить к изучению кода вредоносной программы, однако предварительно должна быть поставлена четкая цель. Мы уже видели, что этот вирус распаковывается, создавая новый процесс и внедряя распакованный код в этот процесс. Поэтому для начала будет правильно сосредоточить внимание на некоторых Windows API, создающих новые процессы и выделяющих память внутри них. Для этого мы можем установить точки останова для вызовов Windows API, которые могут быть импортированы вредоносным ПО для генерации этой активности. Мы установиои точку останова на VirtualAlloc; теперь можно увидеть, когда вредоносная программа выделяет место в памяти для нового процесса; затем можно проверить соответствующее адресное пространство на предмет внедрения распакованного вредоносного ПО. Имеется несколько способов поставить точки останова. Например, используя сочетание клавиш CTRL+G, которое открывает новое всплывающее окно. После ввода имени интересующего нас Windows API x64dbg проверит, присутствует ли соответствующее значение во вредоносной программе. На изображении выше мы видим, что данный API был найден в библиотеке DLL Kernel32. После нажатия ОК в x64dbg отобразится местоположение функции.   На изображении выше видно, что мы находимся в модуле kernel32.dll, а также показан адрес VirtualAlloc. Мы можем установить точку останова на адресе, с которого запускается VirtualAlloc, однако в рамках анализа мы попытаемся увидеть, какие данные будут помещены в память, созданную этим API, который, как мы надеемся, будет распакованной вредоносной программой. Так что установим точку останова не в начале, а в конце функции VirtualAlloc. На изображении выше показано несколько инструкций перехода (команда jmp). При нажатии клавиши Enter на этих переходах x64dbg будет следовать "переходам", отмеченным красными стрелками. На изображении выше видно, что мы обнаружили конец функции VirtualAlloc, представленный инструкцией возврата ret 10. Чтобы установить точку останова, щелкните правой кнопкой мыши по инструкции возврата, выберите Breakpoint (точка останова), а затем Toggle (переключить). Адрес инструкции возврата — 7685F199; после задания точки останова этот адрес станет красным. Убедиться в том, что точка останова поставлена, можно во вкладке Breakpoints (точки останова). На изображении выше показана начальная точка останова, которая была задана в точке входа вредоносной программы. Вторая указанная точка останова — это точка, которая была установлена на инструкции возврата VirtualAlloc (обратите внимание на ассемблерную инструкцию и указанный адрес). Щелчок по вкладке CPU вернет нас к ассемблерному коду, а нажатие SHIFT+8 — к адресу, где в настоящее время находится указатель инструкции (EIP). Теперь мы можем запустить код и исследовать любые точки останова, которые достигаются при вызове VirtualAlloc вредоносной программой. Обратите внимание, что эта точка останова может быть достигнута несколько раз, поэтому при любом анализе требуется непродолжительное применение метода проб и ошибок. На панели инструментов выберем Debug (отладка) и Run (выполнить) — вредоносное ПО будет работать до тех пор, пока не будет достигнута точка останова и программа не будет приостановлена. На изображении ниже мы видим, что точка останова достигнута и теперь EIP указывает на адрес инструкции возврата, где размещена эта точка. Обратите внимание, что в верхней части окна x64dbg текущий модуль показан как kernelbase.dll. Это DLL, в которой находится VirtualAlloc.   Возвращаемое значение VirtualAlloc можно определить, "перешагнув" эту инструкцию (либо войдя в нее). Для этого выберем Debug на панели инструментов.   Теперь EIP перемещается к инструкции после вызова VirtualAlloc. Обратите внимание, что мы вернулись в модуль 267.exe и вызов VirtualAlloc был сделан не напрямую. Непрямой вызов означает, что вместо использования инструкции CALL VirtualAlloc функция VirtualAlloc была сохранена в регистре EDI и вызов был сделан инструкцией CALL EDI. На изображении ниже показан вызов EDI и VirtualAlloc, сохраненной в регистре EDI.   Теперь с помощью VirtualAlloc была выделена память, однако нам нужно посмотреть, используется ли эта память для перемещения в нее распакованного вредоносного ПО. Проверив параметры, передаваемые после выделения памяти, мы можем увидеть, сохраняется ли в них распакованная вредоносная программа. Эти параметры выделены на изображении ниже. Щелкните правой кнопкой мыши по параметру [esp+28], затем выберите Follow in Dump (отследить в дампе), чтобы отобразить содержимое этого параметра. Тот же результат даст применение опции Selected Address (выбранный адрес) или Address: ESP+28 (адрес: ESP+28).   Затем окно x64dbg обновится, показывая все данные, занесенные в дамп пользователем. Теперь поищем заголовок исполняемого файла. Заголовки файлов используются операционной системой для определения их типов; заголовок исполняемого файла Windows всегда начинается с 4D 5A в шестнадцатеричном формате (MZ в ASCII). Результат занесенного в дамп параметра показывает, что этот параметр не содержит искомого, поскольку значения 4D 5A и MZ отсутствуют. Второй параметр [esp+2c] также не содержит вредоносного ПО, поэтому необходимо разрешить выполнение вредоносного ПО, пока мы не найдем его. Снова нажмем Debug, чтобы запустить вредоносную программу, пока опять не будет достигнута точка останова, когда будет сделан вызов VirtualAlloc. Повторяется тот же процесс, что и раньше, и затем анализируются новые параметры. На этот раз вызов VirtualAlloc был сделан путем вызова регистра EBP; и снова вредоносная программа использует два параметра. Щелкнув правой кнопкой мыши по [edi+54] и проследив за содержимым этого параметра в окне дампа, вы увидите, что он действительно содержит исполняемый файл Windows (спойлер: это распакованная вредоносная программа!)   Прокрутив окно дампа вверх, мы увидим заголовок исполняемого файла Windows — распакованная вредоносная программа успешно обнаружена. Обратите внимание на значения 4D 5A и MZ и строку "This program cannot be run in DOS mode" (эта программа не может быть запущена в режиме DOS). Чтобы извлечь распакованную вредоносную программу, щелкните правой кнопкой мыши по MZ и выберите Follow in Memory-Map (проследить в карте распределения памяти).   Теперь мы видим, где распакованная вредоносная программа находится в памяти и какие разрешения были выделены для этой области памяти.   На изображении выше показан адрес распакованного вредоносного ПО, а также уровень защиты, выделенный для данной области памяти. Могут быть установлены три возможных флажка: E — исполняемая, R — чтение и W — запись. Если для уровня защиты установлено значение ERW, это явный признак того, что это распакованная вредоносная программа, поскольку память, выделенная для вредоносного ПО, должна быть исполняемой и доступной для записи. Чтобы извлечь распакованную вредоносную программу, щелкните правой кнопкой мыши по адресу памяти и выберите Dump Memory to File (дамп памяти в файл). Выберите путь для сохранения распакованного файла и откройте файл с помощью шестнадцатеричного редактора.   Мы видим заголовок файла, который мы только что выгрузили из памяти, однако этот файл не похож на исполняемый файл Windows, поскольку заголовок не начинается с 4D 5A в шестнадцатеричном формате, а имеющиеся значения ASCII не начинаются с MZ. Причина в том, что вредоносная программа была выгружена из памяти, поэтому к файлу был добавлен "мусорный" (junk) код. Чтобы очистить файл, воспользуйтесь сочетанием клавиш CTRL+F для поиска значения MZ. Нажав OK, вы обнаружите флажок MZ и соответствующие значения 4D 5A.   Чтобы очистить файл, выберите весь шестнадцатеричный код, добавленный перед 4D 5A, и удалите его: Теперь у нас есть отличный чистый файл, который представляет собой распакованную вредоносную программу.   Мы успешно распаковали вредоносное ПО и можем приступить к анализу кода, написанного его разработчиком! Итак, мы рассмотрели, что такое x64dbg, а также рассказали о том, как можно использовать x64dbg для распаковки вредоносных программ. В следующей статье мы расскажем, что такое стековая память и как она соотносится с x64dbg, а затем применим эти знания для анализа распакованного вредоносного ПО.