Перехват KiTrap0E в IDT

Тема в разделе "WASM.NT.KERNEL", создана пользователем Mika0x65, 14 ноя 2010.

  1. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Мое почтение всем.

    Ради интереса и практики перехватываю KiTrap0E в IDT. Через некоторое время (а иногда сразу) получаю различные BSoD'ы. Т.е. что-то не учел. Сначала я сохраняю используемые регистры, затем копирую eip, cs и eflags в глобальный массив и подменяю cs:eip на адрес в своем коде. Затем вызываю оригинальный обработчик, и когда он выполняет iretd, снова получаю управление. Возвращаю оригинальные eip, cs и eflags в стек и делаю iretd.

    Код (Text):
    1. __declspec(naked) VOID HookFunc()
    2. {
    3.     __asm
    4.     {
    5. ;KTRAP_FRAME еще не сохранен, регистры менять нельзя.
    6.         push ecx
    7.         push ds
    8.         mov cx, 0x23
    9.         mov ds, cx ;теперь можно обращаться к данным через ds.
    10.         mov ecx, dword ptr [esp]
    11.         mov word ptr [DsArea], cx
    12.         mov ecx, [esp + 4]
    13.         mov dword ptr [EcxArea], ecx
    14.         add esp, 0x8
    15.         mov cx, es
    16.         mov word ptr [EsArea], cx
    17.         mov cx, 0x23
    18.         mov es, cx
    19.         mov dword ptr [EsiArea], esi
    20.         mov dword ptr [EdiArea], edi
    21. ;Регистры сохранены, копируем оригинальные eip, cs и eflags.
    22.         cld
    23.         lea esi, dword ptr [esp + 4]
    24.         lea edi, dword ptr [IretAddr]
    25.         mov ecx, 3
    26.         rep movsd
    27.         mov ecx, label
    28.         mov dword ptr [esp + 4], ecx
    29.         mov dword ptr [esp + 8], 8
    30. ;Восстанавливаем регистры.
    31.         push dword ptr [EcxArea]
    32.         mov esi, dword ptr [EsiArea]
    33.         mov edi, dword ptr [EdiArea]
    34.         mov cx, [EsArea]
    35.         mov es, cx
    36.         mov cx, [DsArea]
    37.         mov ds, cx
    38.         pop ecx
    39.  
    40.         jmp [PrevKiTrap0E]
    41. label:
    42. ;KTRAP_FRAME восстановлен, регистры менять нельзя. Сохраняем регистры.
    43.         push ecx
    44.         push ds
    45.         mov cx, 0x23
    46.         mov ds, cx
    47.         mov ecx, dword ptr [esp]
    48.         mov word ptr [DsArea], cx
    49.         mov ecx, [esp + 4]
    50.         mov dword ptr [EcxArea], ecx
    51.         add esp, 0x8
    52.         mov cx, es
    53.         mov word ptr [EsArea], cx
    54.         mov cx, 0x23
    55.         mov es, cx
    56.         mov dword ptr [EsiArea], esi
    57.         mov dword ptr [EdiArea], edi
    58. ;Выделяем место в стеке, копируем оригинальные eip, cs и eflags.
    59.         cld
    60.         sub esp, 0xC
    61.         mov edi, esp
    62.         lea esi, [IretAddr]
    63.         mov ecx, 3
    64.         rep movsd
    65. ;Восстанавливаем регистры.
    66.         push dword ptr [EcxArea]
    67.         mov esi, dword ptr [EsiArea]
    68.         mov edi, dword ptr [EdiArea]
    69.         mov cx, [EsArea]
    70.         mov es, cx
    71.         mov cx, [DsArea]
    72.         mov ds, cx
    73.         pop ecx
    74. ;Jump home.
    75.         iretd
    76.     }
    77. }
    Что я не учел в своем коде? Проверял в отладчике, значение регистров на входе и выходе в обработчик не изменяются. Однако все равно валится, помогите найти проблему.

    Заранее благодарен.

    P.S. Я знаю про более простые способы перехвата, но хочется понять, в чем ошибся.
     
  2. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Система многопроцессорная/многоядерная?
    Какие бсоды? Хотя бы один пример с выводом !analyze -v

    И вообще, код по вызову оригинального обработчика очень кривой.
     
  3. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Great
    Два ядра (дело происходит в VM). !analyze -v предоставлю чуть позже.

    А что именно криво в коде?

    ADD:
    --
    А, подозреваю, тебе не понравились манипуляции в стеке в коде сохранения регистров. Проблема в том, что я не могу обращаться к данным через ds/es. Можно переделать на обычные mov'ы относительно ss, но как-то я об этом не подумал, когда писал.
     
  4. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Лень разбираться, но предположу что код ошибки не удаляется со дна стека. Если бы сразу вызывался системный ISR, то всё былобы тру, иначе в стеке лишний дворд.
    В любом случае необходимо сформировать трап-фрейм, иначе размаскировать прерывания вы не можите.
     
  5. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Clerk
    Я бы увидел в отладчике лишний dword. В любом случае, код ошибки выталкивает ориганальный обработчик -- KiTrap0E. А зачем KTRAP_FRAME? Моя iretd восстановит значение eflags, в котором IF будет установлен.

    Итак, при запуске моего драйвера происходит исключение в lsass.exe:

    Кроме того, создать свой KTRAP_FRAME и вызвать KiTrap0E не получится, т.к. стек должен быть чист на момент выполнения KiTrap0E. Сама KiTrap0E делает нечто в этом роде:

    if (esp - fs:[_NT_TIB.StackBase] + 0x8C != 0)
    Создать два KTRAP_FRAME, один из которых указывает на KiServiceExit2.

    А второй KTRAP_FRAME перетрет сохраненный мной контекст. В итоге, я решил сохранить cs:eip & eflags в глобальной переменной, чтобы не держать их в стеке и подменять адрес возврата, созданный процессором на свой.
     
  6. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Mika0x65
    Ваш код в общем верный, проверил каждую инструкцию. Но проблема в флажках. Вы не маскируете IF. Тоесть ваш Post' хэндлер получит управление с IF, а должен с !IF. Если вы замаскируете IF, то ISR #PF приведёт к багчеку, так как проверяет IF.
     
  7. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Так, давай по шагам.

    К примеру возьмем переход из user mode.
    1. IF установлен, прерывания разрешены.
    2. Происходит #PF. Процессор сохраняет в стеке ядра eflags, cs, eip и сбрасывает IF. Прерывания запрещены.
    3. Вызвается мой обработчик. Он меняет eflags, но не трогает IF. Прерывания запрещены.
    4. Вызвается код KiTrap0E. что там с прерываниями происходит я не знаю.
    5. KiTrap0E выполняет iretd. IF восстанавливается, прерывания разрешены.
    6. Выполняется мой код. Прерывания разрешены.
    7. Мой код выполняет iretd повторно восстанавливая eflags. Прерывания разрешены.

    Когда и где надо сбросить/установить IF? И надо ли вообще? Кроме того, ошибка происходит в user mode, предположительно, в ntdll. Судя по всему, я все же что-то испортил в контексте, но не пойму что.
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    6. Fail.
     
  9. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Отвечу также кратко:

    6. Почему?
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Говорил же что нельзя размаскировать прерывания без формирования трап фрейма. Да и вобще возможна рассинхронизация, пока первый процессор будет хэндлить фолт, возникающий на другом затрёт сохранённые в переменных регистры. И загружать ядерный селектор нельзя, этим вы меняете прев. мод. Вобще так не делается, всё наперекосяк.
     
  11. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Подумав я совсем не вижу решения, разве что скопировать себя весь код ISR с нулевым NL(без раскрытия процедур). Это перестройка графа, всё тотже морфинг(его частный случай).
     
  12. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Mika0x65
    Да, я тоже сразу заметил, что KiTrap0E восстановит IF в еденицу и кранты вам)
    первое же прерывание таймера (да и вообще любое) все угробит, т.к. нет сформированного треп-фрейма
     
  13. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Great
    Clerk
    Все равно не улавливаю. Допустим, выполняется мой код (который после вызова оригинального обработчика), прерывания разрешены. Происходит прерывание, например, того же таймера. Обработчик прерывания таймера сохранит контекст в свой KTRAP_FRAME и восстановит контекст по выходу. Почему все должно угробиться?

    В принципе, как вариант, я могу изменить eflags, сохраненный процессором в стеке -- сбросить IF. Все равно у меня есть копия eflags в глобальной переменной, откуда eflags можно восстановить, выполняя мою iretd. Сегодня попробую так сделать.
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Mika0x65
    Для всех прерываний стек общий и загружается он при вызове шлюза(смене кпл на нулевой). Тоесть предыдущий стек будет затёрт и после возврата управление будет передано вникуда. Тут наверно иные проблемы могут быть, так как стек не переключается. Задача не сформирована, всякая попытка шедулера и прочего механизма разрулить поток приведёт к краху. Это нарушение общей архитектуры NT.
     
  15. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    О, это интересно. Получается, что IF должен быть сброшен все время, пока работает обработчик прерывания. Тогда попробую сбросить IF в eflags, который в стеке. А когда сам буду делать iretd, верну eflags на место.
     
  16. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Mika0x65
    Если вы сбросите IF, то менеджер памяти будет считать что фолт произошёл на высочайшем IRQL, это незамедлительно приведёт к багчеку с кодом IRQL_NOT_LESS_OR_EQUAL.
     
  17. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    Получается, без серьезных модификаций это сделать невозможно. В принципе, можно поколдовать с PIC'ами, чтобы запретить прерывания не с помощью IF, но пока, наверное, оставлю. Спасибо за разъяснения.
     
  18. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    > Если вы сбросите IF, то менеджер памяти будет считать что фолт произошёл на высочайшем IRQL, это незамедлительно приведёт к багчеку с кодом IRQL_NOT_LESS_OR_EQUAL.

    дык откуда он узнает об этом?
    если if сброшен-то.
     
  19. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    n0name
    Насколько я понимаю, обработчик смотрит в стек. На всякий случай решил проверить. Добавил and 'dword ptr [esp + 8], 0xFFFFFDFF' перед 'cld'. Получил:

    На этом участке кода:
    Код (Text):
    1. f7ba9652 668b0dae9fbaf7  mov     cx,word ptr [rk!DsArea (f7ba9fae)]
    2. f7ba9659 668ed9          mov     ds,cx
    3. f7ba965c 59              pop     ecx
    4. f7ba965d ff25b09fbaf7    jmp     dword ptr [rk!PrevKiTrap0E (f7ba9fb0)]
    5. f7ba9663 51              push    ecx ;<---------Exception!
    6. f7ba9664 1e              push    ds
    7. f7ba9665 66b92300        mov     cx,23h
    8. f7ba9669 668ed9          mov     ds,cx
    Во-первых, получается, что обработчик все же выполнился без BSoD'а, во-вторых -- откуда там взяться исключению? Значение esp весьма легально:

    esp=eebc0dd8
    eebc0dd8: 0081fd70 00000023 00000000 00000000

    В стеке лежат ss:esp из user mode.

    Что происходит? :)
     
  20. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    n0name
    Считает со стека:
    Код (Text):
    1. _KiTrap0E       proc
    2.  
    3.         ENTER_TRAP      kite_a, kite_t
    4.  
    5.  
    6. if FAST_BOP
    7.         cmp     dword ptr PCR[PcVdmAlert], 0
    8.         jne     Kt0eVdmAlert
    9. endif
    10.  
    11.         MODIFY_BASE_TRAP_FRAME
    12.  
    13.         mov     edi,cr2
    14. ;
    15. ; Now that everything is in a sane state check for rest of the Pentium
    16. ; Processor bug work around for illegal operands
    17. ;
    18.  
    19.         cmp     _KiI386PentiumLockErrataPresent, 0
    20.         jne     PentiumTest              ; Check for special problems
    21.  
    22. NoPentiumFix:                            ; No.  Skip it
    23.         sti
    24.  
    25.  
    26.         test    [ebp]+TsEFlags, EFLAGS_INTERRUPT_MASK   ; faulted with
    27.         jz      Kt0e12b                 ; interrupts disabled?