#cpp #c #windows #x86
Возьмем цикл, который читает bool переменную #includevolatile bool stop = false; void loop() { while (!stop) { putchar('.'); } } Мы хотим поменять значение stop на 4-м чтении, чтобы цикл напечатал троеточие многоточие и завершился. Как на Windows перехватить чтения переменной stop, и поменять ее значение?
Ответы
Ответ 1
Для точек останова на память можно использовать Guard Page. Это специальный флаг свойств страницы памяти, при котором обращение к странице вызывает исключение STATUS_GUARD_PAGE_VIOLATION (0x80000001). При этом флаг Guard Page сбрасывается, и повторное обращение к странице памяти исключений не вызывает. Для чтений памяти, обработчик исключений может перехватить исключение STATUS_GUARD_PAGE_VIOLATION, изменить значение памяти и пометить исключение обработанным. Чтение перезапустится, и прочитается новое значение выставленное в обработчике. Чтобы точка останова не была одноразовой, флаг Guard Page надо выставить повторно. Для этого в обработчике STATUS_GUARD_PAGE_VIOLATION надо выставить флаг процессора TF (trap flag). Тогда перед выполнением следующей инструкции будет выброшено исключение STATUS_SINGLE_STEP. В его обработчике можно обновить флаг Guard Page, а также можно прочитать значение записанное предыдущей инструкцией, если она делала запись памяти. В коде это выглядит следующим образом: #includeint aux_counter = 0; // счетчик для отсчета четырех чтений // установка PAGE_GUARD для страницы в которую входит адрес |addr| void set_guard_on_bool(volatile bool* addr) { MEMORY_BASIC_INFORMATION info; VirtualQuery((void*)addr, &info, sizeof(info)); DWORD unused; VirtualProtect((void*)addr, sizeof(*addr), info.Protect | PAGE_GUARD, &unused); } // обработчик исключений LONG __stdcall exception_handler(EXCEPTION_POINTERS* e) { switch (e->ExceptionRecord->ExceptionCode) { case STATUS_GUARD_PAGE_VIOLATION: { // параметры исключения - чтение/запись и адрес памяти bool is_read = e->ExceptionRecord->ExceptionInformation[0] == 0; void* location = (void*)e->ExceptionRecord->ExceptionInformation[1]; // проверяем что это чтение адреса |stop| // TODO: тут можно пропустить исключения для всех остальных страниц памяти if (location == &stop && is_read) { ++aux_counter; // завершаем цикл на 4-е чтение переменной if (aux_counter == 4) { stop = true; return EXCEPTION_CONTINUE_EXECUTION; } } // выставляем TF чтобы вызвать исключение STATUS_SINGLE_STEP e->ContextRecord->EFlags |= 0x100; return EXCEPTION_CONTINUE_EXECUTION; } case STATUS_SINGLE_STEP: { // обновляем флаг PAGE_GUARD set_guard_on_bool(&stop); return EXCEPTION_CONTINUE_EXECUTION; } default: { // пропускаем остальные исключения return EXCEPTION_CONTINUE_SEARCH; } } } int main() { // устанавливаем обработчик исключений AddVectoredExceptionHandler(1 /* first */, exception_handler); // и выставляем флаг PAGE_GUARD set_guard_on_bool(&stop); loop(); } Пример работы программы: > g++ -O3 main.cpp && a.exe ...
Комментариев нет:
Отправить комментарий