Гипервизор над нуль-API бот-процессом (Windows XP IA-32 / Wi
От: Vertecs Узбекистан  
Дата: 24.11.19 22:19
Оценка:
Здравствуйтe!

Общая концепция
(Идея появилась ещё в 90-е, когда я только ознакомился с возможностями защищённого уровня и виртуализации процессора i386, но работал под DOS. В общем, идея стара, но взяться за её практическую реализацию я решился лишь сейчас чисто ради исследовательского интереса…)
  1. Необходимо запустить несколько десятков/сотен «бот-процессов», которые никак не делят своё адресное пространство с системой и не имеют доступа к какому-либо API, так как в своё распоряжение должны получать все 4 Гб адресного пространства (не памяти)
  2. Фактически каждый процесс имеет изначально 64 Кб памяти, которая зеркалами размазывается и повторяется по всему периоду в 4 Гб через предустановку селекторов сегментных регистров «cs/ds/es/fs/gs/ss», чтобы эти 64 Кб повторились 65536 раз от 0x0000???? до 0xFFFF????, чем достигается предотвращение любых исключений, связанных с доступом к памяти
  3. Инструкции математического сопроцессора с ESCAPE-набором полностью должны быть исключены и генерировать исключение в любом случае, чтобы симулировать гипотетический периферийный сопроцессор для управления сетевым обменом, регионами памяти и портами ввода/вывода
  4. Так как инструкции процессора «in/out» / «ins/outs» / «lock/hlt» / «cli/sti» являются привилегированными и генерируют в прикладных задачах исключение, посредством финального обработчика исключений планируется переквалифицировать их назначение
  5. Инструкции «in/out» будут представлять каналы обмена между этими процессами, будто отдельный процесс сам по-себе — это порт ввода/вывода.
  6. Если процесс №38 пытается читать порт №67, текущий процесс приостанавливается на неопределённый промежуток времени, а вместо него загружается/запускается/возобновляется процесс №67, который должен сгенерировать некие данные и прерваться командой «hlt», после чего он приостанавливается и работа процесса №38 возобновляется со значением регистра EAX из процесса №67
  7. Инструкции «cli/sti» будут экранировать участки кода как «begin/end» для их внедрения в соседний процесс, чтобы фрагмент экранируемого кода инжектировался в целевой код и запускался при исключении через комбинацию «lock+hlt», что позволит соседним процессом не только обмениваться данными через фиктивную карту портов ввода/вывода, но и инжектировать любые фрагменты кода друг в друга
  8. Таблицу векторов программных прерываний «int 0…255» стоит организовать таким образом, чтобы абсолютно всегда генерировать исключение тоже

Условия
Говоря проще, все «in/out» / «cli/sti» / «int/hlt» / «rep+ins/outs» / «esc-набор» будут проходить через мой обработчик исключений и интерпретироваться в рамках поставленной задачи. Скорость мне не нужна (пока) и на тестах задержки достигали до 25 млн тиков на одной только «lock+ins» инструкции, причём с файлами и потоками я ещё не начинал работать. Что меня вполне устраивает, так как важна не производительность, а детальное построение графов взаимодействиях всех «ботов» с экспортом в SVG…

Практика
Я убедился, что попытка доступа к любому из 65536 портов гарантированно приводит к исключению. Но вот не все индексы «int»-прерываний выпадают в мою ловушку и с этим ещё нужно разбираться…
А так как API функция CreateProcess слишком комплексная и выполняет все 4 действия автоматически, пришлось воспользоваться ресурсами ядра через функции NtOpenFile/NtCreateSection/NtMapViewOfSection/NtCreateProcess.

Если Вы условную концепцию поставленной мной задачи могли воспринять без стереотипов, то смогли уже догадаться, что я хочу организовать некую сеть процессов на неких виртуальных псевдо-машинах, где не нужна аппаратная PC-периферия в портах ввода/вывода и не нужно никакого системного API. Получается некий условный «клеточный автомат», где в качестве «живых единиц» выступает x86-код из грубого генератора случайных чисел.
Случайным образом генерируется x86-код в количестве сотен/тысяч файлов и регистры EIP/ESP устанавливаются случайным образом перед запуском процесса. А так как все 4 Гб пространства — это повторяющиеся 64 Кб кода, то абсолютно не важно, где и как тот код будет читать/писать память.
Лишь только Escape-инструкции «FPU» нужно перехватывать и все остальные из набора «in/out» / «int/hlt» и т.д…
Никакого низкоуровневого доступа к реальным портам ввода/вывода процессора мне получать не нужно, так как роль портов ввода/вывода и периферии выполняют сами подгружаемые «бот-единицы»…
(Извиняюсь за повтор и излишнюю детализацию, но опыт из других форумов показывает, что конкретно эту мою задачу необходимо занудно повторениями детально прояснять!)

Опыт
На данный момент удалось продвинуться не так далеко.
    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:hFile\r\n", Error, hFile);        // Здесь EAX возвращает 0 и в hFile загружается дескриптор файла.
    Error = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, NULL, PAGE_EXECUTE_READWRITE, SEC_IMAGE, hFile);
    printf("%08X %08X:hSection\r\n", Error, hSection);    // Здесь уже возвращается код 0xC0000022 и я не понимаю, почему...
    // Соответственно, дальше происходит исключение, предупреждение и закрытие всей программы
    Error = NtMapViewOfSection(hSection, (void *)-1, &ImageBaseAddr, NULL, &ViewSize, 0, PAGE_EXECUTE_READWRITE, NULL, 0);
    printf("%08X %08X:ImageBaseAddr\r\n", Error, ImageBaseAddr);
    Error = NtCreateProcess(&hProcess, PROCESS_ALL_ACCESS, NULL, (void *)-1, PROCESS_CREATE_FLAGS_BREAKAWAY, hSection, NULL, NULL);
    printf("%08X %08X:hProcess\r\n", Error, hProcess);

Программу пишу в Visual Studio 6 на Windows'XP под VMware, сразу запуская на гостевой машине (Win'XP) и на хосте — Windows'8.1, но вижу абсолютно одинаковый результат.

Наверное, следует переписать этот код несколько иначе.

Что я делаю не так на данном этапе?

P.S.: Спасибо!
Отредактировано 24.11.2019 22:34 Alikberov . Предыдущая версия .
winapi escape exception port kernel x86 x86-32 Visual Studio FPU IA32 Windows XP Windows 8
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.