сейчас мыщъх тестирует один очень нехилый эмуль, вытаскивая из кладовых (под)сознания накопленные анти-отладочные трюки. вот сейчас откопал давно обнаруженный баг в w2k, до сих пор не исправленный на висле и юзаемый некоторыми защитами. короче, вот код, угадайте что он делает? xor eax, eax xor ebx, ebx dec ebx push offset handler push ebx mov fs:[eax], esp push ebx push cs push offset jump_to IRETD угадайте, что он делает? ответ - из-за бага в ядре винды, после выполнения IRETD установленная цепочка SEH обработчиков слетает нах и управление передается на дефлотный обработчик в KRN32 ну или на фильтр, установленный SetUnhandledExceptionFilter (если он есть)
А в чём баг заключается ? Ну взводится TF, возникает трассировочное исключение, управление диспетчер исключений пулучает. Если сех-фрейм валидный то структурный обработчик исключений вызывается. Кстати ядро ничего про юзермодные сех-фреймы не знает. Add: XPSP3 Кстати всем трюкам трюк: NtContinue(CONTEXT.regEFlags -> 0). Соединил
Clerk > А в чём баг заключается ? закинуть готовый пример? баг заключается в... короче, значит, что мы делаем. 1) устанавливаем свой SEH обработчик 2) выполняем PUSH -1/push cs/push куда_прыгать/IRETD на r3 3) запускаем это дело на выполнение. на чем запускаем не важно. тестировалось вплоть до вислы при выполнении IRETD установленный SEH _слетает_. в SEH chain видится только один обрабочтк и он указывает в ядро. соотвественно, программа падает с криком об пошаговом исключии, которое подавляется установкой фильтра необрабатываемых исключений, который по идее в данной ситуации вообще не должен получать управления. это дело хорошо отслеживается в ольге. до выполнения IRETD у нас была цепочка SEH, а после выполнения ее уже нет. если это не баг, то я не знаю. > Ну взводится TF, возникает трассировочное исключение, > управление диспетчер исключений пулучает. > Если сех-фрейм валидный валидный. > то структурный обработчик исключений вызывается. он не только не вызывается, то еще и SEH chain ре-иницилизиреутся и туда записывается единственный системный обработчик.
У меня в опытах TF не взводится а вызывается дважды установленный "обычный" (т.е. "handler") обработчик: Handler got control! EFLAGS:00254616 EIP:00000000 A.Handler got control! EFLAGS:00250646 EIP:7c9012b0 В обработчике я просто пытаюсь передать управление на метку далее. Возможно CS тоже нужно править? Второй EIP вроде бы указывает в процедуру менеджера исключений: 7C9012B0 66:F2:AF REPNE SCAS WORD PTR ES:[EDI] (не проверял внимательно!!!)
Код (Text): .code ENTER_SEH macro Local Delta1, Delta2 assume fs:nothing push ebp Call Delta1 Delta1: add dword ptr [esp],(ExceptionExit_ - Delta1) Call Delta2 Delta2: add dword ptr [esp],(MainExceptionHandler - Delta2) push dword ptr fs:[TEB.Tib.ExceptionList] mov dword ptr fs:[TEB.Tib.ExceptionList],esp endm LEAVE_SEH macro clc ExceptionExit_: pop dword ptr fs:[TEB.Tib.ExceptionList] lea esp,[esp + 4*3] endm $PUSH_REF macro Variable Local dt_ Call dt_ dt_: add dword ptr [esp],(offset Variable - offset dt_) endm MainExceptionHandler proc C mov esp,dword ptr [esp + 8] ;(esp) -> ExceptionList mov eax,STATUS_UNSUCCESSFUL mov ebp,dword ptr [esp + 4*3] stc jmp dword ptr [esp + 4*2] MainExceptionHandler endp Entry proc ENTER_SEH assume fs:nothing push -1 push cs $PUSH_REF Continue Iretd Continue: nop nop nop LEAVE_SEH Int 3 ret Entry endp end Entry Вот скомпиленый пример: Код (Text): Entry: db 08Bh, 064h, 024h, 008h, 0B8h, 001h, 000h, 000h, 0C0h, 08Bh db 06Ch, 024h, 00Ch, 0F9h, 0FFh, 064h, 024h, 008h, 055h, 0E8h db 000h, 000h, 000h, 000h, 081h, 004h, 024h, 035h, 000h, 000h db 000h, 0E8h, 000h, 000h, 000h, 000h, 081h, 004h, 024h, 0DCh db 0FFh, 0FFh, 0FFh, 064h, 0FFh, 035h, 000h, 000h, 000h, 000h db 064h, 089h, 025h, 000h, 000h, 000h, 000h, 06Ah, 0FFh, 00Eh db 0E8h, 000h, 000h, 000h, 000h, 081h, 004h, 024h, 008h, 000h db 000h, 000h, 0CFh, 090h, 090h, 090h, 0F8h, 064h, 08Fh, 005h db 000h, 000h, 000h, 000h, 08Dh, 064h, 024h, 00Ch, 0CCh, 0C3h Чтото я ничего не вижу ядерных адресов и тп. в юзермодном стеке..
У меня второй Exception был потому что флаг направления в первом случае получался как после STD (у меня debugout так сделан) после того как поправл - никаких mircales: Код (Text): .data MsgDefault db 'Normal execution...',0Dh,0Ah,0 MsgUnHandledFilter db 'UNHANDLED execution...',0Dh,0Ah,0 Msghandler db 'Handler got control! EFLAGS:???????? EIP:???????? CS:????????',0Dh,0Ah,0 MsgEnd db '..End!',0Dh,0Ah,0 MsgAfterException db 'After ...',0Dh,0Ah,0 .code assume fs: nothing push offset @@MyUnHandledFilter call SetUnhandledExceptionFilter xor eax, eax xor ebx, ebx dec ebx push offset @@handler push ebx mov fs:[eax],esp push ebx push cs push offset jump_to IRETD jump_to: push offset MsgDefault call Write_Log jmp Exit @@AfterException: cld push offset MsgAfterException call Write_Log Exit: push offset MsgEnd call Write_Log invoke CloseHandle,hFile invoke ExitProcess,NULL @@handler proc C pExcept: dword, pFrame: dword, pContext: dword, pDispatch: dword PrintException pExcept pushad mov edx, pContext mov eax,(CONTEXT ptr [edx]).regFlag mov edi,offset Msghandler+28 call HexChar mov edx, pContext mov eax,(CONTEXT ptr [edx]).regEip mov edi,offset Msghandler+41 call HexChar mov edx, pContext mov eax,(CONTEXT ptr [edx]).regCs mov edi,offset Msghandler+53 call HexChar push offset Msghandler call Write_Log mov edx, pContext mov (CONTEXT ptr [edx]).regEip, offset @@AfterException popad mov eax, ExceptionContinueExecution ret @@handler endp @@MyUnHandledFilter proc C pExcept: dword, pFrame: dword, pContext: dword, pDispatch: dword PrintException pExcept @@Halt: push offset MsgUnHandledFilter call Write_Log jmp @@Halt mov edx, pContext mov (CONTEXT ptr [edx]).regEip, offset @@AfterException mov eax, ExceptionContinueExecution ret @@MyUnHandledFilter endp Output: Handler got control! EFLAGS:00254616 EIP:00000000 CS:0000001b After ... ..End!
ну не я знаю. еще раз проверил все свои оси (w2k sp4, XP SP2/SP3, S2k3 SP1, Vista SP1), ни на одной SEH не вызывается. если трассировать ольгой, то хорошо видно, что после выполнения IRETD содержимое fs:[0] меняется на значение которое было до установки нашего обработчка. ага. маленькая поправка. если обработчиков больше одного, то баг не проявляется. а если обработчик один (как было показано выше), то он слетает. xor eax, eax xor ebx, ebx dec ebx push offset handler push ebx mov fs:[eax], esp вот тут мы ставим один обработчик. до его исполнение дело вообще не доходит. сразу же после выполнения IRETD у нас fs:[0] ре-иницилизируется. под отладчком SetUnhandledExceptionFilter ес-но не вызывается. а если применить плагины, которые его таки вызывают, то вызывается SEH. короче, под ольгой (1.10, 2.00j) без плагинов SetUnhandledExceptionFilter не вызывается, но fs:[0] послушно "слетает". без отладчика после слета fs:[0] вызывается SetUnhandledExceptionFilter. но это ерунда. тут натолкнулся на очевидный антиотладочный прием, с которым провозился добрые полчаса. конкретно туплю блин. сам трюк (после деобфускации) - push -1/popfd. ольга ес-но поглошает исключение при пошаговой трассировке и seh не вызывается.
kaspersky Не может Teb.Tib.ExceptionList ядром апгрейтиться, это однозначно. На счёт регистра флагов при входе в диспетчер - налаживается маска в KeContextToKframes/KeContextFromKframes, собственно для XPSP3 описано: Вероятно в отладчике какието баги, но точно не в ядре. По сути это всё дешёвые антиотладочные трюки, основанные на некоторых багаг в отладчиках, как например NtUnmapViewOfSection - изза нотификации ядром дебуггера, последний выполняет останов взводя TF, соответственно RGP при возврате из сервиса меняются.