Debug через print lvl master

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 библеотеку, можна отримати один з цікавих способів візуалізації, для справжніх линуксоидов/РОЅІХоидов — візуалізації в терміналі через текстову графіком. Вихідні коди великих візуалізацій лежать в це коммите.

Що таки потрібно зробити?

  • Зробити 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 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.