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