Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #80, АВГУСТ 2005 г.

Штурм ядра Linux

Крис Касперски ака мыщъх

Хакер, номер #080, стр. 080-106-4


За концом распаковщика идут текстовые строки "System halted", "Ok, booting the kernel", "invalid compressed format (err=1)", за ними следует длинная цепочка нулей, а потом начинается упакованный код, дизассемблировать который без предварительной распаковки невозможно. А как его распаковать? Поскольку линуксоиды не любят изобретать велосипед и всегда стремятся использовать готовые компоненты, ядро сжимается с помощью gzip.

Упакованный код начинается с "магической последовательности" 1F 8B 08 00, которую легко найти в любом hex-редакторе. В ядре 2.4.27 она расположена по смещению 4904h, а в ядре 2.6.7 по смещению 49D4h от начала файла. Выделим область отсюда и до конца файла, и запишем ее в файл с расширением gz (например, kernel.gz). Пропустив ее через gzip (gzip -d kernel.gz), мы получим на выходе готовый к дизассемблированию образ ядра. IDA Pro уже ждет, когда он будет в нее загружен.

Основной код ядра исполняется в 32-разрядном режиме и грузится в память по адресу 10:C0100000h. В самом начале идет модуль /arch/i386/kernel/head.S, а затем init.c, подгружающий все остальные модули. Как определить, какому именно модулю соответствует данная часть дизассемблерного кода?

В директории /boot лежит замечательный файл System.map-x.y.z (где x.y.z номер версии ядра), в котором перечислены адреса публичных символьные имен, они же метки:

Фрагмент файла System.map-2.4.27

c0108964 T system_call

c010899c T ret_from_sys_call

c01089ad t restore_all

c01089bc t signal_return

c01089d4 t v86_signal_return

c01089e4 t tracesys

c0108a07 t tracesys_exit

c0108a11 t badsys

В частности, в ядре 2.4.27 метке ret_from_sys_call соответствует адрес C010899Ch. Отняв отсюда базовый адрес, мы получим смещение метки от начала файла: 899Ch, ну а саму метку нетрудно найти в исходных текстах глобальным поиском. Она определена в файле /arch/i386/kernel/entry.S. Остальные метки обрабатываются аналогично.

А вот другой трюк: если в ядре встретилась текстовая строка или "редкоземельная" команда вроде lss или "mov cr4,xxx", глобальный поиск легко обнаружит ее в исходных текстах. Поскольку компилятор таких команд заведомо не понимает, здесь явно имела место ассемблерная вставка, а значит, дизассемблерный код будет практически полностью совпадать с соответствующим фрагментом исходного текста!

В общем, в дизассемблировании ядра нет ничего сверхъестественного, и эта задача вполне по силам рядовому кодокопателю.

[где гнездятся ошибки]

В прикладных программах и серверных приложениях наибольшее количество ошибок сосредоточено в переполняющихся буферах (атаки типа buffer overflow и buffer overrun). В ядре так же имеются буферы, некоторые из которых могут быть переполнены, однако, атаки этого типа для него не так характерны.

Назад на стр. 080-106-3  Содержание  Вперед на стр. 080-106-5