Mastodon

Monday, July 2, 2012

VMware + GDB stub + IDA

Многим известно, что в системе виртуализации VMware Worstation с самых незапамятных времен существует стандартный GDB интерфейс для удалённой отладки, однако, мало кто пользуется ним в повседневной работе в силу того, что отладку в "голом" GDB тяжело назвать удобной. Однако, в роли вполне вменяемого клиента для отладочного интерфейса GDB может выступать IDA Pro, в которой соответствующий функционал был добавлен ещё в 5-й ветке, но работать должным образом и без багов начал только в 6.0.
Отладка гостевой операционной системы Windows c использованием связки VMware + GDB stub + IDA бывает незаменимой когда приходится иметь дело с детектированием удалённых отладчиков ядра, отладкой PatchGuard, отладкой процесса загрузки ОС а так же критического кода (например, векторов прерываний) который по тем или иным причинам тяжело отлаживать с помощью WinDbg.
Очевидно, что отладочный интерфейс гипервизора ничего не знает о среде запущенной на нем  операционной системы Windows сам по себе, поэтому, для комфортной отладки с использованием VMware + GDB stub требуется некоторая настройка IDA Pro как debug клиента. В Hex Blog, в своё время, была опубликована заметка с описанием подобной настройки, к которой прилагался скрипт vmware_modules.py, который осуществляет:
  • Нахождение nt!PsLoadedModuleList и перечисление всех загруженных в настоящий момент модулей режима ядра, с последующим созданием сегментов для каждого из них.
  • Загрузку отладочных символов для всех найденных модулей.
Из-за ряда ошибок и недоработок в оригинальном скрипте, который не позволял нормально работать с ним - я решил его переписать, внеся следующие изменения:
  • Переписан алгоритм нахождения nt!PsLoadedModuleList. Оригинальный скрипт использовал базу сегмента FS для доступа к структуре _KPCR, что является не лучшей идеей: на остановленной в случайное время виртуальной машине в FS может быть загружен как user-mode, так и kernel-mode селектор, а поскольку в режиме пользователя FS указывает на совсем другую структуру (_TEB) - очень часто скрипт vmware_modules.py попросту не срабатывал. Вместо этого я реализовал поиск адреса nt!PsLoadedModuleList по сигнатуре в исполняемом образе ядра, адрес загрузки которого, в свою очередь, находится путём анализа векторов прерываний.
  • Добавлена полная поддержка Windows x64, отсутствовавшая в оригинальном скрипте. Поскольку стандартный способ для определения разрядности debug target-а через idainfo.is_32bit() / idainfo.is_64bit() на моей версии IDA Pro и IDAPython не работал (соответствующие функции всегда возвращали False) - я реализовал данный функционал путём небольшого хака с проверкой значения старших 24-х бит базы IDT.
  • Исправлены ошибки с загрузкой отладочных символов для модулей, чей полный путь не соответствует формату \SystemRoot\System32\<some_path>.
Моя версия скрипта доступна для загрузки в репозитории на GitHub:
https://github.com/Cr4sh/IDA-VMware-GDB

Необходимые шаги по настройке:
  1. Установить IDA Pro от 6.0 и старше и актуальную версию IDAPython для неё.
  2. Отредактировать .vmx файл виртуальной машины, добавив в него строчку debugStub.listen.guest32 = "TRUE" для 32-х разрядных гостевых операционных систем или debugStub.listen.guest64 = "TRUE" для 64-х разрядных.
  3. Для успешной загрузки отладочных символов необходимо скопировать директорию %SystemRoot%\system32 из гостевой операционной системы в хостовую, и указать путь к ней в переменной SYSTEM32_COPY_PATH внутри скрипта IDA-VMware-GDB.py.
  4. После запуска гостевой операционной системы в VMware Workstation можно в любое время подключить к виртуальной машине удалённый отладчик, для чего в IDA Pro следует выбрать пункт главного меню "Debugger" → "Attach" → "Remote GDB Debugger", указав номер порта 8832 для 32-х разрядного debug target-а или 8864 для 64-х разрядного. При этом IDA и GDB stub не конфликтуют с удалённой отладкой ядра Windows с помощью WinDbg и использовать с виртуальной машиной можно оба отладчика одновременно.
После выполнения данных шагов и запуска скрипта IDA-VMware-GDB.py становится возможной навигация между загруженными в память модулями режима ядра:


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