# bug в Olly

Тема в разделе "WASM.HEAP", создана пользователем kaspersky, 20 апр 2008.

  1. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    нашел в Olly неприятный баг. при трассировке SEH/VEH программ в момент генерации исключения в регистровый контекст попадает EFlags со взведенным битом TF, который Olly "забывает" вычистить, в результате чего, после выхода из SEH/VEH обработчика флаг трассировки оказывается взведен и генерируется отладочное прерывание, передаваемое в отлаживаемую программу, в результате чего SEH/VEH обработчик вызывается еще раз, что в общем случае приводит к краху программы.

    решение: в момент генерации исключения "вычистить" TF-бит из регистрового контекста, переданного функции диспетчеризации исключений, в которой Olly оказывается по Shift-F7/F8
     
  2. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Столкнулся с подобной проблемой в отладчике IDA. В ней, в процессе манипуляции с флагами, при выполнении pushf в стек заносится flags с установленным TF, несомотря на то, что в flags TF в этот момент не установлен. Причем, как ни странно, если участок кода выполняется не пошагово, такой проблемы не возникает.
     
  3. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    Mika0x65
    ничего странного нет, при непошаговом выполнении TF не взведен. у ИДЫ это не баг, а misfeature, что позволяет защите задетектить трассировку, но не ведет (в отличие от Olly) к краху отлаживаемой (незащищенной!!!) программы. согласитесь, это несколько разные вещи ;)
     
  4. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Вообще-то в моем случае это вело к краху отлаживаемой программы.
     
  5. rain

    rain New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2006
    Сообщения:
    976
    kaspersky это баг windows, проявляется ещё при мутках с SetThreadContext, когда ставишь флаг трассировки, а он начинает трассироваться с другого места
     
  6. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    rain
    ага, во всех проблемах форточки виноваты, нашли крайних. взводить флаг трассировки с помощью SetThrContext вообще не самая лучшая идея, особенно если поток не "заморожен". но это ладно. вернемся к Olly.

    при трассировке программы TF-бит ес-но взведен и отладчику посылается отладочное исключение, которое он обрабатывает, не передавая его в отлаживаемую программу, но вот при генерации исключения (любого) внутри самой программы первой user-land функцией, получающей управление, будет NTDLL.DLL!KiUserExceptionDispatcher, вызываемая из ядра и получающая регистровый контекст. флаг трассировки сбрасывается ядром и функция спокойно вызывает SEH/VEH обработчик, назначенный программистом, по выходу из которого восстанавливается регистровый контекст, соответствующий состоянию ЦП на момент генерации исключения. со взведенным TF-битом, в результате чего выполнение следующей команды приводит к генерации отладочного исключения, которое Olly ловит, но, поскольку, он не помнит, чтобы он ставил бит трассировки, то он передает это исключение в программу, что приводит к повторному вызову SEH/VEH обработчика. при более-менее корректно написанном SEH/VEH обработчике мы просто зациклившемся, а при некорректном - получаем крах (например, обработчик ловит исключение возникающее при выполнении xor eax,eax/mov eax,[eax] и тупо увеличивает EIP на два, не проверяя кода исключения).

    это баг Olly. он должен помнить, что после возврата из обработчика трассировочное прерывание принадлежит ему, а не программе ;)
     
  7. rain

    rain New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2006
    Сообщения:
    976
    сори за отступление от темы
    Вот пример. Для старта трейса создаётся новый процесс (который будем трейсить) с флагом CREATE_SUSPENDED, затем через GetThreadContext\SetThreadContext устанавливается в контексте треда флаг TF. Особенность в том что когда мы вызываем ResumeThread то, мы получаем Single Execution Exception НЕ после той инструкции которая шла за EIP который был в GetThreadContext\SetThreadContext а за первой инструкцией KiUserApcDispatcher. Чем это объясняется? Что предлагается в замен менять EIP на заглушки с popfd?

    Касательно той проблемы о которой топик то, похоже мы говорим о разных вещах, скажу прямо для мну олли не представляет большого интереса. Но баг имеет место бы следующего плана.
    здесь не ясно в какой именно контекст, тот контекст который текущий и текущий eflags или тот который передаётся на стеке? При определённых условиях можно заметить тот факт что мы ловим трап по TF на KiUserExceptionDispatcher.
    например так:
    Код (Text):
    1.     pushfd
    2.     or dword ptr [esp], 100h
    3.     popfd
    4.     int 3
    5.         nop
    6.         nop
    Отбросим олик и посмотрим сколько сехов вызовет такой код? На всех х86 системах у мну 3 бряка (wow64 не берём там правильно и поэтому защитные механизмы не могут юзать эту особенность). Бряки по адресам 0x7C90EAF0 - ntdll!KiUserExceptionDispatcher+0x4, 0x00401256 - адрес int 3 и 0x00401258 адрес второго нопа. пример и бинарник в атаче.

    Проверил только что под оликом(без трейса) -- результаты идентичны. А как заставить олик при трейсе на int 3 генерировать исключение посылая его программе?

    upd:
    с трейсом по shift - f7 результаты теже
     
  8. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    rain
    > Для старта трейса создаётся новый процесс
    > с флагом CREATE_SUSPENDED, затем через
    > GetThreadContext\SetThreadContext устанавливается
    > в контексте треда флаг TF. Особенность в том что
    > когда мы вызываем ResumeThread то, мы получаем
    > Single Execution Exception НЕ после той инструкции
    > которая шла за EIP который был в GetThreadContext\
    >SetThreadContext а за первой инструкцией KiUserApcDispatcher.
    > Чем это объясняется?
    это объясняется особенностями реализации процедуры разморозки потока. если взглянуть на функцию KiUserApcDispatcher, то мы увидим следующее:

    Код (Text):
    1. .text:77F91B8C                 public KiUserApcDispatcher
    2. .text:77F91B8C KiUserApcDispatcher proc near
    3. .text:77F91B8C
    4. .text:77F91B8C arg_C           = dword ptr  10h
    5. .text:77F91B8C
    6. .text:77F91B8C                 lea     edi, [esp+arg_C]
    7. .text:77F91B90                 pop     eax
    8. .text:77F91B91                 call    eax
    9. .text:77F91B93                 push    1
    10. .text:77F91B95                 push    edi
    11. .text:77F91B96                 call    ZwContinue
    12. .text:77F91B9B                 nop
    13. .text:77F91B9B KiUserApcDispatcher endp
    на момент выполнения KiUserApcDispatcher (вызываемой из ядра), регистр флагов уже восстановлен и флаг трассировки взведен. далее она выталкивает из стека Stack ntdll.LdrInitializeThunk, которая мотает LdrQueryImageFileExecutionOptions и после выхода из нее, KiUserApcDispatcher вызывает ZwContinue, "ныряющую" в ядро, где уже полностью восстанавливается контекст потока и поток получает управление.

    что удивительного в том, что ResumeThread реализована как асинхронная процедура?! что же касается восстановления регистра флагов _до_ передачи управления на EIP потока, то это сделано умышленно, чтобы user-level отладчики могли трассировать user-land код. поскольку, у потока есть только один контекст, то... по-другому просто не получается.

    а какие проблемы отловить исключение в обработчике и пропускать его до тех пор, пока мы не дойдет до обозначенного EIP?


    > Что предлагается в замен менять EIP на заглушки с popfd?
    взводить флаг трассировки из SEH/VEH обработчика. хотя это тоже не идеальный вариант.

    > здесь не ясно в какой именно контекст, тот контекст который текущий
    > и текущий eflags или тот который передаётся на стеке?
    тот контекст (набор регистров и флагов), который имеет место быть у потока в момент выполнения инструкции, вызывающей исключение

    > При определённых условиях можно заметить тот факт что мы ловим
    > трап по TF на KiUserExceptionDispatcher.
    вообще-то при любом исключении мы поймаем на ней трап, если мы, конечно, ее трапаем. скажем там. KiUserExceptionDispatcher - это первая user-land функция, получающая управление после начальной обработки исключения ядром, и она уже в свою очередь смотрит какие у нас SEH/VEH обработчики установлены и какие из них вызывать.

    Код (Text):
    1. > pushfd
    2. > or dword ptr [esp], 100h
    3. > popfd
    4. > int 3
    5. > nop
    > Отбросим олик и посмотрим сколько сехов вызовет такой код?
    три, конечно. первый на int 03 (само int 03 его и вызывает), два других трассировочные прерывания. тут правда не ясно как ты сбрасываешь TF флаг, т.к. за последним nop что-то должно быть расположено ;) ну ладно, бум считать, что ты сбрасываешь TF-флаг из ыур-обработчика.

    > А как заставить олик при трейсе на int 3
    > генерировать исключение посылая его программе?
    ALT-O, Exceptions, Ignore (pass to program) following exceptions: INT 3 break и все будет ок.

    > с трейсом по shift - f7 результаты теже
    что и следовало ожидать.
     
  9. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    мне это понравилось)
     
  10. rain

    rain New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2006
    Сообщения:
    976
    ну так собсно и было, но мне кажется это не тру, при многопоточности скорее всего такой трейсер можно будет поимёть её хуком
    дык его сначала нужно как-то вызвать и установть в трассируемом процессе, нафиг такое счастье
    мы её специально не трапаем
    посмотри пример, в сехе если не установить явно в контексте на стеке TF он сам сбросится и больше трапаться не будет.

    Глянь где произошли сами бряки в предидущем моём посте, один там явно лишний, если ты считаешь такое поведение правельным, то почему тогда на вов64 только два?)
     
  11. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    можно автору было написать или попробовать тут отпостится http://www.woodmann.com/forum/forumdisplay.php?f=37
     
  12. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    Asterix
    мыщъх не по уши деревянный. отписал автору olly на мыло. кстати, не первый раз уже. и все безрезультатно. мне в принципе все равно. пофиксить этот баг можно даже без написания собственного плагина: http://souriz.wordpress.com/2008/04/23/a-new-bug-in-olly-776/
    в любом случае, даже если баг будет пофиксен в 2.xx - фигли толку? народ юзает 1.xx и еще долго будет юзать и полезно знать как бороться с багами. кстати, ни soft-ice, ни ms visual studio/ms windbg такого бага не имеют, так что не нужно говорить, что это винда кривая такая ;) когда я только начинал изучать Win Dbg API (а это было лет ~10 тому назад), то быстро столкнулся с этой проблемой при написании экспериментального отладчика (типа "макетника") и так же быстро решил ее, передавая INT 01h программе только когда был совершенно уверен, что это она его взвела, а не я, в смысле не отладчик.
     
  13. kaspersky

    kaspersky New Member

    Публикаций:
    0
    Регистрация:
    18 май 2004
    Сообщения:
    3.006
    баг признан багом и бу скоро исправлен. ждем-с!

    # Dear Kris,
    # thank you for your bug report. I will try to remove it from v2.0 ASAP.
    # Sincerely, Olly