Так, похоже вы правы. С LoadLibrary исключение обрабатывается и выполнение программы продолжается (слегка модифицировал обработчик). В чём может быть проблема, когда загрузка DLL осуществляется вручную? Память выделяется через VirtualAlloc с флагом PAGE_EXECUTE_READWRITE.
Вы были правы на счёт обработчика, он хитрее, чем я полагал: Код (Text): EXCEPTION_DISPOSITION __cdecl handler ( struct _EXCEPTION_RECORD *_ExceptionRecord, void * _EstablisherFrame, struct _CONTEXT *_ContextRecord, void * _DispatcherContext ) { lpData1 = (LPDWORD)&lpData1; _ContextRecord->Eip += 6; return ExceptionContinueExecution; }
Вот такой ещё интересный момент. Загрузка DLL происходит следующим образом: dll-loader.exe -> library1.dll -> library2.dll. В library1 присутствует код, который грузит как саму library1, так и library2. Так вот, после такой хитрой загрузки library1 работает в полном соответствии с SEH и т.д., а вот в library2 почему-то возникают описанные проблемы. То есть, при одном и том же коде -- разный результат... Странно всё. Тестирую, кстати, на W7.
>VOID handler() { *lpData = (LPVOID)&lpData; } >LPDWORD lpData = NULL; Что в 'lpData' лежит? Нуль. Т.е. в хендлере ОП пишет по нулевому адресу и возникает ещё одно исключение. Что он хотел сделать: VOID handler() { lpData = (LPVOID)&lpData; } ...Ага, уже исправил. Y_Mur Не более обязательно, чем в других колбеках – если один не использует эти регистры, то и сохранять\восстанавливать их незачем. Более того, современные системы для обработки сех не полагаются на то, что пользовательский хендлер сохранит эти регистры (даже в сохранность esp не верят). Хотя да, полагаться на это мы бы не стали. 7mm Если хочешь try\except без CRT, то можешь подключить только те кусочки, где определены нужные процедуры – и не нужны будут асм-вставки. Либо можешь свой _except_handler4\_except_handler3 написать, если MS не доверяешь. Опять-таки, выгода – достигается улучшенный контроль и не нужны асм-вставки. Можешь даже багу исправить.
ohneуказал на IMAGE_DLLCHARACTERISTICS_NO_SEH. Это значение DllCharacteristics из _IMAGE_OPTIONAL_HEADER (заголовка pe-файла) - в msdn "The image does not use structured exception handling (SEH). No handlers can be called in this image." Значит нужна доп-я обработка при загрузке образа DLL-ки в память процесса, как это делает LoadLibrary... Может ohne подскажет как вручную "включить" SEH?
(хз чей топик, тоесть кто автор..) В самом верху этого раздела прикреплён мой топик. Почитать вам его не нужно, тогда попросите когонибудь почитать его за вас. Конкретно по вопросу: RtlDispatchException -> RtlIsValidHandler -> RtlLookupFunctionTable -> RtlCaptureImageExceptionValues проверяет в заголовке модуля флажёк IMAGE_DLLCHARACTERISTICS_NO_SEH, если взведён выполняется возврат с ошибкой, что значит хэндлер инвалидный и не может быть вызван. Он скажет сбросить этот флажёк, либо сбросить его в проекции модуля.
Добился чтобы MSVC и масм генерировали практически одинаковый тестовый код. При этом masm вариант работает на ура - Оля отлично отлавливает бряк (по F2) в SEH обработчике и обработчик корректно исправляет адрес записи. А в MSVC варианте вместо перехода на бряк в SEH обработчике Оля пишет "отлаживаемая прога не способна обработать исключение"...
Clerk В том топике по ключевому слову "NO_SEH" ничего не нашлось. Для exe тот-же флажок, или другой? Странно зачем MSVC вообще SEH блокирует.
Код (Text): Structure for Optional Header (+0x46) DllCharacteristics: 0x0000 Как видно, флаг, запрещающий SEH, не установлен.
Только что проверил такую штуку: в Windows XP SP3 всё работает как по маслу. Проблемы возникают в W7. Вот здесь похожая проблема (http://wasm.ru/forum/viewtopic.php?id=33418) - там вроде бы дело в DEP.
1. Если дело в этом т.е. в DEP, то ваша dll-ка вообще бы не работала. В любом случае, проверьте установку атрибутов на страницы памяти, где располагается сегмент кода - PAGE_EXECUTE_READWRITE 2. Clerk говорит о том, что "...RtlCaptureImageExceptionValues проверяет в заголовке модуля флажёк IMAGE_DLLCHARACTERISTICS_NO_SEH...". Но у вас "модуля" нет - вы загружали dll-ку вручную, может поэтому так и происходит...
Да, флаг стоит. В коде стоит и в Olly RWX отображается. Да, модуль загружается вручную. Не регистрируется... Может быть дело в этом. Однако, в посте #24 я описал принцип загрузки DLL. Получается, что всё-таки одна из двух загружаемых (идентично?) DLL работает, включая SEH.
Смотри там же(http://wasm.ru/forum/viewtopic.php?id=33418) #10: " чего не было сказано: если хендлер находится в памяти, выделенной VirtualAlloc, то, кроме всего прочего, проверяются флажки процесса Pcb.Flags (_KEXECUTE_OPTIONS): ExecuteDispatchEnable и ImageDispatchEnable. если они оба сброшены, то RtlIsValidHandler вернёт false. " -вот это надо-бы проверить
Так а это, твоя длл добавляется в список загруженных модулей (их, кстати, очень много)? SEH обработан не будет, если адрес хендлера указывает вне зарегистрированных модулей. Это часть защиты от атак переполнения буффера - чтобы нельзя было перетереть адрес обработчика на стеке.
Ну похоже на то... Отключил DEP, дело в нём -- ничего не изменилось. Получается, что в W7 можно забыть про 'хитрую' загрузку DLL с возможностью использования SEH без MSVCRT?
Да ёлки, я разве про DEP писал? То, что я описал - встроенная фича обработки SEH. Не отключается afaik
Да это я просто до вашего комментария пробовал. Кстати, если за обработку исключений отвечает KiUserExceptionDispatcher, то можно наверняка его подкрутить, чтобы поменять логику обработки SEH для незарегистрированных модулей?