Перехват библиотечных функций в linux и bsd

       

При всей непохожести windows на


При всей непохожести windows на linux между ними можно выделить общие черты. Обе системы образуют "слоеный пирог" из библиотек различных уровней иерархий. Ядерные функции windows NT сосредоточены в файле ntoskrnl.exe, доступ к которым осуществляется через прерывание INT 2Eh (NT 3.5x, NT4.x, W2K) или через INT 2Eh/sysenter (XP, Longhorn). В linux для той же цели используется прерывание IINT 80h (x86 BSD использует гибридный механизм, одновременно поддерживая как INT 80h, так и call  far 0007h:00000000h).
Ядро реализует базовые функции ввода/вывода, распределения памяти, создания/завершения процессов и т. д., причем если NT предоставляет низкоуровневые полуфабрикаты, над которыми еще предстоит поработать, ядерные функции linux'а (они же "системные вызовы" или по-английски sys-calls) вполне юзабельны. Тем не менее прямые обращения к ядру с прикладного уровня встречаются редко. Вместо этого приложения предпочитают использовать системно-независимую библиотеку libc.so.x – отдаленный аналог KERNEL32.DLL из windows. Эта библиотека загружается в физическую память всего один раз, а затем проецируется на адресной пространство всех используемых ее процессов ("so" расшифровывается как "shared object [file]", а x – номер версии, например, "libc.so.6").
Помимо libc, существуют и другие библиотеки, например, libncurses.so.x, отвечающая за управление курсором и отрисовку псевдографики в текстовом режиме ("аналог" USER32.DLL). Библиотеки могут подключаться как на стадии загрузки elf-файла через таблицу символов (аналог таблицы импорта), так и динамически по ходу выполнения программы посредством вызова функций dlopen/dlsym (аналог LoadLibrary/GetProcAddress соответственно). Наконец, всякая программа содержит большое количество непубличных не экспортируемых функций, которые так же требуется перехватывать.
В штатный комплект поставки (out form box) некоторых UNIX'ов входят две "хакерские" утилиты truss и krace (в LINUX – strace), следящие за системными вызовами и ведущие подробный log (см. листинг 1). К сожалению, эти утилиты есть не на всех системах, и даже там где они есть, для решения поставленной задачи они непригодны: многие библиотечные функции обрабатываются локально и до ядра просто не доходят. К тому же strace работает через механизм ptrace, а он нерентабелен (т. е. не позволяет трассировать уже трассируемые программы) и с которым успешно сражаются многие защитные механизмы, черви и упаковщики. Наконец, в некоторых случаях приходится не только шпионить за вызовами, но и "подминать" чужие функции, заменяя их на свои.


Как это сделать?
mmap(0x0,4096,0x3,0x1002,-1,0x0)                = 671657984 (0x2808b000)
break(0x809b000)                                = 0 (0x0)
break(0x809c000)                                = 0 (0x0)
break(0x809d000)                                = 0 (0x0)
break(0x809e000)                                = 0 (0x0)
stat(".",0xbfbff514)                            = 0 (0x0)
open(".",0,00)                                         = 3 (0x3)
fchdir(0x3)                                     = 0 (0x0)
open(".",0,00)                                         = 4 (0x4)
stat(".",0xbfbff4d4)                            = 0 (0x0)
open(".",4,00)                                         = 5 (0x5)
fstat(5,0xbfbff4d4)                             = 0 (0x0)
fcntl(0x5,0x2,0x1)                              = 0 (0x0)
__sysctl(0xbfbff38c,0x2,0x8096ab0,0xbfbff388,0x0,0x0) = 0 (0x0)
fstatfs(0x5,0xbfbff3d4)                         = 0 (0x0)
break(0x809f000)                                = 0 (0x0)
getdirentries(0x5,0x809e000,0x1000,0x809a0b4)   = 512 (0x200)
getdirentries(0x5,0x809e000,0x1000,0x809a0b4)   = 0 (0x0)
lseek(5,0x0,0)                                         = 0 (0x0)
close(5)                                        = 0 (0x0)
fchdir(0x4)                                     = 0 (0x0)
close(4)                                        = 0 (0x0)
fstat(1,0xbfbff104)                             = 0 (0x0)
break(0x80a3000)                                = 0 (0x0)
write(1,0x809f000,158)                                 = 158 (0x9e)
exit(0x0)                                       process exit, rval = 0
Листинг 1 образец отчета truss

Рисунок 1 программа "hello,world", под "микроскопом" truss'а

Содержание раздела