Пример использования недокументированной функции Windows

12 Окт
2011

Большая часть программ от Sysinternals использует недокументированные функции. Мне хватило этого факта, чтобы заинтересоваться этой темой. Интересно, как крутые дядьки используют неописанные функции в своих не менее крутых программах.
Предполагаем, что мы в нужной степени ленивые программисты, знаем С, в ладах с WinAPI и с архитектурой современной ОС Windows и у нас есть Ida Pro, хе-хе. Хотим красиво, быстро и эффективно выполнить задачу, не изобретая велосипед (и чтоб ещё сильно не перенапрячь руки и голову).

Поищем подопытную функцию. Много вкусного можно найти в ntdll.dll. Сам я пишу из-под Win7 64, но взял 32-битную версию чудесной библиотеки. На всякий случай: %SystemDisk%\Windows\System32\ntdll.dll.
Чтобы было просто, откроем ntdll в Ida и посмотрим, какие функции экспортируются. Если нет Ida, то можно взять любую программу работающую с PE-файлами (например, PETools). Нас интересуют функции с приставкой Rtl (Run Time Library). То есть во время выполнения нашего кода мы можем попросить эту системную функцию об услуге.
После небольшого поиска простенькой функции, таковая нашлась — RtlComputeCrc32.

Двойным щелчок по имени функции получаем её дизассемблированный код. Изучать функцию можно и любым другим дизассемблером вроде HDasm или W32Dasm. Чтобы не тратить место, приведу псевдокод RtlComputeCrc32, любезно предоставленный декомпилятором Ida (в теле функции нажать F5, если Hex-Rays Decompiler имеется в плагинах Edit->Plugins).

Сразу получаем много информации! Надо подумать, что мы, собственно, ищем. Нам нужно:
1) имя функции, чтобы получить её адрес в ntdll;
2) прототип функции, чтобы создать правильный указатель на неё;
3) примерный принцип работы, чтобы передать ей корректные аргументы и правильно обработать результат;
Пункты 1-2 у нас уже есть из псевдокода. Задача наша теперь разобраться в функции и на её основе написать программу, высчитывающую CRC32 от чего-то.
По псевдокоду легко понять, что функция перебирает байты массива a2, размер которого a3, а а1 — инициализирующее значение алгоритма. Проделав вычисления с байтами, получает индекс из таблицы RtlCrc32Table (двойной щелчок покажет монструозную таблицу). Гуглим CRC32 и примеры реализации и понимаем, что всё верно.
Дело за малым — воспользоваться добычей. Я сделал пустое консольное приложение в Visual Studio, но делать, естественно, можно и в любой другой среде.
GetModuleHandle() возвращает хэндл ntdll, GetProcAddress() — адрес функции. Используем указатель на функцию типа UndocFoo для вызова RtlComputeCRC32().



Успех. Проверить можно с помощью любого онлайн-вычислителя.
Наши байты 016107 дали CRC32 = 0x1c017c60.

То же самое выдал онлайн-вычислитель:
«
Вот так, без траты времени на реализацию собственной функции или использования чужого большого кода, мы сделали такую чудесную программку. Было несложно и весело.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх