Сообщений 2 Оценка 122 Оценить |
Тестовое приложение NTTASK16
Тестовое приложение Process Viewer
Несмотря на то, что Windows NT является целиком 32-разрядной системой, она способна выполнять большинство 16-битных приложений, как приложений MS-DOS, так и 16-битных приложений для Windows 3.1. В Windows NT 3.5 и более ранних версиях, каждая 16-битная программа выполнялась в своей собственной виртуальной машине. Каждая виртуальная машина выглядела как относительно полная Windows 3.1-система, из-за чего эта технология получила название Windows On Windows (WOW). Деятельность каждой 16-битной программы была полностью отделена от других 16-битных программ. В результате, сбои в одной 16-битной программе никак не влияли на остальные программы в системе.
Начиная с версии 3.51, Windows NT приобрела возможность запускать несколько 16-битных программ в одной виртуальной машине, разделяя одно и тоже адресное пространство и таблицу локальных дескрипторов (LDT) между программами. В результате, как только загружена одна 16-битная программа, последующие 16-битные программы стартуют быстрее и используют меньше памяти. Обратная сторона медали состоит в том, что если одна из 16-битных программ фатально завершается, то вся виртуальная машина целиком перестает существовать. К счастью, возможность запускать 16-битные программы в отдельной виртуальной машине сохранилась.
Виртуальная DOS-машина реализована в Windows NT в виде Win32-процесса под названием NTVDM.EXE. Ecли не брать во внимание тот факт, что NTVDM использует значительное количество недокументированных функций из NTDLL.DLL, то в остальном это такой же процесс, как и другие Win32-процессы. Каждой исполняющейся 16-битной программе соответствует один поток в процессе NTVDM.
Windows NT предоставляет интерфейс для управления виртуальными машинами в составе библиотеки VDMDBG.DLL. В частности, для перечисления 16-битных задач служит функция VDMEnumTaskWOWEx:
INT WINAPI VDMEnumTaskWOWEx( IN DWORD dwProcessId, IN TASKENUMPROCEX pfnEnumProc, IN LPARAM lParam ); |
где
dwProcessId | Идентификатор процесса NTVDM.EXE. Как было отмечено, в системе может быть запущено несколько виртуальных машин одновременно. С помошью этого параметра мы указываем, 16-битные задачи какой из виртуальных машин мы хотим получить. |
pfnEnumProc | Адрес пользовательской функции, которая будет вызвана для каждой 16-битной задачи в рамках указанной виртуальной машины. |
lParam | Дополнительный пользовательский параметр, который без изменений передается в функцию, указанную параметром pfnEnumProc. |
Пользовательская функция, адрес которой передается в качестве параметра VDMEnumTaskWOWEx, должна соответствовать следующему прототипу:
typedef BOOL (CALLBACK * TASKENUMPROCEX)( IN DWORD dwThreadId, IN WORD hMod16, IN WORD hTask16, IN LPSTR pszModName, IN LPSTR pszFileName, IN LPARAM lParam ); |
В отличие от принятой в Win32 практики, пользовательская функция должна вернуть FALSE, чтобы продолжать перечисление, и TRUE - чтобы прервать перечисление. Параметрами функции являются:
dwThreadId | Указывает идентификатор Win32-потока в процессе NTVDM, который соответствует данной 16-битной задаче. |
hMod16 | Идентификатор 16-битного модуля, на основе которого была создана задача. |
hTask16 | Идентификатор 16-битной задачи. |
pszModName | Имя модуля, идентификатор которого был указан в параметре hMod16. Как правило, имя модуля совпадает с именем исполняемого файла без расширения, однако бывают и исключения. |
pszFileName | Полный путь к файлу, из которого был загружен исполняемый модуль задачи. |
lParam | Пользовательский параметр. |
Чтобы перечислить все 16-битные задачи в системе, мы должны каким-либо образом найти все виртуальные машины. С одной стороны, это можно сделать просто перечислив все 32-битные процессы, как это описано в статье Как получить список запущенных процессов?, и выбрать из них процессы с именем NTVDM.EXE. Тестовое приложение Process Viewer использует этот подход.
С другой стороны, можно воспользоваться функцией VDMEnumProcessWOW, которая специально предназначена для перечисления виртуальных машин WOW:
INT WINAPI VDMEnumProcessWOW( IN PROCESSENUMPROC pfnEnumProc, IN LPARAM lParam ); typedef BOOL (CALLBACK * PROCESSENUMPROC)( IN DWORD dwProcessId, IN DWORD dwAttrib, IN LPARAM lParam ); |
Здесь
pfnEnumProc | Адрес пользовательской функции, которая будет вызвана для каждого экземпляра виртуальной машины. |
lParam | Произвольный пользовательский параметр. |
dwProcessId | Идентификатор процесса виртуальной машины. |
dwAttrib | Атрибуты виртуальной машины. В настоящее время определен только один атрибут с именем WOW_SYSTEM, который говорит о том, что эта виртуальная машина является системной виртуальной машиной. Новые 16-битные задачи будут создаваться в этой виртуальной машине, если явно не указано иначе. |
В качестве иллюстрации использования функций VDMEnumTaskWOWEx и VDMEnumProcessWOW предлагается программа NTTASK16, полный текст которой приведен ниже.
#define STRICT #include <windows.h> #include <stdio.h> #include <vdmdbg.h> #pragma comment(lib, "vdmdbg.lib") BOOL CALLBACK TaskEnumProcEx( IN DWORD dwThreadId, IN WORD hMod16, IN WORD hTask16, IN LPSTR pszModName, IN LPSTR pszFileName, IN LPARAM lParam ) { printf("\tThread ID:\t%u (0x%X)\n", dwThreadId, dwThreadId); printf("\tModule handle:\t0x%04X\n", hMod16); printf("\tTask handle:\t0x%04X\n", hTask16); printf("\tModule Name:\t%s\n", pszModName); printf("\tFile Name:\t%s\n\n", pszFileName); return FALSE; } BOOL CALLBACK ProcessEnumProc( IN DWORD dwProcessId, IN DWORD dwAttrib, IN LPARAM lParam ) { printf("VDM Process ID: %u (0x%X)\n", dwProcessId, dwProcessId); printf("Attributes: 0x%08X\n", dwAttrib); VDMEnumTaskWOWEx(dwProcessId, TaskEnumProcEx, 0); return FALSE; } int main( int argc, char * argv[] ) { VDMEnumProcessWOW(ProcessEnumProc, 0); return 0; } |
Сообщений 2 Оценка 122 Оценить |