Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Виртуальная ферма x86-ботов

15K
26 ноября 2019 года
Vertecs
116 / / 21.06.2008
Возниклa необходимость в написании собственного супервизора, который будет оболочкой для запуска колонии «бот-процессов» с хаотическим машинным кодом…
Готовые эмуляторы Bochs/QEmu для этих целей никак не подходят, так как я уже писал 12 лет назад подобный усечённый эмулятор.
А так как, начиная уже с i386, у процессоров имеется вся необходимая встроенная аппаратная поддержка полной виртуализации, то хотелось бы просто обойтись собственным гипервизором, вместо полной эмуляции каждой команды.

Прикладнaя API-функция CreateProcess достаточно сложная и выполняет четыре действия автоматически и без возможности опционального контроля:
  1. Создать адресное пространство процесса (размером 4Gb)
  2. Резервировать в адресном пространстве процесса регион размером, достаточным для размещения исполняемого файла. Начальный адрес региона определяется в заголовке EXE-модуля. Обычно он равен 0x00400000, но может быть изменен при построении файла параметром /BASE компоновщика.
  3. Отобразить исполняемый файл на зарезервированное адресное пространство. Тем самым VMM распределяет физические страницы не из файла подкачки, а непосредственно из EXE-модуля.
  4. Таким же образом отобразить на адресное пространство процесса необходимые ему динамически связываемые библиотеки. Информация о необходимых библиотеках находится в заголовке EXE-модуля. Желательное расположение региона адресов описано внутри библиотеки. Visual C++, например, устанавливает по умолчанию адрес 0x10000000. Этот адрес может так же изменяться параметром /BASE компоновщика. Если при загрузке выясняется, что данный регион занят, то система попытается переместить библиотеку в другой регион адресов, на основе настроечной информации, содержащейся в DLL-модуле. Однако эта операция снижает эффективность системы и, кроме того, если настроечная информация удалена при компоновке библиотеки параметром /FIXED, то загрузка становится вообще невозможной.
Для решения моей задачи мне необходимо самому запросить систему создать для меня дополнительное адресное пространство в 4 Гб, но не проецировать туда саму оперативную память.
По-видимому, для этого нужно вызвать функцию NtSetLdtEntries/ZwSetLdtEntries и подготовить таблицу селекторов сегментов соответствующим образом.
(В документациях говорится, что начиная с процессора i386 можно настроить таблицу 1024 селекторов ссылками на 1024 сегмента по 4096 байта каждый и создать виртуальное адресное пространство в 4 Гб. При этом можно переназначать сегменты так, чтобы они в адресном пространстве могли повторяться несколько раз в разных местах или располагались нелинейно.)

Затем мне необходимо создать некий «бот-процесс»…
Под новый «бот-процесс» необходимо через системные функции ядра в адресном пространстве создать 65536 зеркал на один регион памяти в 64 Кб, чтобы на протяжении всего 32-битного пространства повторялся 16-битный регион ОЗУ.
В моём случае, мне не нужно резервировать в адресном пространстве создаваемого «бот-процесса» регион под системное API и необходимости в верхних 2 Гб под системное API в «бот-процессе» у меня нет, так как вызовов API-функций «бот-процесс» совершать не должен: Все 4 Гб должны быть одним регионом 64 Кб, повторяющимся на всём протяжении.
То есть, созданный «бот-процесс» должен работать «в собственном соку» и никак не взаимодействовать с системой, так как любое чтение памяти и её перезапись будет в инкапсуляции модифицировать всё тот же регион 64 Кб самого «бот-процесса»…

Также, через биты регистра CR0 необходимо исключить FPU-функционал Escape-инструкций у «бот-процесса», чтобы никаких операций вещественной арифметики он не совершал…

Естественно, обращение к портам ввода/вывода также не должно никак эмулироваться или симулироваться, а просто генерировать исключение для моего сборщика статистики.

Как результат, с помощью моего гипервизора я должен просто следить за работой «бот-процесса» и обрабатывать любые исключения самостоятельно…

Мною уже построен обработчик SEH, который перехватывает исключения локального «бота», который я встроил инлайн-вставками «asm { … … }» прямо в саму оболочку.
Но мне нужно, как уже можете понимать, просто создавать сотни виртуальных пространств в 4 Гб и загружать в них сотни «ботов», а затем просто собирать статистику…

