Недетский трюк от Криса Крис Касперски Хакер, номер #092, стр. 092-122-2 Создадим простейшую программу test.c и откомпилируем ее компилятором Microsoft Visual C++ с настройками по умолчанию. #include <stdio.h> main() { printf("hello, world!\n"); } Образовавшийся файл test.exe пропустим через утилиту dumpbin, входящую в состав MS VC (dumpbin /IMPORTS test.exe > out), и посмотрим, что хорошего она нам скажет: Dump of file test.exe KERNEL32.dll 405000 Import Address Table 4054AC Import Name Table 0 time date stamp 0 Index of first forwarder reference 2DF WriteFile 174 GetVersion 7D ExitProcess ... Ага, таблица адресов располагается по адресу 405000h, а lookup-таблица — по 4054ACh. Заглянув туда hiew'ом, мы увидим следующее (RVA-адреса имен импортируемых функций): .00405000:D8 56 00 00-62 55 00 00-70 55 00 00-7E 55 00 00 .00405010:92 55 00 00-A6 55 00 00-C2 55 00 00-D8 55 00 00 .00405020:F2 55 00 00-0C 56 00 00-22 56 00 00-3A 56 00 00 .004054AC:D8 56 00 00-62 55 00 00-70 55 00 00-7E 55 00 00 .004050DC:92 55 00 00-A6 55 00 00-C2 55 00 00-D8 55 00 00 .004050EC:F2 55 00 00-0C 56 00 00-22 56 00 00-3A 56 00 00 Как видно, обе таблицы полностью совпадают и указывают на массив имен/ординалов импортируемых функций: .004056D8:DF 02 57 72-69 74 65 46 61 70 41 6C-6C 6F 63 00 ??WriteFile А теперь пропустим через dumpbin «Блокнот» из стандартной поставки NT (dumpbin /IMPORTS notepad.exe > out) и увидим, в чем состоит разница. KERNEL32.dll 1001080 Import Address Table 1006784 Import Name Table FFFFFFFF time date stamp FFFFFFFF Index of first forwarder reference 77E99F42 1EF LocalUnlock 77E8B7F4 1AE GlobalUnlock 77E8CCA3 1A7 GlobalLock Таблица адресов еще до загрузки файла в память уже содержит готовые эффективные виртуальные адреса! Если не веришь — смотри hiew'ом: .010012D4:22 6A AF 76-47 26 AF 76-9E DB AE 76-5F FC AF 76 .010012E4:32 6A AF 76-E2 16 AE 76-71 6F AF 76-C2 AC AF 76 .010012F4:9C 1D AF 76-00 00 00 00-00 00 00 00-00 00 00 00 Ого! Содержимое таблицы адресов — эффективные виртуальные адреса импортируемых функций! Благодаря этой хитрости системному загрузчику уже не нужно тратить время на импорт функций. Он просто смотрит на поле временной отметки (TimeDateStamp) импортируемой DLL, и, если оно совпадет с DLL, установленной на компьютере, реальный импорт не производится. В противном случае, конечно, приходится напрягаться и тратить такты процессора на загрузку, но Microsoft обновляет свои прикладные приложения синхронно с обновлением системных библиотек, поэтому ее программы получают огромное преимущество над конкурентами. Какое коварство! Такая техника импорта функций называется биндингом (binding) и при желании может быть реализована с помощью утилиты editbin, позаимствованной все из того же компилятора (editbin /BIND test.exe). Посмотрим, что она сделала с нашим тестовым файлом? А сделала она с ним вот что: Dump of file test.exe KERNEL32.dll 405000 Import Address Table 4054AC Import Name Table 44B17B02 time date stamp Mon Jul 10 01:54:10 2006 |