Сбрасывает ли инструкция Sysenter этот флажёк ? Смотрел в манах на амд, про него ничего нет(у меня P4). Сказано что изменяет VM, IF, RF.
Freeman Остаётся надеятсо что существует баговая комбинация eflags/eip при которой значение этого флажка не определено(чтоб проскачить в KiFastCallEntry с взведённым df, остальные входы сбрасывают), как вариант возможно для сискалл пройдёт, хотя врятле, мелкомягкие походу знали это, да и потестить негде, попробую сбрутфорсить, может чего и получится, но я уже почемуто даже не надеюсь..
Виндбг дебажит недостоверно такие вещи, поэтому на его результаты я бы полагаться не стал. Он сам мог сбросить DF даже если он был и установлен. Например, fs он всегда перезагружает в 0x30 в ядре во время пошагового трейса, код вида Код (Text): mov ax, ds mov fs, ax mov eax, [fs:0xffdff124] mov cx, 0x30 mov fs, cx не будет исполнен корректно, поскольку сразу после инструкции mov fs, ax когда fs получит значение 0x23, ядерная часть отладчика сбросит fs в 0x30 обратно и код не выполнится. Такие куски кода приходится пропускать, ставя бряк после того, как сегментному регистру вернут первоначальное значение. Подозреваю, что так же может быть и с DF при переходе в ядро.
Всё верно в манах, если там чтото не огаворено, значит не юзаетсо. Чтоб проверить похучил: Код (Text): KGDT_R3_DATA equ 00020H KGDT_R3_CODE equ 00018H KGDT_R0_DATA equ 00010H KGDT_R0_CODE equ 00008H KGDT_R0_PCR equ 00030H KGDT_R3_TEB equ 00038H RPL_MASK equ 00003H sysenter macro BYTE 0Fh BYTE 34h endm sysexit macro BYTE 0Fh BYTE 35h endm GET_POINTER macro Reg32, Offset_ Local l1 Call l1 l1: pop Reg32 lea Reg32,[Reg32 + (Offset_ - offset l1)] endm MSR_SYSENTER_CS equ 174h MSR_SYSENTER_ESP equ 175h MSR_SYSENTER_EIP equ 176h EFLAGS_TF equ 0000000000000100000000b ;Trap Flag (Single Step) EFLAGS_DF equ 0000000000010000000000b ;Direction Flag USER_SHARED_DATA_BASE equ 0FFDF0000h ENTRY_DATA struct ExFreePoolEntry PVOID ? Pool PVOID ? ENTRY_DATA ends PENTRY_DATA typedef ptr ENTRY_DATA STACK_CODE_SIZE equ ((offset check_ - offset shell_ + 3) and (not(3))) ;*************************** ;* WARNING: BSOD IF TF = 1 * ;*************************** iKiFastCallEntry proc C pushfd mov ecx,KGDT_R3_DATA or RPL_MASK mov ds,cx mov es,cx inc dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 2*4] ;Fast system calls test eax,eax jns dispatch_ pop dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 3*4] ;Entry eflags cmp eax,-1 je check_ cmp eax,-2 push KGDT_R0_PCR mov ecx,STACK_CODE_SIZE / 4 pop fs sub esp,STACK_CODE_SIZE push edx ;-> Esp push esi push edi cld GET_POINTER Esi, offset shell_ lea edi,[esp + 3*4] mov eax,dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 4] ;Original entry. rep movsd mov ecx,MSR_SYSENTER_EIP xor edx,edx pop edi pop esi wrmsr GET_POINTER Edx, offset EntryData lea eax,[esp + 4] ; pushfd ;Save DF push ENTRY_DATA.Pool[edx] mov edx,ENTRY_DATA.ExFreePoolEntry[edx] cld jmp eax dispatch_: lea esp,[esp + 4] jmp dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 4] ;Original entry. shell_: Call Edx ;ExFreePool ; popfd ;Restore DF sti pop ecx ;-> Esp mov edx,dword ptr ds:[USER_SHARED_DATA_BASE + 304h] ;UsSystemCallRet -> ntdll!KiFastSystemCallRet push KGDT_R3_TEB or RPL_MASK pop fs sysexit ;Eax = (DF) check_: sti inc dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 4*4] ;Fast system calls for check pushfd test dword ptr [esp],EFLAGS_DF setnz al lea esp,[esp + 4] ;Remove eflags. movzx eax,al ;(DF) mov dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 5*4],eax ;DF mov ecx,edx ;-> Esp mov edx,dword ptr ds:[USER_SHARED_DATA_BASE + 304h] ;UsSystemCallRet -> ntdll!KiFastSystemCallRet sysexit ;Eax = (DF) iKiFastCallEntry endp EntryData ENTRY_DATA <> ENTRY_OFFSET equ (offset EntryData - offset iKiFastCallEntry) POOL_SIZE equ ((offset EntryData - offset iKiFastCallEntry + sizeof ENTRY_DATA + 3) and (not(3))) iKiLoadFastSyscall proc uses esi edi ;Only first processor. ;Default in MSR_SYSENTER_ESP ;Default in MSR_SYSENTER_CS(KGDT_R0_CODE) invoke KeSetSystemAffinityThread, 1 invoke ExAllocatePool, NonPagedPool, POOL_SIZE .if Eax push eax lea esi,iKiFastCallEntry mov edi,eax mov ecx,POOL_SIZE / 4 cld mov edx,dword ptr [ExFreePool + 2] rep movsd mov edx,dword ptr [edx] mov ENTRY_DATA.Pool[eax + ENTRY_OFFSET],eax mov ENTRY_DATA.ExFreePoolEntry[eax + ENTRY_OFFSET],edx cli mov ecx,MSR_SYSENTER_EIP rdmsr xchg dword ptr [esp],eax xor edx,edx wrmsr sti xor eax,eax pop dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 4] ;Previous entry. mov dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 2*4],eax ;Fast system calls mov dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 3*4],eax ;Entry eflags mov dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 4*4],eax ;Fast system calls for check mov dword ptr ds:[USER_SHARED_DATA_BASE + PAGE_SIZE - 5*4],eax ;DF .endif push eax invoke KeRevertToUserAffinityThread pop eax ret iKiLoadFastSyscall endp Получилось вобщем как и ожидал результат, не сбрасываются все остальные флажки, про которые не сказано в манах: В частности не сбрасывается DF, но он сбрасывается в диспетчере, не инструкцией cld, а через popfd, я этого не заметил. Также не сбрасывается TF, при исполнении sysenter c взведённым TF вызывается диспетчер исключений, который чекает ип, если это KiFastCallEntry, то сбрасывает TF и продолжает исполнять диспетчер сервиса, ибо быстрый вызов не использует стек, моё ИМХО эта инструкция большая ошибка, которую совершила эта контора, в случае трассировки она не ускоряет вызов, а очень сильно его замедляет, гораздо дольше чем через Int.
Мой браузер и IDE (да и остальной повседневный софт) постоянно юзает sysenter с взведенным TF, огга Если в процессе идет трассировка через TF, то там уже, по определению, всё жутко тормозит, будь-то трассировка через DebugApi или через in-process SEH/VEH. Так что... на эту "большую ошибку этой конторы" можно и не обращать внимания. Конечно же, имхо
nester7 Функционал дебугапи предоставлен только для одной цели - сообщить потоку его юзоющего об событии в отлаживаемом потоке, в частности фильтрация исключений, но это никак не связано с пошаговой отладкой. В данном топике разбираетсо низкоуровневый механизм предоставляемый процессором и не с каким функционалом столь высокого уровня не связан. Изначально этот топик продолжение темы на VT, Гордон в курсе, предпологалось что системный вход имеет две уязвимости, одна связана с селекторами, вторая считалось с пропуском DF. Как оказалось DF сбрасывается програмно. Механизм работы sysenter слишком кривой. Данная инструкция не сохраняет флажки, Cs, Ss. Поэтому он и неполноценный мягко сказано. Так как флажки не сохраняются, TF не сбрасываетсо при смене кольца и возникает отладочное исключение, обойти это невозможно. Ось это исключение обрабатывает, тратя на это сотни инструкций, против единственной Int, которая сбрасывает флажки. Если трассировка не используется это весьма эффективно, так как нет тех обращений к памяти и проверок что имеются при исполнении Int, поэтому и быстрый вызов. Но при трассировке переход в ядро, в реальном ядре на KiFastCallEntry занимает в десятки раз больше времени, чем посредством Int. Само собой разумеется что с учётом планирования ты это не заметишь, темболее скорее всего что ты понимаешь под трассировкой уставновку точки останова после каждой инструкции, даже не затрагивая пошаговую отладку(TF). Использование структурных обработчиков исключений(ты имел ввиду юзермод) также тут не причём. Что понимать под трассировщиком - это не тот механизм, что использует юзермодные калбаки. Имеется ввиду трассировка, есполняемая на самом низком уровне, тоесть в IDT перехвачен шлюз и диспетчер при каждом подобном исключении взводит повторно TF, продолжая пошаговую отладку. Юзермодный же механизм требует в сотни раз больше времени на исполнение. На эту большую ошибку конторы не обратит внимания только тот, кто с этим не сталкнулся, а смотрит со стороны не понимая сути.)
И есчо. Касательно этого: Код (Text): ;*************************** ;* WARNING: BSOD IF TF = 1 * ;*************************** Ось выносится изза необработанного отладочного исключения, но его так просто не словить. Диспетчер #DB при исполнении Sysenter с взведённым TF получает управление. Вот этот код: Код (Text): 00407C3E _KiTrap01 push 0 00407C40 mov word ptr ss:[esp+2],0 00407C47 push ebp 00407C48 push ebx 00407C49 push esi 00407C4A push edi 00407C4B push fs 00407C4D mov ebx,30 00407C52 mov fs,bx ; Modification of segment register 00407C55 mov ebx,dword ptr fs:[0] 00407C5C push ebx 00407C5D sub esp,4 00407C60 push eax 00407C61 push ecx 00407C62 push edx 00407C63 push ds 00407C64 push es 00407C65 push gs 00407C67 mov ax,23 00407C6B sub esp,30 00407C6E mov ds,ax ; Modification of segment register 00407C71 mov es,ax ; Modification of segment register 00407C74 mov ebp,esp 00407C76 test dword ptr ss:[esp+70],20000 00407C7E jnz short ntoskrnl.V86_kit1_a 00407C80 cld 00407C81 mov ebx,dword ptr ss:[ebp+60] 00407C84 mov edi,dword ptr ss:[ebp+68] 00407C87 mov dword ptr ss:[ebp+C],edx 00407C8A mov dword ptr ss:[ebp+8],BADB0D00 00407C91 mov dword ptr ss:[ebp],ebx 00407C94 mov dword ptr ss:[ebp+4],edi 00407C97 test byte ptr fs:[50],0FF 00407C9F jnz ntoskrnl.Dr_kit1_a 00407CA5 cmp dword ptr fs:[54],0 00407CAD jnz short ntoskrnl.00407D10 00407CAF mov ecx,dword ptr ss:[ebp+68] 00407CB2 cmp ecx,ntoskrnl._KiFastCallEntry 00407CB8 je ntoskrnl.00407B7D Видно что ип сравнивается с адресом шлюза, если исключение на нём возникло, юзоется следующий код: Код (Text): 00407B7D mov dword ptr ss:[ebp+68],ntoskrnl._KiFastCallEntry2 00407B84 and byte ptr ss:[ebp+71],0FE 00407B88 jmp ntoskrnl.Kei386EoiHelper Тоесть состояние потока восстанавливается каким было на момент возникновения трассировочного исключения и передаётся на второй шлюз KiFastCallEntry2(что и юзоет амд через Syscall). На это много времени нужно. И что самое главное если подменён адрес шлюза в мср, то возврат не исполняется, ибо адрес отличен от KiFastCallEntry, а чтобы это словить нужно поставить свой диспетчер исключений. Это в простейшем случае делоется через перехват второго шлюза в IDT, либо регистрацией диспетчера в KiDebugRoutine. Ни то ни другое для подобного тестового кода не нужно, темболее что второй вариант вызовет коллизии с уже зарегистрированным диспетчером, который принадлежит ядерному отладчику(в моём случае это баговый сисер). Теперь ты должен уже понять сколь много времени займёт трассировка Sysenter. [Да и вообще, кто сможет продебажить например MessageBox() в юзермоде так чтоб независло, тогда и разговор будет. Закрыто.]
Так, давай еще раз и по порядку 1. Я понимаю, что при sysenter + TF нужно программно обработать то, что int делала аппаратно, и это делает sysenter (в данном случае) далеко не fast call. 2. В повседневном софте это накуй никому не нужно и sysenter там fast, а значит, говорить, что это ппц какая ошибка - очень натянуто, что, собсно, я и хотел сказать, не более. 3. Механизм-мезанизм... Сам ты обрабатываешь, похучив IDT, иль ядро это делает (с последующим вызовом UM callback'ов) - в любом случае это томоза, разница в цифрах, и только. Собсно, не о том речь. 4. Я очень рад, что книги, вроде "врутреннего устройства Windows" писались не тобой - там бы на каждый пук был бы метровый листинг из ольгиного дизасма, с кучей околотемной информации, сдобреной олпанским изыком и расплытым смыслом. 5. [Открыто. Не стоит таким образом затыкать рот. Не достойны разговора с тобой? Ну, не отвечай тогда, это же форум ] Кстати, VT - это что/где?
Очень напрягает. И, думаю, не меня одного Как минимум, двух Для Clerk'а, в силу его хороших технических знаний (и способностей?), это игнорируется. Стал бы его кто-нибудь терпеть, если бы он вещал в бегинерсах с вопросами про массивы и указатели? Врят ли. Но напрягает просто ппц - я тупо копирую его пост в редактор и там по предложениям разбираю, пытаясь связать мысли автора в его предложениях и уловить смысл
хм. а я нормально так читаю в силу того что сам предпочитаю сей деолект. тут как и везде главное практека. но пожалуй это не тема топика. форум http://virustech.org/f
Freeman Спасибо. А я-то не мог отделаться от мысли о VTune У анимешников (иль как эт слово нужно писать? ) тоже есть свой сленг, у админов - свой, у электриков - , у автомастеров - , у... ицетера. Постоянно это использовать - неуважение. Просто потому, что другим это сложно читать, а главное - понимать - что раньше было просто словосочетанием, теперь превращается в хyeтерацию, на которую нужно пару секунд залипнуть, чтобы понять о чем тут речь. Собсно, мне похеристически на это дело (меня не особо заломает в очередной раз это вставить в редактор), но было бы здорово, если бы этого было меньше на этом сайте вне хипа