Пошаговая трассировка, int1 & глюки

Тема в разделе "WASM.NT.KERNEL", создана пользователем Setevoy, 4 июл 2007.

  1. Setevoy

    Setevoy New Member

    Публикаций:
    0
    Регистрация:
    14 июл 2006
    Сообщения:
    7
    Захотел я протрассировать пошагово вызов API начиная с юзермода с переходом через колгейт и вплоть до самого низа. Для этого загрузил драйвер. Моё юзермодное приложение через DeviceIoControl вызывает его функцию, которая прописывает в IDT свой обработчик INT1, устанавливает флаг трассировки и возвращает управление. По идее мы должны были так пошагово вернуться в нашу юзермодную функцию. Но только по идее. Вызов IoCompleteRequest приводит к access violation-у. Access violation глупый - IoCompleteRequest вызывает KeInitializeApc примерно таким образом: KeInitializeApc(&pIrp->Tail.Apc,pIrp->Tail.Overlay.Thread,pIrp->ApcEnvironment,IopCompleteRequest,IopAbortRequest,0,0,0);
    при этом при трассировке &pIrp->Tail.Apc оказывается равным нулю, в результате чего далее по коду получаем
    mov word ptr [eax],12h ds:0023:00000000=????
    со всеми вытекающими. Конечно, без трассировки всё работает.

    1. Есть у кого соображения каким образом установленный флаг TF мешает нормальному исполнению программы? (трассируется чистое апи винды, никаких специальных противоотладочных трюков, протекторов и пр.)
    2. Возможно ли вообще осуществить такой трейс?

    Вот код моего обработчика:
    void __declspec( naked noreturn ) int01_handler()
    {
    __asm
    {
    push [esp]
    call next_step
    iretd
    };
    }

    void next_step( VOID* next_eip )
    {
    if ( ( KeGetCurrentIrql() == PASSIVE_LEVEL ) &&
    ( ((USHORT*)next_eip)[0] == 0x350f ) )
    {
    DbgPrint("sysexit at %08lx", next_eip);
    }
    }
     
  2. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Было бы неплохо вызывать оригинальный обработчик.. всякое бывает
     
  3. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    может так
    Код (Text):
    1. void __declspec( naked noreturn ) int01_handler()
    2. {
    3.     __asm
    4.     {
    5.         push    [esp]
    6.         call    next_step
    7.         or [esp], 0x10000
    8.         iretd
    9.     };      
    10. }
     
  4. Setevoy

    Setevoy New Member

    Публикаций:
    0
    Регистрация:
    14 июл 2006
    Сообщения:
    7
    Я так понял, имелся в виду флаг RF. Тогда должно быть не or [esp], 0x10000, а or [esp+8], 0x10000. По [esp] находится старый eip, по [esp+6] - cs, а уже по [esp+8] - EFLAGS. В нём я и попробовал только-что установить бит RF, как ты посоветовал и как пишут в интелевском талмуде. Результат точно такой же - багчек в том же месте, что и в первом моём посте. Нужно сказать, что и раньше отладка на вид происходила нормально (обработчик вызывается для вполне внятных и правдоподобных eip-ов, вроде нормально возвращается из него), а потом вылетало с багчеком. Похоже, что установка TF таки вносит какие-то изменения.

    В любом случае, большое спасибо за мысли. Может, есть ещё какие-то соображения на счёт этой проблемы?
     
  5. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    да, естественно
    прошу прощения за описку
    только тогда [esp + 6], а не [esp + 8] (CS находится по [esp + 4])
    не думаю
    а что если сделать pushad
    Код (Text):
    1. __asm
    2.     {
    3.         pushad
    4.         push    [esp]
    5.         call    next_step
    6.         or [esp + 6], 0x10000
    7.         popad
    8.         iretd
    9.     };
    да, кстати next_step() в конце делает ret 4?
     
  6. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    хех, вероятно что нет, разве что у него по дефолту стоит всем функциям конвенция stdcall
     
  7. rei3er

    rei3er maxim

    Публикаций:
    0
    Регистрация:
    15 янв 2007
    Сообщения:
    917
    Адрес:
    minsk
    гы
    тогда понятно :))
     
  8. Setevoy

    Setevoy New Member

    Публикаций:
    0
    Регистрация:
    14 июл 2006
    Сообщения:
    7
    Флаг RF ничего не дал. Насколько я понял, он нужен на тот случай, когда одна и та же комманда попадает под отладку по нескольким условиям, скажем когда комманда int 1 исполняется с установленным TF.
    Конвенция была действительно stdcall по дефолту.
    Проблема была с регистрами - я просто не учёл , что компилер не сохраняет значение eax в прологе, даже если функция объявлена как возвращающая void. И не только eax, кстати. Так что за подсказку, мужики, спасибо большущее.

    Теперь следующая проблема - конструкция та же, INT 1 перехвачен, TF установлен НО EIP уже в юзермоде, то есть уже изменяется уровень привилегий.
    Что получается - попадаем в обработчик, корректно проходим обработчик, но, очевидно, после IRETD имеем

    Код (Text):
    1. *** Fatal System Error: 0x0000007f
    2.                        (0x0000000D,0x00000000,0x00000000,0x00000000)
    причём WinDbg при анализе показывает, что

    Код (Text):
    1. FAULTING_SOURCE_CODE:  
    2.     81: void next_step( VOID* next_eip )
    3.     82: {
    4.     83:     LARGE_INTEGER sleep_time;
    5.     84:  
    6. >   85:     DbgPrint("[hillo] step at %08lx\n", next_eip);        
    7.     86:
    8.     87:     sleep_time.QuadPart = (LONGLONG)SECONDS(0.1);
    9.     88:     KeDelayExecutionThread( KernelMode, FALSE, &sleep_time );
    что не есть правдой, т.к эти комманды были успешно пройдены - я расставил по всей функции int 3. Пошагово пройти функцию я, разумеется, не могу, т.к. сам же перехватил int 1.

    Код (Text):
    1. void next_step( VOID* next_eip )
    2. {
    3.     LARGE_INTEGER sleep_time;
    4.  
    5.     DbgPrint("[hillo] step at %08lx\n", next_eip);        
    6.  
    7.     sleep_time.QuadPart = (LONGLONG)SECONDS(0.1);
    8.     KeDelayExecutionThread( KernelMode, FALSE, &sleep_time );
    9.  
    10.     if ( (ULONG)next_eip == 0x8053c91d )
    11.     {
    12.         DbgPrint("[hillo] break at popfd\n", next_eip);        
    13.         __asm  int 3;
    14.     }
    15. }
    16.  
    17. void
    18. __declspec( naked noreturn ) int01_handler()
    19. {
    20.     __asm
    21.     {
    22.         push    ebp
    23.         mov     ebp, esp
    24.  
    25.         push    eax
    26.         push    ebx
    27.         push    ecx
    28.         push    edx
    29.         push    esi
    30.         push    edi
    31.  
    32.         push    [ebp+4]         // EIP
    33.  
    34.         call    next_step
    35.  
    36.         pop     edi
    37.         pop     esi
    38.         pop     edx
    39.         pop     ecx
    40.         pop     ebx
    41.         pop     eax
    42.  
    43.         pop     ebp
    44.  
    45.         iretd                        
    46.     };        
    47. }
    Догадываюсь, что не сделал чего-то перед iretd-ом, но что... Гугл ничего не дал, дизасм нтоскернелевского _KiTrap01 тоже пока ничего.

    Может у вас будут какие-то мысли по этому поводу?
     
  9. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    fs не сменил.
     
  10. rav

    rav New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2004
    Сообщения:
    159
    Адрес:
    Москва
    Ага, а ещё не перенастроил es,ds,ss...