![]() |
eXeL@B —› Программирование —› Стек и обработка исключений... |
Посл.ответ | Сообщение |
|
Создано: 01 февраля 2009 02:06 · Личное сообщение · #1 Windows как то по разному обрабатывает исключения в коде, в зависимости от того на каком стеке возникает исключение, может кто нибудь знает точный алгоритм, вот например результаты опытов (код который генерирует исключение и SEH находятся в коде программы): 1. SEH + исключение в главном стеке программы - обрабатывается нормально 2. SEH + исключение в треде (стек треда) - обрабатывается нормально 3. SEH + исключение в callback таймера (стек не понятной чей, наверное kernel) - НЕ обрабатывается 4. SEH + исключение, код выполняется на стеке (памяти) выделеным VirtualAlloc - НЕ обрабатывается 5. SEH + исключение, код выполняется на стеке выделеным HeapCreate/HeapAlloc - НЕ обрабатывается Как например можно создать такой же стек как и у треда (или главной программы), может такой стек имеет какие нибудь "интересные" аттрибуты в отличие от стека случаев 4, 5? Почему же исключения не обрабатываются в 3,4,5 случаях? ![]() |
|
Создано: 01 февраля 2009 07:03 · Поправил: dermatolog · Личное сообщение · #2 |
|
Создано: 01 февраля 2009 09:05 · Личное сообщение · #3 Исключение не обрабатывается только в одном случае - невалидный стек, тоесть страница адресуемая ss:esp не доступна для записи. Используй VEH. > стек не понятной чей, наверное kernel Каждый юзермодный поток имеет ядерный стек(DPC - стек), последний не зависит от юзермодного стека. > Как например можно создать такой же стек как и у треда ntdll!RtlCreateUserStack(). > Почему же исключения не обрабатываются в 3,4,5 случаях? Обрабатываются. ![]() |
|
Создано: 01 февраля 2009 11:15 · Личное сообщение · #4 dermatolog пишет: Прога скомпилена с использованием /SAFESEH? Нет, да это даже не важно как скомпилирована... Допустим в случаях 3,4,5 я трассировал исключение, где же именно оно не обрабатывается, дошел до кода где то в недрах ntdll, обработчик проверяет адрес стека на котором было вызвано исключение, так вот в случаях 3,4,5 обработчик перебирает все стеки процесса (точнее не все стеки а просто проверяет входит ли данный стек в стек процесса) и понимает что исключение выполнено на "не зарегистрированном" стеке, и просто не обрабатывает его. А в случае 2, обработчик проверяет находится ли стек в стеке программы или стек треда. Так почему же обработчик не принимает стек созданный HeapCreate/HeapAlloc? Clerk пишет: Исключение не обрабатывается только в одном случае - невалидный стек, тоесть страница адресуемая ss:esp не доступна для записи. Стек валидный, например же в 5 случае он вообще создан с помощью HeapCreate/HeapAlloc, запись разрешена... Clerk пишет: Используй VEH. Да не в этом дело ![]() Clerk пишет: ntdll!RtlCreateUserStack(). Ага, спасибо, попробую! Clerk пишет: Обрабатываются. Вот пример в аттаче (исходники и бинарник), если убрать mov esp, d то все нормально, а если стек поменять - то второе сообщение не показывается... прога вылетает на исключении. Не обрабатывается.... ![]() ![]() |
|
Создано: 01 февраля 2009 13:01 · Поправил: Clerk · Личное сообщение · #5 Enigma Всё понятно. В начале RtlDispatchException() выполняется проверка на принадлежность фрейма стеку, тоесть проверяется диапазон. Это границы стека определённые в TEB(TIB, поля StackBase и StackLimit). Если фрейм вне этого диапазона, то далее структурная обработка исключения не исполняется диспетчером. Вот код: Code:
Перед сменой стека загрузи в TIB его базу и предел. ![]() |
|
Создано: 01 февраля 2009 13:47 · Личное сообщение · #6 |
|
Создано: 01 февраля 2009 14:12 · Личное сообщение · #7 |
|
Создано: 01 февраля 2009 14:34 · Личное сообщение · #8 |
|
Создано: 02 февраля 2009 12:11 · Личное сообщение · #9 |
|
Создано: 02 февраля 2009 12:33 · Личное сообщение · #10 |
|
Создано: 02 февраля 2009 15:05 · Личное сообщение · #11 seeq Ice-T Вы заблуждаетесь. Обьясню. Я уже много раз писал про это, тут например: wasm.ru/forum/viewtopic.php?id=29865&p=1 wasm.ru/forum/viewtopic.php?id=30212 wasm.ru/forum/viewtopic.php?id=29537&p=2 ,#35 "Еслючение не обрабатывается" - под этим понимается что при возникновении исключения в потоке, ядро не может выполнить его разворачивание в юзермоде. Тоесть при заполнении стекового фрейма информацией(EXCEPTION_POINTERS) возникает исключение в ядерном диспетчере исключений. Ядро не может восстановить стек потока, поэтому прибивается такой поток, да есчо и процесс, к которуму этот поток принадлежит. В любых остальных случаях будет вызван юзермодный диспетчер исключений (KiUserExceptionDispatcher), что он выполнит имеет малое значение. Так этот диспетчер находится в ntdll, следствием является то, что этот код свободно может модифицировать кто угодно. Например я часто исполняю "сырую" обработку исключения, прото выполнив редирект диспетчера исключений на свой(например сплайсингом). Вот кусок живого ядра, который завершает процесс при подобном исключении, медитируйте на нём: Code:
Этот структурный обработчик исключения, который регистрируется в самом начале KiDispatchException(), при заполнении структур, например CONTEXT изза невалидного стека возникает исключение и управление получает этот код. Например: Code:
Исполнив данный код поток и процесс перестанут существовать, причём никакая нотификация остальных потокаов не будет исполнена. Подобное можно обработать единственным способом - перед завершением потока выполняется нотификация отладчика, он получает сообщение о подобном исключении. Далее он может перезагрузить регистры Esp(Ss) и продолжить исполнение, но минус в том, что отладчиком является второй процесс. Думою понятно обьяснил. ![]() |
![]() |
eXeL@B —› Программирование —› Стек и обработка исключений... |