Помогите разобраться c прологом для call gate

Тема в разделе "WASM.NT.KERNEL", создана пользователем AntiFreeze, 22 окт 2009.

  1. AntiFreeze

    AntiFreeze Дмитрий

    Публикаций:
    0
    Регистрация:
    26 июн 2008
    Сообщения:
    65
    Итак, Call gate установлен и имеет один параметр. При входе в обработчик стек выглядит так:
    Ss
    Esp
    Param
    Cs
    Eip <- Current ESP

    Сам обработчик (смещения для _KTHREAD.TrapFrame и _KTHREAD.PreviousMode hardcoded для XP build 2600, не обращаем внимания):
    Код (Text):
    1. __asm
    2. {
    3.     /// На входе в Call Gate прерывания разрешены, поэтому
    4.     cli            
    5.  
    6.     /// Формируем TRAP_FRAME и попутно настраиваем сегментные регистры
    7.     push dword ptr [ esp + 0x10 ]    /// _KTRAP_FRAME.SegSs
    8.     push dword ptr [ esp + 0x10 ]    /// _KTRAP_FRAME.Esp
    9.     pushfd
    10.     pop  eax
    11.     and  eax, 0xFFFCFFFF             /// Сбрасываем EFLAGS_VM и EFLAGS_RF
    12.     or   eax, 0x00000200             /// Устанавливаем EFLAGS_IF
    13.     push eax                         /// _KTRAP_FRAME.Eflags
    14.     push dword ptr [ esp + 0x10 ]    /// _KTRAP_FRAME.SegCs
    15.     push dword ptr [ esp + 0x10 ]    /// _KTRAP_FRAME.Eip
    16.     push 0                           /// _KTRAP_FRAME.ErrCode
    17.     push ebp                         /// _KTRAP_FRAME.ebp
    18.     push ebx                         /// _KTRAP_FRAME.ebx
    19.     push esi                         /// _KTRAP_FRAME.esi
    20.     push edi                         /// _KTRAP_FRAME.edi
    21.     push fs                          /// _KTRAP_FRAME.SegFs
    22.  
    23.     /// Настраиваем fs
    24.     mov  bx, 0x30                    /// GDT_SELECTOR_R0_PCR
    25.     mov  fs, bx
    26.        
    27.     sub  esp, 0x14                   ///  не заполняем _KTRAP_FRAME.ExceptionList (пока), .PreviousPreviousMode, .eax, .ecx, .edx
    28.     push ds                          /// _KTRAP_FRAME.SegDs
    29.     push es                          /// _KTRAP_FRAME.SegEs
    30.     push gs                          /// _KTRAP_FRAME.SegGs
    31.  
    32.     /// Настраиваем ds, es
    33.     mov bx, 0x23                     /// KGDT_R3_DATA or RPL_MASK
    34.     mov ds, bx
    35.     mov es, bx
    36.  
    37.     sub  esp, 0x30                   ///  выделяем остаток памяти под frame
    38.     mov  ebp, esp                    ///  ebp <- Trap Frame
    39.  
    40.     /// Сбрасываем все ненужные флаги
    41.     push 2
    42.     popfd            
    43.  
    44.     /// Сбрасываем Dr7, отладочные регистры в Trap Frame не сохраняем
    45.     xor eax, eax
    46.     mov Dr7, eax
    47.  
    48.     /// Exception list
    49.     push dword ptr fs:[0]          
    50.     mov  dword ptr fs:[0], 0xFFFFFFFF
    51.     pop  dword ptr [ebp + 0x4C]
    52.  
    53.     /// Устанавливаем _KTRAP_FRAME в _KTHREAD
    54.     mov ebx, dword ptr fs:[0x124]
    55.     mov dword ptr [ebx + 0x134] ,ebp
    56.  
    57.     /// Устанавливаем PreviousMode в _KTHREAD
    58.     mov byte ptr  [ebx + 0x140], 1
    59.  
    60.     /// Разрешаем прерывания
    61.     sti
    62. }
    63.  
    64. To Do
    65.  
    66. __asm
    67. {
    68.     cli
    69.     lea esp,[ebp + 0x30]
    70.     pop gs
    71.     pop es
    72.     pop ds
    73.     add esp, 0x14
    74.     pop fs
    75.     pop edi
    76.     pop esi
    77.     pop ebx
    78.     pop ebp
    79.     add esp, 0x18
    80.     sti
    81.     retf 0x4
    82. }
    При выходе из колгейта приложение валится с PF

    Код (Text):
    1. PAGE_FAULT_IN_NONPAGED_AREA (50)
    2. Invalid system memory was referenced.  This cannot be protected by try-except,
    3. it must be protected by a Probe.  Typically the address is just plain bad or it
    4. is pointing at freed memory.
    5. Arguments:
    6. Arg1: f420f00c, memory referenced.
    7. Arg2: 00000000, value 0 = read operation, 1 = write operation.
    8. Arg3: 804fc83a, If non-zero, the instruction address which referenced the bad memory
    9.     address.
    10. Arg4: 00000000, (reserved)
    11.  
    12. FAULTING_IP:
    13. nt!KeContextFromKframes+212
    14. 804fc83a 8b8798020000    mov     eax,dword ptr [edi+298h]
    Причём в колгейтах без параметров всё работает отлично. Чувсвтую, что упустил что-то, но что пока не могу сообразить.
     
  2. AntiB

    AntiB New Member

    Публикаций:
    0
    Регистрация:
    23 мар 2007
    Сообщения:
    393
    AntiFreeze
    а зачем вам call gate если есть TrapGate ?
     
  3. AntiFreeze

    AntiFreeze Дмитрий

    Публикаций:
    0
    Регистрация:
    26 июн 2008
    Сообщения:
    65
    Немного переделал. Теперь выход из Call Gate организовал с помощью nt!Kei386EoiHelper.
    Но. Где-то один раз из 1000 на входе или выходе из колгейта наступает прерывание hal!Halp8254ClockInterrupt, всё валится, причём:
    Код (Text):
    1. IRQL_NOT_LESS_OR_EQUAL (a)
    2. An attempt was made to access a pageable (or completely invalid) address at an
    3. interrupt request level (IRQL) that is too high.  This is usually
    4. caused by drivers using improper addresses.
    5. If a kernel debugger is available get the stack backtrace.
    6. Arguments:
    7. Arg1: 000004cd, memory referenced
    8. Arg2: 000000ff, IRQL
    9. Arg3: 00000001, bitfield :
    10.     bit 0 : value 0 = read operation, 1 = write operation
    11.     bit 3 : value 0 = not an execute operation, 1 = execute operation (only on chips which support this level of status)
    12. Arg4: 8281bd1d, address which referenced memory
    Код (Text):
    1. WRITE_ADDRESS:  000004cd
    2.  
    3. CURRENT_IRQL:  2
    4.  
    5. FAULTING_IP:
    6. hal!Halp8254ClockInterrupt+79
    7. 8281bd1d fe4711          inc     byte ptr [edi+11h]
    Код (Text):
    1. hal!Halp8254ClockInterrupt:
    2. 8281bca4 54              push    esp
    3. 8281bca5 55              push    ebp
    4. 8281bca6 53              push    ebx
    5. 8281bca7 56              push    esi
    6. 8281bca8 57              push    edi
    7. 8281bca9 83ec54          sub     esp,54h
    8. 8281bcac 8bec            mov     ebp,esp
    9. 8281bcae 894544          mov     dword ptr [ebp+44h],eax
    10. 8281bcb1 894d40          mov     dword ptr [ebp+40h],ecx
    11. 8281bcb4 89553c          mov     dword ptr [ebp+3Ch],edx
    12. 8281bcb7 f7457000000200  test    dword ptr [ebp+70h],20000h
    13. 8281bcbe 75bc            jne     hal!V86_Hci_a (8281bc7c)
    14. 8281bcc0 66837d6c08      cmp     word ptr [ebp+6Ch],8
    15. 8281bcc5 741f            je      hal!Halp8254ClockInterrupt+0x42 (8281bce6)
    16. 8281bcc7 8c6550          mov     word ptr [ebp+50h],fs
    17. 8281bcca 8c5d38          mov     word ptr [ebp+38h],ds
    18. 8281bccd 8c4534          mov     word ptr [ebp+34h],es
    19. 8281bcd0 8c6d30          mov     word ptr [ebp+30h],gs
    20. 8281bcd3 bb30000000      mov     ebx,30h
    21. 8281bcd8 b823000000      mov     eax,23h
    22. 8281bcdd 668ee3          mov     fs,bx
    23. 8281bce0 668ed8          mov     ds,ax
    24. 8281bce3 668ec0          mov     es,ax
    25. 8281bce6 648b1d00000000  mov     ebx,dword ptr fs:[0]
    26. 8281bced 64c70500000000ffffffff mov dword ptr fs:[0],0FFFFFFFFh
    27. 8281bcf8 895d4c          mov     dword ptr [ebp+4Ch],ebx
    28. 8281bcfb 81fc00000100    cmp     esp,10000h
    29. 8281bd01 0f8249ffffff    jb      hal!Abios_Hci_a (8281bc50)
    30. 8281bd07 c7456400000000  mov     dword ptr [ebp+64h],0
    31. 8281bd0e 648b0d24010000  mov     ecx,dword ptr fs:[124h]
    32. 8281bd15 fc              cld
    33. 8281bd16 648b3d20000000  mov     edi,dword ptr fs:[20h]
    34. 8281bd1d fe4711          inc     byte ptr [edi+11h]
    35. 8281bd20 807f1101        cmp     byte ptr [edi+11h],1
    36. 8281bd24 753b            jne     hal!Halp8254ClockInterrupt+0xbd (8281bd61)
    37. 8281bd26 0f31            rdtsc
    38. ...
    Код (Text):
    1. Trap Frame
    2. eip=8281bd1d esp=927dbd2c ebp=927dbd2c iopl=0         nv up di ng nz na po nc
    3. cs=0008  ss=0010  ds=0023  es=0023  fs=003b  gs=0000             efl=00000082
    4. hal!Halp8254ClockInterrupt+0x79:
    5. 8281bd1d fe4711          inc     byte ptr [edi+11h]         ds:0023:000004cd=??
    fs=003b !!!!
    как такое может быть ?
     
  4. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    А на входе fs какой?
     
  5. AntiFreeze

    AntiFreeze Дмитрий

    Публикаций:
    0
    Регистрация:
    26 июн 2008
    Сообщения:
    65
    SadKo, на входе куда?
    Вполне вероятно, что в hal!Halp8254ClockInterrupt мы попадаем с fs = 3b. Но она, как и любой другой обработчик прерывания, явно перегружает fs в 30. bp на hal!Halp8254ClockInterrupt ставить бесполезно, т.к. она вызывается каждые 10 мс или что-то около того. bp /t windbg не съел. Да и вообще у виндбг есть проблемы при отладке операций с сегментными регистрами.
     
  6. AntiFreeze

    AntiFreeze Дмитрий

    Публикаций:
    0
    Регистрация:
    26 июн 2008
    Сообщения:
    65
    Поковырял ещё немного. Если использовать тот же пролог для interrupt gate, или при обработке sysenter (c минимальными изменениями конечно), то всё работает как часы.
    Такое впечатление, что прерывание hal!Halp8254ClockInterrupt срабатывает ДО первой инструкции пролога cli (!!!!!).
    А ведь на самом деле: Int и SysEnter сбрасывают IF, а far call - нет.
     
  7. AntiFreeze

    AntiFreeze Дмитрий

    Публикаций:
    0
    Регистрация:
    26 июн 2008
    Сообщения:
    65
    Сегодня провёл маленький эксперимент.

    UserMode:
    Код (Text):
    1. start:
    2.     call    fword ptr [ FarCall ] ; MyDriver!DispatchRoutine
    3.     jmp start
    KernelMode:
    Код (Text):
    1. MyDriver!DispatchRoutine:
    2. 95a0c030 cb              retf
    Как и думал - код валится по той же причине. Получается, что механизм Call Gate'ов нельзя использовать в винде!?