[BSOD] Перехват и обработка INT3

Тема в разделе "WASM.NT.KERNEL", создана пользователем UnameR, 24 фев 2011.

  1. UnameR

    UnameR New Member

    Публикаций:
    0
    Регистрация:
    28 дек 2010
    Сообщения:
    4
    Приветствую всех.

    Пробую перехватывать прерывания(IDT), хук работает, но вот с обработкой проблемы.
    Вот такой код работает отменно:
    Код (Text):
    1. ULONG i = 0;
    2. __declspec( naked ) void int3New()
    3. {
    4.     __asm inc [i];
    5.     __asm jmp int3_old;
    6. }
    Счетчик считает, с этим проблем нет.

    Но вот хочется, чтобы при каждом INT3 выводилось сообщение в лог DbgView
    Делаю так:
    Код (Text):
    1. __declspec( naked ) void int3New()
    2. {
    3.     __asm pushad
    4.     __asm pushfd
    5.  
    6.     DbgPrint("INT3");
    7.  
    8.     __asm popfd
    9.     __asm popad
    10.     __asm jmp int3_old;
    11. }
    Тут уже начинаются проблемы. Если выполнить INT3 единожды, то все ок, сообщение есть, система "живёт".
    Но если поставить сразу два(и больше) прерывания подряд и пустить по ним прогу появляется бсод.

    Как я уже только не пробывал. Вот один из последних вариантов:
    Код (Text):
    1. __declspec( naked ) void int3New()
    2. {
    3.      __asm
    4.     {
    5.         cli
    6.         pushad
    7.         pushfd
    8.         mov eax, cr0
    9.         mov CR0Reg, eax
    10.         and eax, 0xFFFEFFFF      
    11.         mov cr0, eax
    12.     }
    13.  
    14.     __asm inc [i];
    15.     DbgPrint("INT3");
    16.  
    17.     __asm
    18.     {
    19.         mov eax, CR0Reg    
    20.         mov cr0, eax
    21.         popfd
    22.         popad
    23.         sti                    
    24.     }
    25.     __asm jmp int3_old;
    26. }
    Смотрел краш-дампы. Крах из-за доступа в память, куда не было доступа.

    Один из анализов краш-дампа(их много тк было много разных вариантов, взял один из последних):
    Код (Text):
    1. MODULE_NAME: TEST1
    2.  
    3. FAULTING_MODULE: 804d7000 nt
    4.  
    5. DEBUG_FLR_IMAGE_TIMESTAMP:  4d662055
    6.  
    7. EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - <Unable to get error code text>
    8.  
    9. FAULTING_IP:
    10. nt+79a4
    11. 804de9a4 e9c7a03677      jmp     f7848a70
    12.  
    13. TRAP_FRAME:  b2c83cf0 -- (.trap 0xffffffffb2c83cf0)
    14. ErrCode = 00000000
    15. eax=b2c83da8 ebx=7ffde000 ecx=00000000 edx=00000001 esi=00291f18 edi=00291ea4
    16. eip=804de9a4 esp=b2c83d64 ebp=b2c83d64 iopl=0         nv up ei pl nz na po nc
    17. cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000202
    18. nt+0x79a4:
    19. 804de9a4 e9c7a03677      jmp     f7848a70
    20. Resetting default scope
    21.  
    22. CUSTOMER_CRASH_COUNT:  26
    23.  
    24. DEFAULT_BUCKET_ID:  COMMON_SYSTEM_FAULT
    25.  
    26. BUGCHECK_STR:  0x8E
    27.  
    28. LAST_CONTROL_TRANSFER:  from 804e2440 to 804de9a4
    29.  
    30. STACK_TEXT:  
    31. WARNING: Stack unwind information not available. Following frames may be wrong.
    32. b2c83d64 804e2440 badb0d00 00000001 804e2490 nt+0x79a4
    33. b2c83d9c f8bc64e2 f8bc6690 b2c83da8 00291e01 nt+0xb440
    34. b2c83da0 f8bc6690 b2c83da8 00291e01 00291f18 TEST1+0x4e2
    35. b2c83da4 b2c83da8 00291e01 00291f18 0012fc94 TEST1+0x690
    36. b2c83da8 00291e01 00291f18 0012fc94 b2c83dcc 0xb2c83da8
    37. b2c83dac 00291f18 0012fc94 b2c83dcc 7ffde000 0x291e01
    38. b2c83db0 0012fc94 b2c83dcc 7ffde000 00000001 0x291f18
    39. b2c83db4 b2c83dcc 7ffde000 00000001 00000000 0x12fc94
    40. b2c83db8 7ffde000 00000001 00000000 00291ea4 0xb2c83dcc
    41. b2c83dcc 00000000 00000302 0012fb20 00000023 0x7ffde000
    42.  
    43. STACK_COMMAND:  kb
    44.  
    45. FOLLOWUP_IP:
    46. TEST1+4e2
    47. f8bc64e2 ??              ???
    48.  
    49. SYMBOL_STACK_INDEX:  2
    50.  
    51. SYMBOL_NAME:  TEST1+4e2
    52.  
    53. FOLLOWUP_NAME:  MachineOwner
    54.  
    55. IMAGE_NAME:  TEST1.sys
    56.  
    57. BUCKET_ID:  WRONG_SYMBOLS
    58.  
    59. Followup: MachineOwner
    0x0000008E = KERNEL_MODE_EXCEPTION_NOT_HANDLED
    0xC0000005 = STATUS_ACCESS_VIOLATION

    Собственно проблема понятна, за раз обращение к одному адресу несколькими потоками.
    Пробовал создавать строку с фразой INT3 динамически(вызывая другую функцию естественно). (char text[4];test[0] = 'I';...;..;)
    Но ничего не изменилось.

    Буду рад советам или если предложите почитать что-то про мою проблему.
    Я только пробую все это дело, сильно не пинайте, если упустил или не сообщил что-то. Все чисто на энтузиазме и только для себя.

    Тестирую под ВМ(VirtualBox последний) с системой WinXP SP3. Система "чистая". На хосте 2 проца, в ВМ используется 1.
     
  2. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    срочно уберите этот лютый пипец)

    pushfd не требуется.
    а вот сохранять сегменты не помешало бы + перегружать fs.

    залей минидамп, я ничего не понял из твоего поста
     
  3. UnameR

    UnameR New Member

    Публикаций:
    0
    Регистрация:
    28 дек 2010
    Сообщения:
    4
    Краш-дамп от этого кода:
    Код (Text):
    1. __declspec( naked ) void int3New()
    2. {
    3.     __asm
    4.     {
    5.         cli
    6.         pushad
    7.     }
    8.  
    9.     __asm inc [i];
    10.     DbgPrint("INT3");
    11.  
    12.     __asm
    13.      {
    14.         popad
    15.         sti                    
    16.     }
    17.     __asm jmp int3_old;
    18. }
    Расскажите пожалуйста поподробней про
    За ужастный код мне очень стыдно, пробую все что попадается:)
    Но на ошибках учатся)
     
  4. Mika0x65

    Mika0x65 New Member

    Публикаций:
    0
    Регистрация:
    30 июл 2005
    Сообщения:
    1.384
    UnameR
    Манипуляции с cr0 не нужны. В fs должен лежать селектор 0x30, его следует установить в прологе. Там же сохранить сегментные регистры. Т.е. что-то вроде:

    Код (Text):
    1. push ds
    2. push es
    3. push fs
    4. push gs
    5. mov ax, 0x30
    6. mov fs, ax
    Ну а в эпилоге это все надо восстановить.
     
  5. Ladr

    Ladr New Member

    Публикаций:
    0
    Регистрация:
    28 мар 2009
    Сообщения:
    17
    А если попрбовать выводить дебаг инфу в спец системном потоке через глобальный буфер не забывая о синхранизации. Вместо DbgPrint("INT3") записывать данные в память. В другом спец потоке считывать эти данные и выводить. Такой путь хоть и более сложный но видется более надежным.
     
  6. UnameR

    UnameR New Member

    Публикаций:
    0
    Регистрация:
    28 дек 2010
    Сообщения:
    4
    Да, это именно то, что было нужно. Благодарю.

    Задача не требует надёжности, это для себя. Все в подконтрольной среде, поэтому даже если и будет иногда вызывать крахи, это не страшно. Мне чисто для наблюдений :)

    Тема исчерпана. Всем спасибо.
     
  7. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Вообще, в Windows специально предусмотрены особые стабы, в которые оборачиваются обработчики прерываний, чтобы при передачах управления user->kernel корректно создавались бы трап фреймы, иначе вот велики шансы получить самые разнообразные бсоды из-за кучи различных особенностей и подводных камней.
    Чтобы корректно создавался трап фрейм, обработчик должен быть установлен не вручную, а через IoConnectInterrupt() (возможно, придется установить его на свободный рандомный вектор, а потом вручную переставить на третий).
    Только такая установка может гарантировать, что управление попадет в ваш обработчик только после корректного входа в ядро, а после окончания будет произведен корректный возврат через Kei386EoiHelper. И что в любой момент управление сможет быть корректно прервано по таймеру, контекст сохранён, а поток переключен на любой другой. Тогда и прерывания можно будет включить.