#windows #system-calls
#Windows #системные вызовы
Вопрос:
Одинаковые значения идентификаторов системных вызовов в разных версиях ОС отвечают за вызов разных функций ядра. Итак, когда мы используем исполняемый файл, который использовался в эпоху Windows XP в Windows 7, почему все приложение работает правильно?
Комментарии:
1. Приложения, использующие NT API, не выполняют прямые системные вызовы. Они ссылаются на функцию-заглушку в системной библиотеке, которая, в свою очередь, выполняет системный вызов, такой как
Nt
функции с префиксами, экспортируемые ntdll.dll и функции с префиксамиNtUser
иNtGdi
, экспортируемые win32u.dll (ранее user32.dll ). Существуют эквивалентные экспорта сZw
префиксами, но в пользовательском режиме между ними нет разницы, и предпочтительнее использоватьNt
имена.2. Тем не менее, если у приложения нет веской причины (например, это служба пользовательского режима, которая тесно связана с драйвером), я думаю, что она должна предпочесть Windows API низкоуровневым системным вызовам. IMO, если
CreateFileW
выполняет эту работу, то используйте ее. ИспользуйтеNtCreateFile
илиNtOpenFile
только в том случае, если это абсолютно необходимо.
Ответ №1:
Windows предоставляет большой набор DLL, некоторые из которых действуют как тонкие (или иногда не очень тонкие) оболочки вокруг системных вызовов.
Когда идентификаторы системных вызовов меняются между разными версиями Windows, меняются и эти библиотеки DLL.
Но вы импортируете, например, CloseHandle()
из kernel32.dll
по его имени, и поэтому вы не видите изменений, и все просто работает (то есть, если мы не учитываем ошибки и исправления ошибок, которые изменяют поведение, от которого может зависеть ваша программа).
Комментарии:
1.
CloseHandle
это вызов WINAPI, а не системный вызов. Он реализует дополнительное поведение, такое как поддержка стандартных псевдообработчиков ввода-вывода, таких какSTD_INPUT_HANDLE
, для которых он дополнительно очищает дескриптор процессаStandardInput
в параметрах процесса PEB, а затем закрывает дескриптор реального файла с помощьюNtClose
системного вызова. Это такие вызовы,NtClose
о которых говорит OP. Например, в x64NtClose
функция-заглушка в ntdll.dll перемещает значение дескриптора в регистр r10; загружает номер системного вызова в регистр rax; и выдаетsyscall
инструкцию для переключения в режим ядра.2. @eryksun Вы упомянули более прямой пример, но не другой механизм.
3. В XP идентификатор 0x11B9 отвечает за вызов функции NtGdiFullscreenControl, но в Windows 7 он отвечает за вызов функции NtGdiDdUpdateOverlay. Вы имеете в виду, что оба они имеют одинаковую функциональность, хотя и имеют разные имена? Я правильно понимаю?
4. @Farshid, нет, когда мы вызываем
NtGdiFullscreenControl
в пользовательском режиме, мы вызываем функцию-заглушку, которая скомпилирована с номером системного вызова для этой функции в данной версии Windows, которая варьируется. Как только мы переходим в режим ядра черезsyscall
(или черезint 0x2E
в 32-разрядной сборке Windows x86),NtGdiFullscreenControl
функция ядра ищется в таблице системных вызовов — в данном случае в расширенной таблице, которая имеет win32k.sys функции.5. @eryksun, я исследовал исполняемый файл с использованием Ollydbg. Вместо имени отображается идентификатор функции. независимо от версии ОС, этот идентификатор всегда остается фиксированным. Поскольку программа была скомпилирована один раз, а затем использовалась в каждой версии ОС, как можно изменить функциональность функции во время выполнения? В другом выражении, когда элемент управления выполняет команду MOV EAX, 11B9, а затем переключается в режим ядра с помощью MOV EDX, 7FFE0300 и ВЫЗЫВАЕТ DWORD PTR DS:[EDX], как это определяется и какая из функций NtGdiFullscreenControl или NtGdiDdUpdateOverlay должна быть заменена?