Добрый день. У меня вопрос следующий, есть данный код: Код (Text): MOV EAX,0x00401000 PUSH EAX PUSH DWORD PTR FS:[0x0] MOV DWORD PTR FS:[0x0],ESP XOR EAX,EAX MOV DWORD PTR [EAX],ECX Открываю OllyDbg, ставлю бряк на 0x00401000, брякается - порядок. Но если я аллокирую память с помощью VirtualAlloc (с флагом executable), пишу туда свой код, задаю этот код как SEH хендлер, запускаю - код не запускается, а программа вылетает. Почему так получается? Кому SEH готов передавать контроль, кому нет, и от чего это зависит? Спасибо.
Предположу что код в выделенную память не записывается, либо не правильно записывается. Необходимо видеть скомпиленный модуль.
Что-то я совсем запутался. Скомпилировал программу, хотел показать, как работает, а оказывается - не работает. В аттаче два файла, test1.exe и test2.exe. На вид вроде одинаковые, открываю обоих в OllyDbg, ставлю бряк на 00401019, запускаю. Первый брякается, второй вылетает. Как так может быть? Код то одинаковый!
Все понял, спасибо! Зачем-то VC 9 ставит DllCharacteristics=0x8500 по дефолту, что значит: IMAGE_DLLCHARACTERISTICS_NX_COMPAT IMAGE_DLLCHARACTERISTICS_NO_SEH IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE Насчет первого понятно - секюрити, а остальные зачем? Надо в настройках поковыряться... Еще раз спасибо!
bugmenot Хотя этот флажёк известен, но искалась причина не в хекс-редакторе. Дебажим - в опциях оли ставим диапазон кодов исключений [0;-1]. Сех вызывает RtlpExecuteHandlerForException(). > Ставим точку останова на KiUserExceptionDispatcher(). Запускаем, управление получает диспетчер исключений - срабатывает останов. Далее трассируем. > Попадаем в RtlDispatchException(). > Проходим векторную обработку(не установлен хэндлер) в RtlCallVectoredExceptionHandlers(). > Проходим проверки на диапазон стека и тп., оказываемся в RtlIsValidHandler(), которая лжёт, изза чего сех не вызывается и поток входит в NtRaiseException. > RtlIsValidHandler() вызывает RtlLookupFunctionTable(), которая ищет таблицу хэндлеров из директории исключений в модуле. Она вызывает RtlCaptureImageExceptionValues() в начале которой проверка: Код (Text): 7C93411A _RtlCaptureImageExceptionValues@12 mov edi,edi 7C93411C push ebp 7C93411D mov ebp,esp 7C93411F push ecx 7C934120 push dword ptr ss:[ebp+8] 7C934123 call ntdll.RtlImageNtHeader 7C934128 test byte ptr ds:[eax+5F],4 7C93412C jnz ntdll.7C950DA3 Или может так нагляднее: Код (Text): NtHeaders = RtlImageNtHeader(Base); if (NtHeaders->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_SEH) { Далее функция вернёт ошибку и все последующие тоже. А я ведь старался, описал как исключения разбирать подробно, в самом верху этого раздела, всё впустую
Все таки не только во флажке дело, мой первоначальный вопрос актуален. В аттаче два файла: good.exe и bad.exe. good.exe попадает на адрес хендлера, и останавливается на INT3. А вот bad.exe, у которого этот код находится на аллокированной памяти, просто вылетает. Поставил, а куда дальше шагать, не знаю... RtlDispatchException, RtlCallVectoredExceptionHandlers - у меня таких OllyDbg не находит (Windows 7). Я туда заглянул, просмотрел мельком, и мне показалось, что речь о SEH в краце - а значит навряд ли написано про случай с использованием SEH с аллокированным блоком кода. Кстати, тема (theme) в том топике на скриншоте - моя любимая XP-шная тема
Он и должен вылетать. Приложение тихо завершается - обработчик генерирует исключение #BP(при исполнении Int3). Это приводит вновь к вызову обработчика, покуда весь стек доступный для треда не будет исчерпан, после чего ядро тихо завершит процесс. Это на XP, может на W7 есчо есть проверки на вхождение адреса обработчика в диапазон модуля, не смотрел. Нормальный фрейм должен содержать смещение безопасного места и регистр Ebp, для последующего восстановления его. Альтернативой является векторная обработка исключений, она быстрее и надёжнее.
bugmenot если хотите отловить момент завершения в отладчике, поставьте точки останова не только на KiUserExceptionDispatcher() но и на ZwRaiseException(). обратите внимание на третий параметр ZwRaiseException() – "NotifyFrames". если он установлен в ноль, то процесс будет завершён (после уведомления отладчика). Код (Text): KiUserExceptionDispatcher() { if (RtlDispatchException) ZwContinue(); else ZwRaiseException(); } _ struct EXCEPTION_REGISTRATION { EXCEPTION_REGISTRATION* prev; PEXCEPTION_HANDLER_PROC handler; }; блок-схема 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).
Дело в том, что до INT3 дело не доходит. catwalk_mission, спасибо за информацию! Дело в том, что я хочу осуществить запуск программы из памяти, следующим образом: Аллокирую и записываю exe файл и код в другое место, вызываю код. Этот код освобождает главный модуль - UnmapViewOfFile, на этом же месте вызывает VirtualAlloc, записывает туда exe, чинит импорты итд., и запускает. Работает отлично, кроме случаев с ошибками - они не обрабатываются. Можно попробовать сделать это все без UnmapViewOfFile и VirtualAlloc, а просто заполнить все нолями, и поставить правильные права.