GRAFik Не удивительно, андроид же, там все кривое, пакеры значит не исключение) ориг архив Выбрал по системке что посложнее, тривиальную рутину оно без проблем разбирает.
Ну,ну. Вот вам тривиальный вопрос для школьника 2-го класса церковно-приходской школы: Напиши код на MASM64 прстого окна с двумя кнопками, при нажатии на которые вызываются сообщения MesaggeBox. Укажи команды для компиляции в Visual Studio 2022 (bat-файл). Уверяю вас, пол дня потратите, а то и день, на написание подробных и понятных промтов - ТОЛЬКО РАБОЧЕГО ВАРИАНТА ВЫ НЕ ПОЛУЧИТЕ!
GRAFik Он не знает всех подробностей для написания, нужно помогать. Вот пример сборки кода выше. По дефолту он не умеет компилировать(не может просчитать размеры смещений ветвлений, BDO), потому нужно подсказать как это делать: - ход сборки. Без помощи он ничего не собирает.
А, ну теперь я всё понял. Нужно все делать самому, но делать вид, что за тебя это делает Иван Иваныч (ИИ). Я прав или не совсем?
Чето не может он нифига. Код (Text): Создание полноценной операционной системы с браузером и интернетом — это сложнейшая задача, которая требует многолетней работы команды разработчиков. Однако я могу показать вам концептуальный пример минимальной загрузочной системы на MASM с простым калькулятором. Вот пример загрузочной системы с калькулятором (работает в реальном режиме x86): ```assembly ; boot.asm - Минимальная загрузочная ОС с калькулятором ; Сборка: ml /c /coff boot.asm ; Линковка: link /SUBSYSTEM:NATIVE /ALIGN:16 /DRIVER boot.obj .586p .MODEL TINY .CODE ORG 7C00h start: cli xor ax, ax mov ds, ax mov es, ax mov ss, ax mov sp, 7C00h sti ; Очистка экрана mov ax, 0003h int 10h ; Вывод приветствия mov si, offset msg_welcome call print_string main_loop: ; Вывод промпта mov si, offset prompt call print_string ; Чтение ввода mov di, offset buffer call read_string ; Обработка команды call process_command jmp main_loop ; Процедура обработки команд process_command proc mov si, offset buffer cmp byte ptr [si], 0 je empty_cmd ; Проверка на команду выхода mov cx, 4 mov di, offset cmd_exit repe cmpsb je exit_cmd ; Проверка на команду calc mov si, offset buffer mov cx, 4 mov di, offset cmd_calc repe cmpsb je calc_cmd ; Неизвестная команда mov si, offset msg_unknown call print_string ret empty_cmd: ret exit_cmd: mov si, offset msg_reboot call print_string xor ax, ax int 16h int 19h calc_cmd: call calculator ret process_command endp ; Простой калькулятор calculator proc mov si, offset msg_calc call print_string ; Чтение первого числа mov di, offset num1_str call read_string call string_to_int mov [num1], ax ; Чтение оператора mov si, offset msg_operator call print_string mov ah, 00h int 16h mov [operator], al mov ah, 0Eh int 10h ; Чтение второго числа mov si, offset msg_newline call print_string mov di, offset num2_str call read_string call string_to_int mov [num2], ax ; Выполнение операции mov ax, [num1] mov bx, [num2] mov cl, [operator] cmp cl, '+' je calc_add cmp cl, '-' je calc_sub cmp cl, '*' je calc_mul cmp cl, '/' je calc_div mov si, offset msg_invalid_op call print_string ret calc_add: add ax, bx jmp show_result calc_sub: sub ax, bx jmp show_result calc_mul: imul bx jmp show_result calc_div: xor dx, dx div bx jmp show_result show_result: mov [result], ax mov si, offset msg_result call print_string ; Преобразование результата в строку mov ax, [result] mov di, offset result_str call int_to_string mov si, di call print_string mov si, offset msg_newline call print_string ret calculator endp ; Вспомогательные процедуры print_string proc lodsb test al, al jz print_done mov ah, 0Eh int 10h jmp print_string print_done: ret print_string endp read_string proc xor cx, cx read_char: mov ah, 00h int 16h cmp al, 0Dh je enter_pressed cmp al, 08h je backspace mov [di], al inc di inc cx mov ah, 0Eh int 10h jmp read_char backspace: cmp cx, 0 je read_char dec di dec cx mov al, 08h mov ah, 0Eh int 10h mov al, ' ' int 10h mov al, 08h int 10h jmp read_char enter_pressed: mov byte ptr [di], 0 mov al, 0Dh mov ah, 0Eh int 10h mov al, 0Ah int 10h ret read_string endp string_to_int proc xor ax, ax xor bx, bx convert_loop: mov bl, [si] cmp bl, 0 je convert_done sub bl, '0' imul ax, 10 add ax, bx inc si jmp convert_loop convert_done: ret string_to_int endp int_to_string proc pusha mov cx, 10 xor bx, bx div_loop: xor dx, dx div cx add dl, '0' push dx inc bx test ax, ax jnz div_loop mov cx, bx pop_loop: pop ax stosb loop pop_loop mov byte ptr [di], 0 popa ret int_to_string endp ; Данные msg_welcome db 'MiniOS v0.1', 0Dh, 0Ah db 'Commands: calc, exit', 0Dh, 0Ah, 0 prompt db '> ', 0 msg_unknown db 'Unknown command', 0Dh, 0Ah, 0 msg_reboot db 'Press any key to reboot...', 0Dh, 0Ah, 0 msg_calc db 'Calculator:', 0Dh, 0Ah, 'Enter first number: ', 0 msg_operator db 0Dh, 0Ah, 'Enter operator (+, -, *, /): ', 0 msg_newline db 0Dh, 0Ah, 0 msg_result db 0Dh, 0Ah, 'Result: ', 0 msg_invalid_op db 'Invalid operator', 0Dh, 0Ah, 0 cmd_exit db 'exit', 0 cmd_calc db 'calc', 0 buffer db 64 dup(0) num1_str db 16 dup(0) num2_str db 16 dup(0) result_str db 16 dup(0) num1 dw 0 num2 dw 0 result dw 0 operator db 0 ; Загрузочная сигнатура ORG 7DFEh dw 0AA55h END start ``` Что делает этот код: 1. Минимальная загрузочная ОС — запускается с флешки/диска 2. Простой калькулятор — поддерживает +, -, *, / 3. Интерфейс командной строки — базовый ввод/вывод Для создания браузера и интернета потребуется: 1. Защищённый режим — переход в 32/64-битный режим 2. Управление памятью — менеджер памяти, виртуальная память 3. Файловую систему — хотя бы FAT32 4. Сетевой стек — драйвер сетевой карты, TCP/IP стек 5. Графический интерфейс — VGA/SVGA драйвер 6. Парсинг HTML — минимум 50 000 строк кода Практические шаги для развития: 1. Изучите: · "Operating Systems: Three Easy Pieces" · "Intel® 64 and IA-32 Architectures Software Developer Manuals" 2. Начните с: · Перехода в защищённый режим · Реализации FAT32 драйвера · Создания простого графического интерфейса 3. Используйте готовые компоненты: · MenuetOS (написана на ассемблере) · SerenityOS (C++, но открытая архитектура) Хотите, покажу как: 1. Добавить в эту систему простой текстовый редактор? 2. Реализовать базовую файловую систему? 3. Перейти в защищённый режим для доступа к 4 ГБ памяти?
Если это "камешек в мой огород" и намек на то, что я не умею составить какой-нибудь более-менее вменяемый промт для ИИ - ошибаетесь. --- Сообщение объединено, 1 дек 2025 --- Вы хотите сказать, что составили правильный и грамотный промт(запрос) для ИИ и он вам выдал код, который компилируется и работает? НЕ ВЕРЮ!!! ПРУФЫ В СТУДИЮ !!! Скинте копию вашего промта (запроса/вопроса) для ИИ. И копию рабочего кода, который вам выдал ИИ. Если мне потом, после вашего промта(запроса) - ИИ выдаст что-то похожее, тогда я может и поверю вам. А сейчас извините - нет доказательств. И потом - разговор ведь был про MASM64. Но можно и с MASM32 начать. А там видно будет. --- Сообщение объединено, 1 дек 2025 --- P.S. И пожалуйста без этих ваших штучек, то архив не открывается, то разместили вы его где-то на закрытом сайте Пентагона, к которому ни у кого нет доступа.
Код (Text): ; ----------------------------------------------------------------------------------------------------------------------- ; Инклюды и библиотеки ; Этот код требует установки MASM32 SDK (или аналогичного) для инклуд-файлов и библиотек. ; ----------------------------------------------------------------------------------------------------------------------- include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib ; ----------------------------------------------------------------------------------------------------------------------- ; Константы и Идентификаторы ; ----------------------------------------------------------------------------------------------------------------------- .const ID_BUTTON_1 equ 1000 ; Идентификатор для первой кнопки ID_BUTTON_2 equ 1001 ; Идентификатор для второй кнопки WIN_TITLE db "MASM64 Пример с Кнопками", 0 CLASS_NAME db "MASM64WindowClass", 0 BUTTON_TEXT_1 db "Нажми меня (1)", 0 BUTTON_TEXT_2 db "Нажми меня (2)", 0 MSG_CAPTION_1 db "Сообщение Кнопки 1", 0 MSG_CAPTION_2 db "Сообщение Кнопки 2", 0 MSG_TEXT_1 db "Вы нажали кнопку 1!", 0 MSG_TEXT_2 db "Вы нажали кнопку 2!", 0 ; ----------------------------------------------------------------------------------------------------------------------- ; Глобальные переменные ; ----------------------------------------------------------------------------------------------------------------------- .data hInstance dq ? ; Дескриптор экземпляра hWnd dq ? ; Дескриптор главного окна wcex WNDCLASSEX <> ; Структура класса окна msg MSG <> ; Структура сообщения ; ----------------------------------------------------------------------------------------------------------------------- ; Прототипы функций ; ----------------------------------------------------------------------------------------------------------------------- WinMain proto :QWORD, :QWORD, :QWORD, :QWORD WindowProc proto :QWORD, :QWORD, :QWORD, :QWORD ; ----------------------------------------------------------------------------------------------------------------------- .code ; ----------------------------------------------------------------------------------------------------------------------- ; Точка входа в программу (аналог WinMain) ; ----------------------------------------------------------------------------------------------------------------------- start: ; Вызов WinMain (в MASM64 он вызывается напрямую) invoke WinMain, 0, 0, 0, SW_SHOWNORMAL invoke ExitProcess, rax ; Выход из программы ; ----------------------------------------------------------------------------------------------------------------------- ; Функция WinMain ; ----------------------------------------------------------------------------------------------------------------------- WinMain proc hInst:QWORD, hPrevInst:QWORD, CmdLine:QWORD, CmdShow:QWORD ; 1. Получение дескриптора экземпляра (hInst) invoke GetModuleHandle, NULL mov [hInstance], rax ; 2. Регистрация класса окна ; Заполнение структуры WNDCLASSEX mov [wcex.cbSize], SizeOf WNDCLASSEX mov [wcex.style], CS_HREDRAW | CS_VREDRAW mov [wcex.lpfnWndProc], OFFSET WindowProc ; Указатель на обработчик mov [wcex.cbClsExtra], 0 mov [wcex.cbWndExtra], 0 mov rax, [hInstance] mov [wcex.hInstance], rax invoke LoadIcon, NULL, IDI_APPLICATION mov [wcex.hIcon], rax mov [wcex.hIconSm], rax invoke LoadCursor, NULL, IDC_ARROW mov [wcex.hCursor], rax mov [wcex.hbrBackground], COLOR_WINDOW + 1 mov [wcex.lpszMenuName], NULL mov [wcex.lpszClassName], OFFSET CLASS_NAME ; Регистрация invoke RegisterClassEx, ADDR wcex cmp rax, 0 jz Exit_Error ; Если регистрация не удалась ; 3. Создание главного окна invoke CreateWindowEx, \ 0, \ ADDR CLASS_NAME, \ ADDR WIN_TITLE, \ WS_OVERLAPPEDWINDOW, \ 100, \ 100, \ 400, \ 200, \ NULL, \ NULL, \ [hInstance], \ NULL mov [hWnd], rax cmp rax, 0 jz Exit_Error ; Если создание не удалось ; 4. Создание кнопок ; Кнопка 1 invoke CreateWindowEx, \ 0, \ ADDR "Button", \ ADDR BUTTON_TEXT_1, \ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, \ 50, \ 50, \ 120, \ 30, \ [hWnd], \ ID_BUTTON_1, \ [hInstance], \ NULL ; Кнопка 2 invoke CreateWindowEx, \ 0, \ ADDR "Button", \ ADDR BUTTON_TEXT_2, \ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, \ 220, \ 50, \ 120, \ 30, \ [hWnd], \ ID_BUTTON_2, \ [hInstance], \ NULL ; 5. Отображение окна invoke ShowWindow, [hWnd], CmdShow invoke UpdateWindow, [hWnd] ; 6. Оконный цикл сообщений (Message Loop) Message_Loop: invoke GetMessage, ADDR msg, NULL, 0, 0 cmp rax, 0 je Quit_App invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg jmp Message_Loop Quit_App: ; Возвращение значения WM_QUIT mov rax, [msg.wParam] ret Exit_Error: xor rax, rax ; Возврат 0 в случае ошибки ret WinMain endp ; ----------------------------------------------------------------------------------------------------------------------- ; Процедура окна (Обработчик сообщений) ; ----------------------------------------------------------------------------------------------------------------------- WindowProc proc hWnd_p:QWORD, uMsg:QWORD, wParam:QWORD, lParam:QWORD ; Обработка сообщений cmp uMsg, WM_COMMAND je Handle_Command cmp uMsg, WM_DESTROY je Handle_Destroy ; Сообщения по умолчанию invoke DefWindowProc, hWnd_p, uMsg, wParam, lParam ret ; --- Обработка WM_COMMAND --- Handle_Command: mov rax, wParam and rax, 0FFFFh ; Получаем идентификатор элемента управления (LOWORD(wParam)) cmp rax, ID_BUTTON_1 je Button1_Click cmp rax, ID_BUTTON_2 je Button2_Click jmp Command_Default Button1_Click: ; Вызов MessageBox для Кнопки 1 invoke MessageBox, hWnd_p, ADDR MSG_TEXT_1, ADDR MSG_CAPTION_1, MB_OK | MB_ICONINFORMATION jmp Command_Default Button2_Click: ; Вызов MessageBox для Кнопки 2 invoke MessageBox, hWnd_p, ADDR MSG_TEXT_2, ADDR MSG_CAPTION_2, MB_OK | MB_ICONWARNING jmp Command_Default Command_Default: xor rax, rax ; Возврат 0 ret ; --- Обработка WM_DESTROY --- Handle_Destroy: invoke PostQuitMessage, 0 xor rax, rax ; Возврат 0 ret WindowProc endp end start --- Сообщение объединено, 1 дек 2025 --- - сборка шелла. Если повозиться в принципе можно и пе собрать..
@Ahimov, а в bat-файле в ключе /entry: что прописывать /entry: start или /entry:WinMain ? По-моему, нужно писать /entry:start Ну, думаю, спрошу на всякий случай.
Код (Text): ; proc FindProcAddress (BaseAddress: QWORD, FunctionName: QWORD) ; Вход: RBP = Базовый адрес модуля (BaseAddress) ; RDI = Указатель на имя функции (FunctionName) ; Выход: RAX = Адрес функции (или 0 в случае ошибки) FindProcAddress PROC ; Сохраняем нелетучие регистры, используемые в процедуре push rbx push rsi push rdi ; ------------------------------------------------------------------ ; 1. Находим IMAGE_EXPORT_DIRECTORY (Директорию Экспорта) ; ------------------------------------------------------------------ ; RAX = RBP (Базовый адрес модуля) mov rax, rbp ; RAX = Базовый адрес + RVA NT Headers ; NT Header находится по смещению [BaseAddress + [BaseAddress + 3Ch] ] movsx ebx, word ptr [rax + 3Ch] ; EBX = RVA E_LFANEW (Указатель на NT Headers) add rax, rbx ; RAX = Адрес NT Headers ; RAX = Адрес NT Headers + 8 (Пропуск Signature и FileHeader) ; RAX = Указатель на IMAGE_OPTIONAL_HEADER add rax, 18h ; RAX = Адрес начала Data Directories (постоянное смещение) add rax, 70h ; RAX = Адрес Data Directory [0] (Export Table) ; RBX = RVA Export Directory mov ebx, dword ptr [rax] ; EBX = RVA Export Table (Export Directory) ; Если EBX = 0, нет экспорта - ошибка test ebx, ebx jz .ExitError ; RAX = Адрес Export Directory mov rax, rbp add rax, rbx ; RAX = BaseAddress + RVA_ExportTable mov rsi, rax ; RSI = Указатель на IMAGE_EXPORT_DIRECTORY ; ------------------------------------------------------------------ ; 2. Определяем смещения к массивам ; ------------------------------------------------------------------ ; RBX = AddressOfNames (RVA) mov ebx, dword ptr [rsi + 20h] mov rbx, rbp add rbx, [rsi + 20h] ; RBX = Указатель на массив RVA имен (AddressOfNames) ; R8 = AddressOfNameOrdinals (RVA) mov r8, rbp add r8, [rsi + 24h] ; R8 = Указатель на массив Ordinals ; R9 = AddressOfFunctions (RVA) mov r9, rbp add r9, [rsi + 1Ch] ; R9 = Указатель на массив RVA функций ; RCX = NumberOfNames mov ecx, dword ptr [rsi + 18h] ; RCX = Количество экспортируемых имен ; ------------------------------------------------------------------ ; 3. Цикл поиска по имени ; ------------------------------------------------------------------ .NameLoop: ; Проверка конца списка test rcx, rcx jz .ExitError dec rcx ; Уменьшаем счетчик ; RAX = Указатель на текущее имя функции mov eax, dword ptr [rbx] ; RAX = RVA текущего имени add rax, rbp ; RAX = Указатель на строку имени ; Сравнение строк (RDI = искомое имя, RAX = текущее имя) ; Note: Реальная функция сравнения (strcmp) здесь не показана, ; т.к. она требует сложного кода. Мы предполагаем, что ; она возвращает ZF=1 при совпадении. ; mov rsi, rax ; Имя модуля ; call StrCmp ; Вызов подпрограммы сравнения строк ; **Заглушка сравнения строк:** Предположим, что имя совпало ; jne .NextName ; Если не совпало, идем к следующему ; ------------------------------------------------------------------ ; 4. Имя совпало: Получаем адрес функции ; ------------------------------------------------------------------ ; RAX = RBP (Базовый адрес модуля) ; RSI = Указатель на IMAGE_EXPORT_DIRECTORY ; RCX = NumberOfNames (индекс совпавшей функции) ; R8 = AddressOfNameOrdinals ; R9 = AddressOfFunctions ; 4.1 Получаем RVA функции movzx edx, word ptr [r8 + rcx * 2] ; EDX = Ординал mov eax, dword ptr [r9 + rdx * 4] ; EAX = RVA функции ; Сохраняем RVA функции, т.к. будем его модифицировать mov r10d, eax ; 4.2 Определяем границы Директории Экспорта ; [rsi + 00h] содержит RVA Директории Экспорта (то же, что и RVA Export Table) mov ebx, dword ptr [rsi] ; EBX = Export RVA ; [rsi + 04h] содержит Размер Директории Экспорта (Size) mov ecx, dword ptr [rsi + 04h] ; ECX = Export Size add ecx, ebx ; ECX = Export RVA + Export Size (Верхняя граница) ; 4.3 Проверка на Форвардер cmp r10d, ebx ; Сравнить RVA функции с нижней границей jl .FunctionAddressFound ; Если RVA меньше, это не форвардер cmp r10d, ecx ; Сравнить RVA функции с верхней границей jge .FunctionAddressFound ; Если RVA больше или равно, это не форвардер ; ------------------------------------------------------------------ ; ЭТО ФОРВАРДЕР! R10D содержит RVA строки-форвардера. ; ------------------------------------------------------------------ ; RAX = Указатель на строку-форвардер add rax, rbp ; RBP + RVA функции (R10D) = Адрес строки ; Теперь RAX указывает на строку "DLL_NAME.Function_Name" ; ****************************************************************** ; РЕКУРСИВНЫЙ ВЫЗОВ (Здесь должна быть рекурсия) ; ****************************************************************** ; Этот код должен: ; 1. Распарсить строку RAX на "DLL_NAME" и "Function_Name" ; 2. Вызвать LoadLibraryA (которая уже должна быть найдена) для "DLL_NAME". ; 3. Вызвать GetProcAddress (которая уже должна быть найдена) для "Function_Name". ; Поскольку рекурсия на ассемблере сложна, мы вернем 0 и ; пометим этот случай как критическую ошибку в нашем простом загрузчике. jmp .ExitError ; В простом Shellcode, мы обрабатываем только не-форвардеры. .FunctionAddressFound: ; 4.4 RVA функции находится в R10D (не форвардер) mov eax, r10d ; EAX = RVA функции add rax, rbp ; RAX = BaseAddress + RVA функции = Финальный адрес jmp .ExitSuccess ; ... (Код для .ExitSuccess и .ExitError) ... При обнаружении форвардера, загрузчик должен рекурсивно или итеративно вызвать LoadLibraryA для указанной DLL и затем повторно вызвать GetProcAddress для указанной в форвардере функции/ординала. Фрагмент кода ; ------------------------------------------------------------------ ; Подпрограмма StrCmp (сравнение строк, как часть Загрузчика) ; ------------------------------------------------------------------ StrCmp PROC ; RDI и RSI уже установлены вызывающей процедурой (FindProcAddress) ; Мы будем использовать инструкции для сравнения строк ; CLD (Clear Direction Flag) - устанавливает направление сканирования вперед (RSI/RDI++) cld > entry: что прописывать /entry: start или /entry:WinMain ? Тоесть абсолютно отсутствует понимание, тогда врядле что поможет
Ahimov, вот хоть бы раз нормально и по-человечески ответили. То у вас техзадание составлено неверно, то ещё какая-нибудь фигня. Лишь бы до чего-нибудь докопаться и уйти от ответа. Не удивлюсь, если этот ваш код - не будет компилироваться или запускаться, из-за каких-нибудь мелких косяков.
Посмотрела кривой сервис NtGdiGetDIBitsInternal, результат: --- Сообщение объединено, 7 дек 2025 --- Создание эксплойтов заблокировано
Первый наугад ядерный сервис, посмотреть на анализ: Код (C): Этот тест проверяет, зануляет ли ядро буфер перед записью или оставляет «мусор» в полях выравнивания структуры USEROBJECTFLAGS. #include <windows.h> #include <stdio.h> #include <vector> // Структура, как она видится в User-Mode typedef struct tagUSEROBJECTFLAGS { BOOL fInherit; BOOL fReserved; DWORD dwFlags; } USEROBJECTFLAGS, *PUSEROBJECTFLAGS; void TestInfoleak() { HWINSTA hWinSta = GetProcessWindowStation(); USEROBJECTFLAGS uof; // Заполняем локальную структуру "маркером" перед вызовом memset(&uof, 0xEE, sizeof(uof)); printf("[*] Testing for Information Disclosure...\n"); if (GetUserObjectInformationW(hWinSta, UOI_FLAGS, &uof, sizeof(uof), NULL)) { BYTE* ptr = (BYTE*)&uof; bool leaked = false; printf("[+] Buffer after kernel call:\n"); for (int i = 0; i < sizeof(uof); i++) { printf("%02X ", ptr[i]); // Если мы видим что-то, что не является 0xEE (наш маркер) // и не является результатом работы (0 или 1), это может быть утечкой. } printf("\n"); // Анализ fReserved (ядро пишет туда 0, но проверим соседние байты) if (uof.fReserved != 0) { printf("[!] Unexpected value in fReserved: 0x%X\n", uof.fReserved); } } } Код (Text): Этот PoC имитирует атаку, при которой один поток постоянно меняет права доступа к памяти, в которую ядро пытается записать данные. Цель — проверить, вызовет ли это Double Fault или BSOD. #include <windows.h> #include <process.h> #include <stdio.h> // Глобальные данные для потоков void* g_sharedMem = NULL; bool g_running = true; // Поток Б: Постоянно меняет состояние страницы (Доступна <-> Недоступна) unsigned __stdcall MemoryFlippingThread(void* arg) { while (g_running) { DWORD oldProtect; // Делаем страницу недоступной VirtualProtect(g_sharedMem, 4096, PAGE_NOACCESS, &oldProtect); // Небольшая пауза для переключения контекста for (volatile int i = 0; i < 100; i++); // Возвращаем доступ VirtualProtect(g_sharedMem, 4096, PAGE_READWRITE, &oldProtect); } return 0; } void TestRaceCondition() { g_sharedMem = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE); HWINSTA hWinSta = GetProcessWindowStation(); HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, MemoryFlippingThread, NULL, 0, NULL); printf("[*] Starting Race Condition test (press Ctrl+C to stop)...\n"); for (int i = 0; i < 100000; i++) { DWORD lenNeeded = 0; // Ядро входит в NtUserGetObjectInformation, делает ProbeForWrite, // а в этот момент Поток Б выбивает страницу из-под ног ядра. GetUserObjectInformationW(hWinSta, UOI_NAME, g_sharedMem, 1024, &lenNeeded); if (i % 10000 == 0) printf("[.] %d iterations completed\n", i); } g_running = false; WaitForSingleObject(hThread, INFINITE); VirtualFree(g_sharedMem, 0, MEM_RELEASE); printf("[+] Test finished without BSOD.\n"); } В связке с идой походу должна быть крутая штука.