Вопрос про SEH

Тема в разделе "WASM.WIN32", создана пользователем bugmenot, 29 июн 2009.

  1. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Добрый день.

    У меня вопрос следующий, есть данный код:
    Код (Text):
    1.   MOV EAX,0x00401000
    2.   PUSH EAX
    3.   PUSH DWORD PTR FS:[0x0]
    4.   MOV DWORD PTR FS:[0x0],ESP
    5.   XOR EAX,EAX
    6.   MOV DWORD PTR [EAX],ECX
    Открываю OllyDbg, ставлю бряк на 0x00401000, брякается - порядок.
    Но если я аллокирую память с помощью VirtualAlloc (с флагом executable), пишу туда свой код, задаю этот код как SEH хендлер, запускаю - код не запускается, а программа вылетает.

    Почему так получается? Кому SEH готов передавать контроль, кому нет, и от чего это зависит?

    Спасибо.
     
  2. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Предположу что код в выделенную память не записывается, либо не правильно записывается. Необходимо видеть скомпиленный модуль.
     
  3. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Что-то я совсем запутался.
    Скомпилировал программу, хотел показать, как работает, а оказывается - не работает.

    В аттаче два файла, test1.exe и test2.exe.
    На вид вроде одинаковые, открываю обоих в OllyDbg, ставлю бряк на 00401019, запускаю.
    Первый брякается, второй вылетает.

    Как так может быть?
    Код то одинаковый!
     
  4. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    IMAGE_DLLCHARACTERISTICS_NO_SEH - хорошая шутка..
     
  5. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Все понял, спасибо! :)

    Зачем-то VC 9 ставит DllCharacteristics=0x8500 по дефолту, что значит:
    IMAGE_DLLCHARACTERISTICS_NX_COMPAT
    IMAGE_DLLCHARACTERISTICS_NO_SEH
    IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE

    Насчет первого понятно - секюрити, а остальные зачем?
    Надо в настройках поковыряться...

    Еще раз спасибо!
     
  6. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    bugmenot
    Хотя этот флажёк известен, но искалась причина не в хекс-редакторе. Дебажим - в опциях оли ставим диапазон кодов исключений [0;-1]. Сех вызывает RtlpExecuteHandlerForException().
    > Ставим точку останова на KiUserExceptionDispatcher(). Запускаем, управление получает диспетчер исключений - срабатывает останов. Далее трассируем.
    > Попадаем в RtlDispatchException().
    > Проходим векторную обработку(не установлен хэндлер) в RtlCallVectoredExceptionHandlers().
    > Проходим проверки на диапазон стека и тп., оказываемся в RtlIsValidHandler(), которая лжёт, изза чего сех не вызывается и поток входит в NtRaiseException.
    > RtlIsValidHandler() вызывает RtlLookupFunctionTable(), которая ищет таблицу хэндлеров из директории исключений в модуле. Она вызывает RtlCaptureImageExceptionValues() в начале которой проверка:
    Код (Text):
    1. 7C93411A _RtlCaptureImageExceptionValues@12   mov edi,edi
    2. 7C93411C                                      push ebp
    3. 7C93411D                                      mov ebp,esp
    4. 7C93411F                                      push ecx
    5. 7C934120                                      push dword ptr ss:[ebp+8]
    6. 7C934123                                      call ntdll.RtlImageNtHeader
    7. 7C934128                                      test byte ptr ds:[eax+5F],4
    8. 7C93412C                                      jnz ntdll.7C950DA3
    Или может так нагляднее:
    Код (Text):
    1.     NtHeaders = RtlImageNtHeader(Base);
    2.     if (NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) {
    Далее функция вернёт ошибку и все последующие тоже.

    А я ведь старался, описал как исключения разбирать подробно, в самом верху этого раздела, всё впустую :dntknw:
     
  7. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Все таки не только во флажке дело, мой первоначальный вопрос актуален.
    В аттаче два файла: good.exe и bad.exe.

    good.exe попадает на адрес хендлера, и останавливается на INT3.
    А вот bad.exe, у которого этот код находится на аллокированной памяти, просто вылетает.

    Поставил, а куда дальше шагать, не знаю...
    RtlDispatchException, RtlCallVectoredExceptionHandlers - у меня таких OllyDbg не находит (Windows 7).

    Я туда заглянул, просмотрел мельком, и мне показалось, что речь о SEH в краце - а значит навряд ли написано про случай с использованием SEH с аллокированным блоком кода.
    Кстати, тема (theme) в том топике на скриншоте - моя любимая XP-шная тема :)
     
  8. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Аттач забыл, а редактировать вроде как нельзя...
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Он и должен вылетать. Приложение тихо завершается - обработчик генерирует исключение #BP(при исполнении Int3). Это приводит вновь к вызову обработчика, покуда весь стек доступный для треда не будет исчерпан, после чего ядро тихо завершит процесс. Это на XP, может на W7 есчо есть проверки на вхождение адреса обработчика в диапазон модуля, не смотрел. Нормальный фрейм должен содержать смещение безопасного места и регистр Ebp, для последующего восстановления его.
    Альтернативой является векторная обработка исключений, она быстрее и надёжнее.
     
  10. catwalk_mission

    catwalk_mission New Member

    Публикаций:
    0
    Регистрация:
    23 май 2009
    Сообщения:
    19
    bugmenot
    если хотите отловить момент завершения в отладчике, поставьте точки останова не только на KiUserExceptionDispatcher() но и на ZwRaiseException(). обратите внимание на третий параметр ZwRaiseException() – "NotifyFrames". если он установлен в ноль, то процесс будет завершён (после уведомления отладчика).
    Код (Text):
    1. KiUserExceptionDispatcher()
    2. {
    3.     if (RtlDispatchException)
    4.         ZwContinue();
    5.     else
    6.         ZwRaiseException();
    7. }
    8.  
    9.  
    10. _
    11. struct EXCEPTION_REGISTRATION
    12. {
    13.     EXCEPTION_REGISTRATION* prev;
    14.     PEXCEPTION_HANDLER_PROC handler;
    15. };
    блок-схема RtlDispatchException – click-click =)
    как видно из схемы, RtlDispatchException() вернёт false, не вызвав ни одного обработчика в случае, если что-то не в порядке со стеком или хендлером.
    "стек в порядке", если: он выровнен на dword, структура EXCEPTION_REGISTRATION находится в стеке, обработчик исключений находится вне стека, все структуры EXCEPTION_REGISTRATION расположены последовательно.
    "правильность" обработчика проверяет функция RtlIsValidHandler(). если хендлер принадлежит исполняемому модулю, то проверяется PE-заголовок: Exception Directory, наличие флажка IMAGE_DLLCHARACTERISTICS_NO_SEH.
    в общем-то, это всё уже сказал Clerk =)
    чего не было сказано: если хендлер находится в памяти, выделенной VirtualAlloc, то, кроме всего прочего, проверяются флажки процесса Pcb.Flags (_KEXECUTE_OPTIONS): ExecuteDispatchEnable и ImageDispatchEnable. если они оба сброшены, то RtlIsValidHandler вернёт false.
    в случае bad.exe на моей системе они как раз сброшены.
    не знаю точно, от чего, кроме параметров DEP, зависят Pcb.Flags. но можете просмотреть их, введя в отладчике ядра "dt _EPROCESS Pcb.Flags. адрес-структуры-eprocess" (адрес нужной _EPROCESS можно получить с помощью "!process 0 0").
    установить эти флажки для своего процесса можно с помощью ZwSetInformationProcess(ProcessExecuteFlags==0x22).
     
  11. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Дело в том, что до INT3 дело не доходит.

    catwalk_mission, спасибо за информацию!

    Дело в том, что я хочу осуществить запуск программы из памяти, следующим образом:
    Аллокирую и записываю exe файл и код в другое место, вызываю код.
    Этот код освобождает главный модуль - UnmapViewOfFile, на этом же месте вызывает VirtualAlloc, записывает туда exe, чинит импорты итд., и запускает.
    Работает отлично, кроме случаев с ошибками - они не обрабатываются.

    Можно попробовать сделать это все без UnmapViewOfFile и VirtualAlloc, а просто заполнить все нолями, и поставить правильные права.
     
  12. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    bugmenot
    Странно, но у меня доходит. Как вы смотрите что Int3 сработал ?
     
  13. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Ставлю бряк с помощью OllyDbg.
    У меня включен DEP, может в этом дело?
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    На W7 нет где потестить. Продебажте сами, тогда видно будет в чём причина.
     
  15. bugmenot

    bugmenot New Member

    Публикаций:
    0
    Регистрация:
    4 дек 2006
    Сообщения:
    21
    Да, наверно так оно и есть.
    Поставил в исключение DEP - заработало.