Как стать автором
Обновить

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

Время на прочтение3 мин
Количество просмотров15K
Большая часть программ от 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().

#include <stdio.h>
#include <windows.h>

typedef INT (WINAPI *UndocFoo)(INT accumCRC32, const BYTE* buffer, UINT buflen);

int main()
{
	HMODULE hDLL = GetModuleHandle(TEXT("ntdll.dll"));
	if (hDLL == NULL)
	{
		puts("[-] Failed to find ntdll.dll\n");
		return EXIT_FAILURE;
	}
	puts("[+] Got ntdll.dll handle\n");

	UndocFoo ComputeCrc32 = (UndocFoo)GetProcAddress(hDLL, "RtlComputeCrc32");
	if (ComputeCrc32 == NULL)
	{
		puts("[-] Failed to find RtlComputeCrc32\n");
		return EXIT_FAILURE;
	}
	puts("[+] Found RtlComputeCrc32 address\n");

	puts("[*] Calling RtlComputeCrc32...\n");

	BYTE buffer[] = {0x01, 'a', 7};

	INT iCRC32 = ComputeCrc32(INT(0), (BYTE*)buffer, 3);

	printf("[+] Computed CRC32 --> 0x%x\n\n", iCRC32);
	
	puts("Press any key to quit\n");
	getchar();
	return EXIT_SUCCESS;
}




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



То же самое выдал онлайн-вычислитель:

"

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

Публикации

Истории

Работа

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн