Использование Windbg для обратной разработки
Статья представляет собой мануал по тому как пользоваться Windbg. Будет рассмотрена «классическая» версия отладчика. Настроим внешний вид и изучим команды, которые можно использовать для исследования приложения.
Установка
Установка возможна только при использовании Windows SDK. Версию для Windows 10 можно найти здесь. Для работы с отладчиком необходимо запустить процесс установки SDK и выбрать только опции с набором инструментов для отладки. Пример выбора представлен на снимке ниже.
После установки набора инструментов, можно найти все файлы в директории «Windows Kits». Отладчик устанавливается сразу для нескольких версий процессоров. Для выполнения дальнейших команд в мануале нужно выбирать соответствую исследуемому файлу архитектуру процессора. Для исследования возьмем вот этот файл и попробуем найти ключ. Перед началом исследования файла, рекомендуется сделать дополнительную настройку:
Установить директорию и сервер для отладочных символов Проще всего это сделать можно через меню: File→Symbol File Path. В открывшемся меню нужно прописать вот эту строку: «SRVC:\symbolshttp://msdl.microsoft.com/download/symbols». Затем создать директорию C:\symbols;
Установить WorkPlace с удобной раскладкой рабочих панелей. Взять готовый Workspace можно отсюда. В итоге, если запустить для теста notepad.exe в отладчике, он будет выглядеть вот так:
Теперь можно перейти к исследованию команд. Откроем в отладчике файл и приступим.
Набор команд и анализ приложения
Полный справочник по всем командам отладчика можно найти по команде ».hh». Появится справка, как на рисунке ниже. Здесь можно вводить описание или конкретную команду.
Любой набор команд, который можно представить просто списком не имеет большой полезности, поэтому все команды, которые будут описываться в статье, будут сопровождаться примером применения. Начнем с простого.
Определим откуда начинается выполнение приложения. Если не вдаваться в подробности, то самое начало работы приложения это EntryPoint из заголовка файла, однако это не совсем так. EntryPoint для современных языков программирования сегодня это начало подготовительных операций для работы всего приложения. Поэтому если необходимо найти код, который был написан программистом, нам придется еще немного попутешествовать по дизасемблированному листингу.
Первая команда — lm. Показывает список модулей, которые загружены в память процесса, по выдаче этой команды можно получить базовый адрес файла.
Главные команды, которые станут глазами и ушами при исследовании данных в оперативной памяти — d? (b, c, a, p, w, q). Команда показывает дамп памяти по указанному адресу. Можно использовать конкретный адрес или регистр. Например, можно посмотреть как выглядит часть заголовка файла в памяти:
Команда ! dh разбирает файл и показывает заголовки. Нам нужен файловый заголовок, поэтому добавим флаг -f. Если необходимо показать все данные о файловых и секционных заголовках, то можно не дополнять команду.
Как видно на рисунке, данные, которые выдает команда, могут быть использваны для локализации данных внутри файла.
Локализуем точку входа с помощью суммирования базового адреса и информации из заголовка. Выполнить эту опирацию можно рядом команд: ? — выполнение выражения, uf — дизассемблирование функции, bp — установка точки останова. А теперь по порядку на примере:
Расчет адреса.
Дизассемблирование функции от адреса до ret команды.
Установка точки останова, кстати, чтобы управлять точками останова, можно менять последнюю букву команды. На рисунке показан пример установки точки останова и просмотр списка существующих точек через команду bl.
Чтобы дойти до точки останова, можно ввести команду, которая используется для выполнения алгоритма приложения — g.
Как только алгоритм загрузчика ОС выполнит все подготовительные действия мы увидим в командной строке следующие данные:
Можно приступать к поиску функции main. Сделать это достаточно просто, необходимо локализовать константы из интерфейса файла, когда выполняется приветствие и запрос данных:
Для поиска данных будем использовать команду s. Эта команда проводит поиск по определенному в команде объему данных. Соответственно чтобы получить данные о местоположении приглашения к вводу ключа, нужно указать всё адресное пространство исследуемого приложения. Так же необходимо указать тип данных, которые нужно искать.
Теперь, когда мы знаем адрес данных, которые используются, мы можем поставить точку останова, которая будет следить за доступом к данным. Сделать это можно с помощью команды ba. Для такой точки останова нужно указывать размер данных за которыми отладчик будет наблюдать, а там же адрес и тип доступа. Адрес должен быть выровнен по границе в 4 байта. После становки снова нужно запустить приложение через команду g. На рисунке ниже показан вариант команды:
Когда сработает точка останова, нужно найти часть алгоритма приложения, которая печатает приветствие на экран. Для этого удобно использовать стек вызовов функций. Для этого можно выполнить команду k.
Из рисунка видно, что копирование строки для работы с ней выполняется библиотечной функцией, а её вызов был сделан из «For_Crackme+0×15f2».
2. Локализуем функцию проверки ключа. Функция проверки будет недалеко от предложения ввести данные пользователя. В прошлом этапе мы нашли смещение внутри функции до этой операции. Введем можифицированную команду uf — u для того чтобы посмотреть несколько команд после адреса "For_Crackme+0x15f"
:
Фрагмент кода не содержит дополнительных отладочных символов, поэтому просто просмотрим данные рядом:
offset For_Crackme+0x40a2
offset For_Crackme+0x40bb
Чтобы это сделать, используем команду db:
Похоже, что функция подготавливает данные для выдачи информации пользователю. Значит проверка ключа должна быть где-то рядом. Обратим внимание на 2 константы, которые помещаются в память через следующие команды:
...
00401612 c744241c30372f31 mov dword ptr [esp+1Ch],312F3730h
0040161a c7442420302f3937 mov dword ptr [esp+20h],37392F30h
...
Если раскодировать константы, то мы получим вот такое значение:»07/10/97». Выполнить раскодирование может помочь команда .formats 312F3730h. Из списка форматов нас интересует Char или символьное представление. Стоит помнить, что данные в памяти хранятся в LittleEndian формате, поэтому если прочитать наоборот, то получатся данные необходимые для прохождения валидации.
Таким образом можно анализировать приложения с использованием Windbg и не прибегать к дополнительному инструментарию.
Статья написана в преддверии старта курса «Reverse-Engineering. Professional». Напоминаем о том, что завтра пройдет второй день бесплатного интенсива по теме «Пишем дампер процессов». Записаться на интенсив можно по ссылке ниже: