Разные идентификаторы системных вызовов отвечают за вызов разных функций в разных версиях ОС

#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. Например, в x64 NtClose функция-заглушка в 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 должна быть заменена?