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

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

Для всех трех задач существуют важные правила, которым мы должны следовать:

  1. Нам не нужно запускать данный файл .exe, а только статический анализ.
  2. Мы не должны использовать отладчик/дампер для извлечения расшифрованного флага из памяти. Это будет считаться мошенничеством! 😉

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

Анализ файла «strings1.exe_» двоичного

  • После добавления «strings1.exe_» в проект Ghidra, открытия в окне браузера кода и анализа с использованием параметров по умолчанию мы видим что-то вроде этого:

  • Затем в левом представлении Дерево символов мы наблюдаем список Функций:

  • Функция с именем entry в этом списке должна быть точкой входа, и, нажав на это имя, мы получим представление Listing с инструкциями по сборке и также представление Декомпилировать, представляющее эквивалентный исходный код на языке программирования C.
  • Наблюдая за сборкой, выделенной зеленым цветом строкой и даже декомпилированным кодом C, мы получаем аналогичную переменную, переданную в качестве аргумента; теперь видно, что какая-то строка хешируется вызовом функции md5_hash(). Итак, как только мы дважды щелкнем по регистру EAX в той же строке инструкции PUSH в представлении сборки, и мы доберусь до первого флага!

  • После отправки мы получаем успешный ответ в браузере:

Анализ бинарника strings2.exe_

  • Давайте откроем второй «strings2.exe_» в Ghidra, снова найдем функцию с именем entry:

  • Мы ясно замечаем, что некоторые шестнадцатеричные значения назначаются ячейкам памяти в представлении Listing инструкций по сборке, и аналогичным образом эти шестнадцатеричные значения назначаются различным переменным в декомпиляции. , за исключением того, что первое назначение начинается с буквы 'F' вместо 0x46. Таким образом, эта последовательность, скорее всего, представляет собой отдельные символы строки флага, такие как 0x46 (т. е. 70 в десятичном формате). принадлежит 'F' в таблице ASCII.
  • Давайте узнаем флаг, используя простой код Python ниже, который использует все эти шестнадцатеричные значения для получения последовательности символов в виде строки:

  • Еще раз, при отправке мы получаем успешный ответ в браузере:

Анализ бинарника strings3.exe_

  • Эта задача более интересна, поскольку в ней используются различные строки, сохраненные и связанные из файла ресурсов (.rc).
  • Снова в Ghidra загрузили 'strings3.exe_' и нашли функцию entry, давайте пройдем через декомпиляцию вид с правой стороны:

  • Здесь сначала инициализируется MD5, затем некоторые ячейки памяти заполняются 0 (нулем) с помощью функции memset().
  • Затем функция FindResourceA() находит местонахождение ресурса с заданным типом и именем. Указанный тип (3-й аргумент) — 0x6, поэтому он указывает на тип ресурса 'RT_STRING'. который является строковой записью таблицы. Указанное имя (2-й аргумент) — rc.rc, то есть имя ресурса, а дескриптор (1-й аргумент) — 0x0 означает, что функция ищет модуль, используемый для создания текущего процесса. Этот вызов функции фактически возвращает дескриптор информационного блока указанного ресурса.
  • После возврата дескриптора информационного блока функция LoadStringA() принимает 4 аргумента. Первый аргумент — 0x0, чтобы получить дескриптор самого приложения. Второй аргумент — 0x110 (т. е. 272 в десятичном формате), который говорит, что идентификатор строки должен быть загружен. Итак, это строковый идентификатор в файле ресурсов (который мы увидим далее). Третий аргумент на самом деле является буфером для приема строки или указателем только для чтения на сам строковый ресурс. Это означает, что строка флага, скорее всего, будет храниться в этом буфере. Четвертый аргумент — это размер этого буфера в символах.
  • После того, как строка загружена в буфер из функции LoadStringA(), она хешируется по алгоритму MD5, так что дальнейшая вещь не так уж и полезна. На самом деле нам нужно найти идентификатор строки в ресурсе, и это будет наш требуемый флаг!
  • Нам нужно проверить раздел .rsrc на наличие сохраненных строковых ресурсов, используя представление Program Trees слева:

  • Прокрутив немного вниз, мы обнаружили начало записи таблицы строк в ресурсах:

  • Используя эти идентификаторы, мы можем идти вниз, пока не достигнем 0x110 (т. е. 272 в десятичном формате) строкового идентификатора:

  • Наконец, при отправке мы получаем успешный ответ в браузере:

Это было весело! Потому что, как мы знаем, реверс-инжиниринг и системные низкоуровневые вещи становятся все более увлекательными и интересными, когда мы погружаемся еще глубже…

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

Эми Чаван