Вот нашел здесь статью http://www.wasm.ru/article.php?article=Win32SEHPietrek1 Под дебагом перехват эксепшна работает, а под релизом не ловит. В чем может быть причина? Компилю в VS 2005 с дефолтными настройками. Код (Text): //================================================== // MYSEH - Matt Pietrek 1997 // Microsoft Systems Journal, January 1997 // FILE: MYSEH.CPP // To compile: CL MYSEH.CPP //================================================== #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdio.h> DWORD scratch; EXCEPTION_DISPOSITION __cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame, struct _CONTEXT *ContextRecord, void * DispatcherContext ) { unsigned i; // Indicate that we made it to our exception handler printf( "Hello from an exception handler\n" ); // Change EAX in the context record so that it points to someplace // where we can successfully write ContextRecord->Eax = (DWORD)&scratch; // Tell the OS to restart the faulting instruction return ExceptionContinueExecution; } int main() { DWORD handler = (DWORD)_except_handler; __asm { // Build EXCEPTION_REGISTRATION record: push handler // Address of handler function push FS:[0] // Address of previous handler mov FS:[0],ESP // Install new EXECEPTION_REGISTRATION } __asm { mov eax,0 // Zero out EAX mov [eax], 1 // Write to EAX to deliberately cause a fault } printf( "After writing!\n" ); __asm { // Remove our EXECEPTION_REGISTRATION record mov eax,[ESP] // Get pointer to previous record mov FS:[0], EAX // Install previous record add esp, 8 // Clean our EXECEPTION_REGISTRATION off stack } return 0; }
Может подскажете, как подобным образом реализовать __except(EXCEPTION_EXECUTE_HANDLER). Посути мне надо просто перейти в определенную точку в коде. Для этого насколько я понимаю надо записать нужный адрес в ContextRecord->Eip. Но как же тут быть со стеком и с текущими значениями регистров?
Восстановится всё для того места где произошел эксепшн, а не для того адреса куда мне перейти надо.. надо ведь как-то вычислять сколько стека освобождать надо, и т.д.
Или просто посоветуйте решение как можно продолжить выполнение потока после такого эксепшна как вызов инструкции по кривому адресу. Вот пример: Код (Text): #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdio.h> //================================================== // MYSEH - Matt Pietrek 1997 // Microsoft Systems Journal, January 1997 // FILE: MYSEH.CPP // To compile: CL MYSEH.CPP //================================================== EXCEPTION_DISPOSITION __cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame, struct _CONTEXT *ContextRecord, void * DispatcherContext ) { DWORD scratch; // Indicate that we made it to our exception handler printf( "Hello from an exception handler\n" ); // Change EAX in the context record so that it points to someplace // where we can successfully write ContextRecord->Eax = (DWORD)&scratch; // Tell the OS to restart the faulting instruction return ExceptionContinueExecution; } typedef void(*badfunc)(); int main() { DWORD handler = (DWORD)_except_handler; __asm { // Build EXCEPTION_REGISTRATION record: push handler // Address of handler function push FS:[0] // Address of previous handler mov FS:[0],ESP // Install new EXECEPTION_REGISTRATION } badfunc f=NULL; f(); printf( "After writing!\n" ); __asm { // Remove our EXECEPTION_REGISTRATION record mov eax,[ESP] // Get pointer to previous record mov FS:[0], EAX // Install previous record add esp, 8 // Clean our EXECEPTION_REGISTRATION off stack } return 0; }
Ну я в общем-то отличаю И если уж говорить о SEH, то это никак не встроенный в венду механизм обработки исключений, скорее наоборот: SEH есть расширение системного механизма обработки исключений Windows. По поводу темы дискуссии, автору рекомендую к прочтению мою статью, не так давно опубликованную на этом сайте: обработка user-mode исключений в Windows. Для решения вашей задачи потребуется реализовать механизм, подобный SEH.
Ну как бы доступные пользователю в юзермоде обработчики - SEH/VEH. Более низкоуровневый - это уже хукать KiUserExceptionDispatcher, undoc. В ядре тоже есть SEH. Поэтому о чем речь-то? А __try/__except/__finally (_except_handler/_global_unwind/_local_unwind) - это надстройка над SEH, причем спецефичная для msvc.
Я про то, что название SEH не корректно для системной обработки исключений. SEH - это, по-логике, расширение msvc, хотя обычно, говоря SEH, подразумевают то, что вы имели в виду.
nerd, В контексте есть Ebp, теоретически можно доскакать до нужного фрейма (аргумент EstablisherFrame указывает на структуру EXCEPTION_REGISTRATION, через которую был вызван обработчик). С правильным Esp, естественно, несколько сложнее. Есть ещё RtlUnwind(), которая, если я правильно понимаю, вызывает обработчики вплоть до указанного с кодом STATUS_UNWIND (0xC0000027) а потом переходит куда сказано. Что при этом с регистрами — вопрос. Если бы средствами C (без __try / __except / __finally, но с __asm) можно было бы реализовать человеческий инлайновый SEH (т.е. с возможностью обработать исключение и осмысленно перейти куда-нибудь в теле функции), это уже было бы сделано. Компилятор попросту не предоставляет достаточно информации для этого. А уж если это C++ с его деструкторами — всё гораздо веселей (на OpenRCE есть неплохая статья про художества MSVC++). Поиском нашёл здесь интересную тему. Стоит глянуть.
VEH регайте, SEH локальный и не стабильный, не юзайте его для решения задач, отличных от защиты стековых фреймов.