Оценка 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; } |
Оценка 122 Оценить ![]() ![]() ![]() ![]() ![]() ![]()
|