Использование недокументированных функций, довольно широко используется в современных программных продуктах. Они позволяют получить доступ к скрытым или к интересным свойствам системы. А иногда и ускорить выполнение какого-то участка кода. Но у них есть один довольно серьёзный минус, который перечёркивает все те плюсы, которые были описаны выше. Так как они не документированы, за их поддержку и работу, особо никто не отвечает. Поэтому всю ответственность за возможную не работу берёте на себя только вы. К тому же, разные версии Windows могут и не поддерживать эти функции. Так что выбор использовать или нет, только за вами.
Пока вы думаете, мы разберём несколько примеров, которые помогут разобраться в этом с виду тёмном лесу. Все примеры будут относиться к среде Delphi, но при понимании темы, думаем, не сложно повторить это в других средах и на других языках. Где искать такие функции? Можно конечно вооружившись дизассемблером исследовать ntdll.dll, но можно посетить, например сайт http://undocumented.ntinternals.net и разбираться уже в нём.
Пожалуй, начнём. Стартанём с довольно стандартной функции NtQuerySystemInformation. Название у неё довольно обманчивое, потому что с помощью неё можно получить не только доступ к системной информации, но и, например информацию о процессах и много чего ещё.
NtQuerySystemInformation( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, // Структура SYSTEM_INFORMATION_CLASS OUT PVOID SystemInformation, // Массив для получения информации IN ULONG SystemInformationLength, // Длина массива OUT PULONG ReturnLength OPTIONAL ); // Информация о выполнении функции
Пробуем вызвать эту функцию, но сталкиваемся с полным непониманием со стороны борландовского компилятора, что от него нужно. Просветить его можно только с помощью прямого вызова этой функции из ntdll.dll. Но перед этим, её нужно описать. Прототип есть, так что вперёд:
function NtQuerySystemInformation(infoClass: PSYSTEM_PROCESS_INFORMATION; buffer: Pointer; bufSize: DWORD; returnSize: Dword): DWORD; stdcall;external ntdll.dll
Теперь в заголовке пропишем строку "initialization" и после этого слова запишем следующий код:
var libvar:cardinal; …. initialization libvar:= LoadLibrary(NTDLL.DLL); // Загружаем библиотеку if libvar = 0 then // Если она не загрузилась, exit; //то выходим NtQuerySystemInformation:= GetProcAddress(libvar,NtQuerySystemInformation); // Загружаем функцию if @NtQuerySystemInformation <>nil then // Если не загрузилась, exit; // то выходим finalization FreeLibrary(libvar); // При выходе освобождаем память
Всё это было сделано для того, чтобы определить, можно загрузить данную функцию ещё до старта приложения. В противном случае сразу же выходим!
Функция, с которой мы будем работать, может принимать довольно много вариантов структур. Мы рассмотрим только несколько. А описание всех структур, конечно же, в msdn. Этой структурой будет SYSTEM_BASIC_INFORMATION. Её кстати тоже надо объявить прямо в коде и вызвать из ntdll.dll, ведь она также является недокументированной.
SYSTEM_BASIC_INFORMATION = packed record AlwaysZero: ULONG; // Всегда 0 MaximumIncrement: ULONG; // Часовые единицы измерения PageSize: ULONG; // Размер страницы памяти NumberOfPhysicalPages: ULONG; // Количество страниц памяти LowestPhysicalPage: ULONG; // Минимальное количество страниц HighestPhysicalPage: ULONG; // Максимальное количество страниц AllocationGranularity: ULONG; // Зарезервировано LowestUserAddress: POINTER;// Минимальное количество пользователей HighestUserAddress: POINTER; // Максимальное количество пользователей ActiveProcessors: POINTER; // Активные процессоры NumberProcessors: BYTE; // Количество процессоров Filler: array [0..2] of BYTE; end;
Теперь нам уже ничего не мешает вызвать эту функцию:
var status:longint; SysInf:TSystem_Basic_Information; begin status:= NtQuerySystemInformation(0, @SysInf,sizeof(SysInf),nil); if status <> 0 then exit; ShowMessage(IntToStr(SysInf.NumberProcessors)); end;
В этом примере мы получаем количество процессоров, которые присутствуют на машине. Сами же Майкрософт не рекомендуют использовать недокументированные функции и рядом с описанием NtQuerySystemInformation, расположилась обычная WinAPI GetSystemInfo. Конечно, в данном случае наиболее предпочтительнее вызывать более стандартный аналог, но что если, например, задачи нестандартные? Рассмотрим например структуру [http://undocumented.ntinternals.net/UserMode/UndocumentedFunctions/SystemInformation/Structures/
SYSTEM_PROCESS_INFORMATION.html|SYSTEM_PROCESS_INFORMATION], которая позволяет получить максимально доступную (на таком уровне) информацию о процессе. И теперь взглянем на стандартный прототип PROCESS_INFORMATION. Ну что, есть разница? А ведь в SPI это ещё не все значения.
Теперь перейдём к более наглядной демонстрации. Мы не будем снова описывать эту структуру, просто это итак подразумевается. Перейдём лучше сразу к вызову:
var SystemInfo, ProcessInfo: PSYSTEM_PROCESS_INFORMATION; ReturnLength: DWORD; ntst,status:Integer; begin ReturnLength := 0; ntst:= NtQuerySystemInformation(5, nil, 0, ReturnLength); if ntst = 0 then // Если функция равна нулю, exit; // то выход if ReturnLength > 0 then begin GetMem(SystemInfo,ReturnLength); // Выделяем память под структуру try NtQuerySystemInformation(SystemProcessesAndThreadsInformation,SystemInfo,ReturnLength, ReturnLength); // Снова вызываем функцию, надо для определения количества памяти ProcessInfo:= Systeminfo; repeat ProcessInfo :=Pointer(DWORD(ProcessInfo) + ProcessInfo.NextOffset); // Указатель на данные в памяти этой структуры ListBox1.Items.Add(ProcessInfo.ModuleName) // Результаты выводим например на ListBoix until ProcessInfo^.NextOffset = 0; // Крутим пока смещение не будет равно нулю finally FreeMem(SystemInfo); // Освобождаем память end; end; end;
Вот таким образом, можно получить максимально полную информацию о процессах. И напоследок приведём небольшой алгоритм работы с недокументированными функциями:
- Описать эту функцию с помощью LoadLibrary();
- Отключить нужную библиотеку;
- Через GetProcAddress получить адрес экспортируемой функции;
- Вызвать эту функцию и наслаждаться работой.
Удачи в работе с недокументированными функциями!