Проблема с sysenter hook

Тема в разделе "WASM.BEGINNERS", создана пользователем Neraverin, 31 окт 2010.

  1. Neraverin

    Neraverin New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2010
    Сообщения:
    9
    Сразу скажу, что с асмом пока знаком плохо. Собираю тестовый драйвер под Win XP SP3 x86 на Intel. Хочу поставить хук на NtClose Хук делается так.
    Код (Text):
    1. __asm
    2. {
    3. pushad
    4. mov ecx, 0x176
    5. rdmsr
    6. mov OldSyscall, eax
    7. mov eax, NewSyscall
    8. xor edx, edx
    9. wrmsr
    10. popad
    11. }
    Функция __declspec(naked) NewSyscall(). Внутри есть глобальная переменная _eax
    Код (Text):
    1. __asm
    2. {
    3. pushad
    4. pushfd
    5. push fs
    6. mov di, 0x30
    7. mov fs, di
    8. mov eax, fs:[0x124]
    9. mov eax, [eax + 0x44]
    10. mov _eax, eax
    11. //push eax - так почему то не работало
    12. push edx
    13. call CollectProcess
    14. pop fs
    15. popfd
    16. popad
    17. jmp RetAddr
    18. }
    19. typedef struct Close_args
    20. {
    21.     ULONG retaddr1;
    22.     ULONG retaddr2;
    23.     HANDLE hHandle;
    24. } *pClose_args;
    25.  
    26. typedef NTSTATUS (*PNTClose)(HANDLE);
    27.  
    28. __declspec(naked) CollectProcess(PVOID Stack)
    29. {
    30.     switch(_eax)
    31.     case 0x19:
    32.         {
    33.             pClose_args Args = Stack;
    34.             if (...)
    35.             {
    36.                 RetAddr = OldSyscall;
    37.                 break;
    38.             }
    39.             else
    40.             {
    41.                 ...
    42.                 PNTClose RealNtClose = RealNtCloseAddress;
    43.                 // RealNtCloseAddress содержит корректный адресс функции NtClose
    44.                 RealNtClose(Args->hHandle); - BSOD
    45.                 ...
    46.                 RetAddr = Args->retaddr2;
    47.             }
    48.             break;
    49.         }
    50.     return;
    51. }
    При вызове собственно происходит падение в BSOD. Что собственно хочется получить - пользователь вызывает NtClose. Проверяются некоторые параметры, например UID пользователя. И если он подходящий, то происходт нормальный вызов. Если он не подходящий, то хочется вернуться к месту вызова вернув NT_ACCESS_DENIED. Помогите разобраться или дайте направление в котором копать. А то уже неделю не могу разобраться. Да и BSOD бывает разный. Или с кодом 0x000000d1 или 0x00000050. Ps часть кода написана по памяти, так что могут быть маленькие недочеты.
     
  2. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
    А на SDT хук не проще поставить?

    Это 0x000000d1 - DRIVER_IRQL_NOT_LESS_OR_EQUAL.
    Это 0x00000050 - PAGE_FAULT_IN_NONPAGED_AREA.

    В каком конкретно месте валится?
     
  3. Neraverin

    Neraverin New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2010
    Сообщения:
    9
    Валится в месте вызова прям. Пытался ходить отладчиком внутрь. Там происходит много различных вызовов и падает все далеко не сразу. Подозреваю, что может не сохраняю какие то регистры, но разобраться не могу. Собственно если возвращаться по OldSyscall то все нормально работает. Раньше и был хук SDT, теперь в ТЗ стоит отойти от него по ряду причин.
     
  4. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
    Neraverin
    Учитывая DRIVER_IRQL_NOT_LESS_OR_EQUAL вы там случайно IRQL не поднимаете?
     
  5. Neraverin

    Neraverin New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2010
    Сообщения:
    9
    Насколько я понимаю - нет. Падение в BSOD происходит даже если закоментить скрытый под ... код. То есть попадаю в CollectProcess(PVOID Stack). Вызываю функцию NtClose по известному адрессу и происходит падение. Явно KeRaiselrql не вызывается 100%. В NtClose IRQL не повышается как я понимаю.
     
  6. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
    Neraverin
    А вы переключаете стек user-mode на стек kernel-mode?

    Вы уверены? В обработчике IRP_MJ_CLOSE драйвер может повысить IRQL, а стек user-mode - подкачиваемый, что может приводить к ошибкам.
     
  7. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Конечно падает, во первых !IF, это эквивалентно высочайшему IRQL, стек не переключен с DPC на локальный, задача не сохранена и пр.
    Код (Text):
    1. G_InitialStack  ULONG ? ; KTHREAD.InitialStack
    2. G_PreviousMode  ULONG ? ; KTHREAD.PreviousMode
    3. G_DebugActive   ULONG ? ; KTHREAD.PreviousMode
    4. G_TrapFrame ULONG ? ; KTHREAD.TrapFrame
    5. G_KernelDr  ULONG ? ; KPRCB.ProcessorState.SpecialRegisters
    6.  
    7. Drx:
    8.     test byte ptr [ebp + TsSegCs],MODE_MASK
    9.     jz MarkFrame    ; KM
    10.     mov ebx,dr0
    11.     mov ecx,dr1
    12.     mov edi,dr2
    13.     mov [ebp + TsDr0],ebx
    14.     mov [ebp + TsDr1],ecx
    15.     mov [ebp + TsDr2],edi
    16.     mov ebx,dr3
    17.     mov ecx,dr6
    18.     mov edi,dr7
    19.     mov [ebp + TsDr3],ebx
    20.     mov [ebp + TsDr6],ecx
    21.     xor ebx,ebx
    22.     mov [ebp + TsDr7],edi
    23.     mov dr7,ebx  
    24.     push edx  
    25.     mov edi,dword ptr fs:[PcPrcb]
    26.     mov ecx,G_KernelDr
    27.     mov ebx,[edi + ecx + SrKernelDr0]
    28.     mov edx,[edi + ecx + SrKernelDr1]
    29.     mov dr0,ebx
    30.     mov dr1,edx
    31.     mov ebx,[edi + ecx + SrKernelDr2]
    32.     mov edx,[edi + ecx + SrKernelDr3]
    33.     mov dr2,ebx
    34.     mov dr3,edx
    35.     mov ebx,[edi + ecx + SrKernelDr6]
    36.     mov edx,[edi + ecx + SrKernelDr7]
    37.     mov dr6,ebx
    38.     mov dr7,edx
    39.     jmp MarkFrame
    40.    
    41. v86:
    42.     add esp,KTRAP_FRAME_LENGTH
    43. ; V86 Es, Ds, Fs, Gs
    44.     push 0
    45.     push 0
    46.     push 0
    47.     push 0
    48. ; IRET frame.
    49.     push KGDT_R3_DATA OR RPL_MASK   ; Ss
    50.     push 0  ; Esp
    51.     push EFLAGS_INTERRUPT_MASK + EFLAGS_V86_MASK + 2H
    52.     push KGDT_R3_CODE OR RPL_MASK   ; Cs
    53.     push 0  ; Eip
    54. ; #UD
    55.     push edx
    56.     mov ecx,PCR[PcGdt]
    57.     mov edx,dword ptr ptr [ecx + 2]
    58.     mov ecx,dword ptr [ecx + 4]
    59.     and ecx,0FF000000H
    60.     and edx,000FFFFFFH
    61.     or ecx,edx
    62.     pop edx
    63.     jmp ecx ; KiTrap06
    64.    
    65. ; o !IF, !VM
    66. ;
    67. xKiFastCallEntry proc C
    68.     push KGDT_R0_PCR
    69.     mov ecx,KGDT_R3_DATA OR RPL_MASK
    70.     pop fs
    71.     mov ds,ecx
    72.     push 2
    73.     mov es,ecx
    74.     popfd   ; !DF etc.
    75. ; Переключаем DPC стек.
    76.     mov ecx,PCR[PcTss]
    77.     mov esp,[ecx + TssEsp0]
    78.    
    79.     push KGDT_R3_DATA OR RPL_MASK   ; Ss
    80.     push edx    ; Esp
    81.     add edx,2*4 ; Arg's
    82.     or byte ptr [esp + 1],(EFLAGS_INTERRUPT_MASK shr 8) ; IF
    83.    
    84.     push KGDT_R3_CODE OR RPL_MASK   ; Cs
    85.     push dword ptr ds:[USER_SHARED_DATA + UsSystemCallReturn]   ; Eip
    86.     push 0
    87.     push ebp
    88.     push ebx
    89.     push esi
    90.     push edi
    91.     mov ebx,PCR[PcSelfPcr]
    92.     push KGDT_R3_TEB OR RPL_MASK    ; Fs
    93.    
    94.     mov esi,dword ptr [ebx + PcPrcbData + PbCurrentThread]
    95.     push dword ptr [ebx + PcExceptionList]
    96.     mov dword ptr [ebx + PcExceptionList],EXCEPTION_CHAIN_END
    97.    
    98.     mov ecx,G_InitialStack
    99.     mov ebp,dword ptr [esi + ecx]
    100.     push MODE_MASK  ; UM
    101.     sub esp,TsPreviousPreviousMode
    102.     mov ecx,G_PreviousMode
    103.     sub ebp,NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH
    104.     mov byte ptr [esi + ecx],MODE_MASK
    105. ; V86
    106.     cmp ebp,esp
    107.     mov ecx,Dr7
    108.     jne v86
    109.     mov dword ptr [ebp + TsDr7],0
    110.     test ecx,ecx
    111.     mov [ebp + TsDbgArgPointer],edx
    112.     mov [ebp + TsDbgArgMark],0BADB0D00H
    113.     jnz Drx
    114. ; Normal SET_DEBUG_DATA.
    115.     mov ebx,[ebp + TsEbp]
    116.     mov edi,[ebp + TsEip]
    117.     mov ecx,G_TrapFrame
    118.     mov [ebp + TsDbgEbp],ebx
    119.     mov [ebp + TsDbgEip],edi
    120.     mov dword ptr [esi + ecx],ebp
    121. MarkFrame:
    122.         sti ; IF
    Необходимые константы в kimacro.inc
    Плохой способ, лучше распарсить саму KiFastCallEntry() и скопировать код в буфер. При этом нужно сохранить в стеке ветвления и поправить их. При этом нужен всего дизасм длин.

    Но я бы не стал это юзать. Нужно определять смещение некоторых полей. Более того это потенциальный способ убить систему, при вызове с TF ось упадёт, не зависимо от способа формирования трап фрейма.
     
  8. Neraverin

    Neraverin New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2010
    Сообщения:
    9
    Спасибо за помощь. Буду изучать сегодня в этом направлении. Вот только не совсем понял про IF. Если IА эквивалентно высочайшему IRQL, то падать это должно всегда. Однако если просто убрать вызов по указателю (оставив при этом остальную логику), то все нормально работает.
     
  9. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Neraverin
    Прерывания замаскированы все. IRQL работает только если прерывания размаскированы. Иначе быть не может, ведь камень их не пропускает.
    В принципе достаточно перезагрузить стек и селекторы для работы в KM. При этом задача не сохранена и текущий тред ядерный. Для этого достаточно перезагрузить стек и сегментные регистры.
    DPC стек это стек уникальный для процессора, но общий для всех потоков исполняемых на данном процессоре. Ловушки и прерывания используют локальный стек, который определён в TSS, туда он загружается шедулером. DPC стек загружается однократно в MSR при инициализации оси. В этом стеке и начинает исполняться сискал. Если разрешить прерывания, то при переключении задачи и последующем вызове сискала на текущем процессоре стек будет затёрт, изза этого восстановление состояния при следующем переключении задач невозможно, это приведёт к багчеку.
    Перехват сискалов перезаписью Ip в MSR это тупой способ. Попытка вызова сискала с взведённым TF приведёт к багчеку(ядро хэндлит это проверкой адреса фолта, но так как он будет изменён вохникнет фолт не обработанный что приведёт к багчеку). Одно нажатие F7 в олли на шлюзе и оси упадёт.