image

Эта статья является логичным продолжением моей старой статьи про визуализацию работы brainfuck алгоритмов на виртуальной машине с циклической памятью. Под катом немного тяжеловатого видео и картинок.

++recoveryModePublicationCount; // количество оборотов мнения некоторых хабраюзеров на ...




Почему debug через print? Print является самым простым средством визуализации процессов и памяти, хорош тем, что он работает вместе с написанным кодом (в отличие от отладчика, который например как в swift просто не воспринимает иногда breakpoints, evals и проч привычные вещи)
А теперь представим, что всю работу программы можно визуализировать через print? Казалось бы нет, но если программа не занимает довольно много памяти, то можно.

Конечно, такая визуализация не будет полной, без визуализации регистров процессора, всего стека, кучи, и маленького slow-down работы этой программы.
В RayFoundation на уровне библиотеки заложена возможность подменять memory managment указатели (как malloc, free), и таким образом контролировать и/или sandbox-ить код, об этом немного тут, но если не читали — не отвлекайтесь, потому что такой большой обьем технических подробностей тут не очень уместен (интересен будет не всем).

Так вот, можно считать что sandbox создает непрерывную страницу памяти какого-то, заданного программистом размера. Как оказалось, для тестов ray было достаточно (для красоты визуализации это должен быть квадрат NxN) 256 х 256 = 65536 байт памяти + размер worker структуры самой sandbox. И это для работы в «простом» и "ASLR" режимах. Далее будет наглядно показана разница в этих режимах, через тот самый master-lvl-print-дебаг.

Несложными манипуляциями, прикручивая ncurses библеотеку, можно получить один из интересных способов визуализации, для настоящих линуксоидов/POSIXоидов — визуализации в терминале через текстовую графику. Исходные коды больших визуализаций лежат в этом коммите.

Что таки нужно сделать?


  • Сделать sandbox и выбрать ему размер
  • Сделать делеи в работе программы (в данном случае это делеи во время malloc, calloc, realloc, free потому что это единственные контрольные точки, изменение которых не расползется по всему коду, можно было вставить usleep везде, но это для тех кому не будет лениво, но если это inject-библиотека для анализа, то это именно единственные контрольные точки для аналитика, и поставить usleep везде нет возможности)
  • Отображать память sandbox в терминале через ncurses в отличном от main потоке


Сказано — сделано. Первые результаты (смотреть в полноэкранном режиме):

Default-mode



(каждая цветная точка — это байт памяти со значением >0, нулевые байты черного цвета, немного криво от того что терминал размером 512х256 мне так и не удалось создать с нормальным масштабом)

Это работа в дефолтном моде, где каждый элемент который был malloc-цирован ставится в самое начало свободного участка памяти.
Я, как человек который знает что делает код, могу на «глаз» сказать где какая структура находится, потому что для ray, например, характерно наличие autoPool, который чистит память если нужно, это массив, который хранит все указатели на malloc-ированные обьекты. Получается такой себе мешок в мешке, т.к. этот пул работает внутри sandbox, и я долго добивался эффекта, чтобы можно было сделать множество вложенных пулов и sandbox, но это лирика. Приблизительная (немного грубо отмечено) схема обьектов:

image

Круто же, неправда ли?
Можно посмотреть как выглядит память, попробовать себя на статическом и динамическом анализе в отличении отдельных обьектов, структур хранения. Но случай выше очень идеальный, для реального мира. Дело в том, что sandbox при каждом удалении обьектов делал memset(0), что почти никогда, реальный аллокатор не делает, он делает это после определенного количества освобожденных обьектов и делает это целыми страницами.

Вот пример стандартной sandbox с «насыщением» т.е. место удаленных обьектов переиспользуется а не зануляется:

Default-mode with saturation




Для систем требовательных к безопасности здесь можно отметить несколько особенностей:
  • некоторые обьекты которые находятся в памяти достаточно долго все еще можно отследить (RPool в верху экрана)
  • некоторая критическая информация может остаться не удаленной и ее можно считать
  • равномерное замусоривание в области работы не дает четко распознать какие обьекты там работают
  • можно провести частичный анализ по области значений байт, и попытаться выделить основные рабочие структуры, но замусоривание делает это чуть сложнее


ASLR-mode




Еще круче. Но, в этой картинке трудно что-то разобрать. Единственное что я увидел это одну активную область, которая постоянно изменяется. Что это может быть за область? Она всегда меняется и остается на одном и том же месте.
image

ответ
это счетчик RPool-а, который знает сколько указателей находится в текущий момент времени в программе на куче, и рядом с ним счетчик свободных мест, которые остаются для указателей


Можно выделить еще немного особенностей для ASLR-mode
  • при достаточной архитектуре обьектов с указателями и интенсивной работе с кучей довольно тяжело разобрать что здесь где находится, т.к. одна статическая часть обьекта может быть в одном куске памяти, а остальные суб-обьекты могут быть совершенно в другом
  • по времени жизни обьектов и интенсивности изменения их кусков все еще можно распознать некоторые части программы
  • равномерное распределение памяти выглядит безопаснее от того, что не зная значения ГПСП нельзя провести атаку по конкретному указателю обьекта, а если обьект использует realloc, и не зная времени этого realloc — нельзя провести атаку длительную по времени
  • можно частичный анализ по range значений байт, и попытаться выделить основные рабочие структуры, но при множественных суб-частях и realloc-ах почти нереально


ASLR-mode with saturation




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

Есть еще пару видео с визуализацие работы тестов RList, на меньшем куске памяти и с большим масштабом.

default-mode:


aslr-mode:


Выводы


Такой инструмент наглядно показывает работу структур, позволяет находить утечки памяти, а alsr иногда помогает находить access violation, т.к. если переписать чуть дальше своего размера можно внезапно получить sigsegv и много интересных вещей. С другой стороны это еще и помогает своему коду быть немного безопаснее.

P.S. если нужно будет могу приаттачить исходные видео на github, т.к. у них кач-во получше чем youtube конвертированных
P.P.S. огромное человеческое спасибо JetBrains за их opensource лицензии

Комментарии (0)