На данный момент я попытался построить оболочку функциями пришлось воспользоваться ресурсами ядра через функции NtOpenFile/NtCreateSection/NtMapViewOfSection/NtCreateProcess.
Код:
OBJECT_ATTRIBUTES ObjAttr;
    IO_STATUS_BLOCK StatusBlock;
    HANDLE  hSection;
    HANDLE  hProcess;
    PVOID   ImageBaseAddr;
    SIZE_T  ViewSize;
    HANDLE  hFile;
    OBJECT_ATTRIBUTES ofs;
    UNICODE_STRING dn;
    IO_STATUS_BLOCK State;
    DWORD   Error;
    //
    ZeroMemory(&State,sizeof(IO_STATUS_BLOCK));
    WCHAR   *ch1 = L"\??\C:\the_bot.x86";       // В этом файле случайный мусор
    RtlInitUnicodeString(&dn, ch1);
    InitializeObjectAttributes(&ofs, &dn, 0, 0, 0);
    // Начинаю сложный (для меня) процесс работы с функциями ядра
    Error = NtCreateFile(&hFile,GENERIC_WRITE|GENERIC_READ,&ofs, &State,0,FILE_ATTRIBUTE_NORMAL,0,0/*FILE_SUPERSEDE*/,0,0,0);
    printf("%08X %08X:hFilern", Error, hFile);      // Здесь EAX возвращает 0 и в hFile загружается дескриптор файла.
    Error = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, NULL, PAGE_EXECUTE_READWRITE, SEC_IMAGE, hFile);
    printf("%08X %08X:hSectionrn", Error, hSection);    // Здесь уже возвращается код 0xC0000022 и я не понимаю, почему...
    // Соответственно, дальше происходит исключение, предупреждение и закрытие всей программы
    Error = NtMapViewOfSection(hSection, (void *)-1, &ImageBaseAddr, NULL, &ViewSize, 0, PAGE_EXECUTE_READWRITE, NULL, 0);
    printf("%08X %08X:ImageBaseAddrrn", Error, ImageBaseAddr);
    Error = NtCreateProcess(&hProcess, PROCESS_ALL_ACCESS, NULL, (void *)-1, PROCESS_CREATE_FLAGS_BREAKAWAY, hSection, NULL, NULL);
    printf("%08X %08X:hProcessrn", Error, hProcess);
Программу пишу в Visual Studio 6 на Windows'XP под VMware, сразу запуская на гостевой машине (Win'XP) и на хосте - Windows'8.1, но вижу абсолютно одинаковый результат. Но, кажется, нужно подходить с другого конца и сначала подготовить сегментными селекторами 4 Гб с гранулярностью по 64 Кб, а затем открывать туда проекцию процесса.

В сети готовых примеров, отдалённо напоминающих искомое, нету. Кроме, например, KlbrInWin-исходников, для запуска KolibriOS-приложений под Windows.

P.S.: В моей оболочке должно запускать одновременно до нескольких сотен подобных «бот-процессов», машинный код которых будет генерироваться генератором случайных чисел, так как мне нужно собрать статистическую картину генерируемых ими исключений…

Спасибо!
260
28 ноября 2019 года
Ramon
1.1K / / 16.08.2003
Боюсь, что уважаемая аудитория ничего из ваших объяснений не поняла.

PS: А пенсионеры добавят, что x86 не соответствует Критериям виртуализации Попека и Голдберга в принципе, и никакой поддержки "полной виртуализации" в i386 так же нет, да и какие то мутные игры с виртуальной памятью гипервизором не являются.
15K
28 ноября 2019 года
Vertecs
116 / / 21.06.2008
Цитата: Ramon
Боюсь, что уважаемая аудитория ничего из ваших объяснений не поняла.

Этo я уже понял…

Цитата: Ramon
PS: А пенсионеры добавят, что x86 не соответствует Критериям виртуализации Попека и Голдберга в принципе, и никакой поддержки "полной виртуализации" в i386 так же нет, да и какие то мутные игры с виртуальной памятью гипервизором не являются.

Спасибо!
Однако, ещё 17 лет назад прорывом было запуск Linux и Windows одновременно на одном хосте - VMware ESX.
По телеканалу Rambler-TV тогда впервые это увидел.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог