Разбираюсь с работай SEH. Возник следующий вопрос. Правильно ли, что после работы следующего антиотладочного приёма из статьи Способы обхода отладчиков режима пользователя R4DX перестанет нормально работать SEH в данном процессе, т. к. нарушится цепочка SEH-фреймов - обработка всех исключений будет заканчиваться на ближайшем перезаписаном обработчике? Код (Text): assume fs: nothing ; Устанавливаем новый seh обработчик push offset seh_handler ; push dword ptr fs:[0] ; mov fs:[0],esp ; call DebugBreak ; jmp exit ; Если DebugBreak не вызвал ошибок, то мы здесь => нас отлаживают!!!; Выходим ;) seh_handler: ; Если мы здесь, то все ОК и нас не отлаживают!!! mov esi,[esp+0ch] ; В esi указатель на CONTEXT assume esi:PTR CONTEXT mov [esi].regEip,offset WeArentBeingDebugged ; Устанавливаем новый eip и выходим xor eax,eax ret WeArentBeingDebugged: ; Здесь основная программа...
vg От отладчика зависит, опций его и пользователя. Ерунда вобщем, нормально нужно замер времени выполнить. Хочет того отладчик, или не хочит а доставлено сообщение ему будет, а это операция тяжёлая, много времени очень требует: Код (Text): IsDebugPortSet proc C Local CallCount:ULONG Local TimeOut:ULONG assume fs:nothing Int 2AH mov ecx,eax @@: Int 2AH cmp eax,ecx je @b add eax,64*2 mov CallCount,0 mov TimeOut,eax push ebp Call Dt1 int 3 Dt1: Call Dt2 mov esp,dword ptr [esp + 4*2] mov ebp,dword ptr [esp + 4*3] mov dword ptr fs:[TEB.Tib.ExceptionList],esp inc CallCount Int 2AH cmp TimeOut,eax ja Gen mov eax,CallCount pop dword ptr fs:[TEB.Tib.ExceptionList] cmp eax,1000H setc al add esp,4 movzx eax,al ret Dt2: push dword ptr fs:[TEB.Tib.ExceptionList] Gen: mov dword ptr fs:[TEB.Tib.ExceptionList],esp cli IsDebugPortSet endp Пикод без оптимизации: db 055h, 08Bh, 0ECh, 083h, 0C4h, 0F8h, 0CDh, 02Ah, 08Bh, 0C8h db 0CDh, 02Ah, 03Bh, 0C1h, 074h, 0FAh, 005h, 080h, 000h, 000h db 000h, 0C7h, 045h, 0FCh, 000h, 000h, 000h, 000h, 089h, 045h db 0F8h, 055h, 0E8h, 001h, 000h, 000h, 000h, 0CCh, 0E8h, 033h db 000h, 000h, 000h, 08Bh, 064h, 024h, 008h, 08Bh, 06Ch, 024h db 00Ch, 064h, 089h, 025h, 000h, 000h, 000h, 000h, 0FFh, 045h db 0FCh, 0CDh, 02Ah, 039h, 045h, 0F8h, 077h, 021h, 08Bh, 045h db 0FCh, 064h, 08Fh, 005h, 000h, 000h, 000h, 000h, 03Dh, 000h db 010h, 000h, 000h, 00Fh, 092h, 0C0h, 083h, 0C4h, 004h, 00Fh db 0B6h, 0C0h, 0C9h, 0C3h, 064h, 0FFh, 035h, 000h, 000h, 000h db 000h, 064h, 089h, 025h, 000h, 000h, 000h, 000h, 0FAh P4, XPSP4, приоритет нормальный, аффинитет тоже, хотя это не важно. Отношение числа сепшенов без отладчика к числу под отладчиком примерно несколько сотен. Юзермодный дебуггер это не сможет обойти никак.
vg Не совсем. Неточность 1: не в процессе, а в потоке – SEH-фреймы специфичны для потока (указатель на первый фрейм находится в структуре, специфичной для потока, все последующие фреймы располагаются в стеке потока). Неточность 2: ничего не нарушится. Код всего лишь добавляет ещё один SEH-фрейм, совершенно валидным способом, который используется в т.ч. и компиляторами. Потом, конечно, фрейм нужно убрать, а то и правда обработка нарушится, ага. Кстати говоря, данный приём полагается исключительно на неопытность пользователя, отлаживающего код – ожидается, что юзер кликнет в отладчике "go handled" (Shift+F9 в Olly).
Sol_Ksacap Например указатель на следующий сех-фрейм замените на текущий, оля думает что это бесконечная цепочка сех фреймов и выпадает при первом исключении
Clerk Хм, любопытно. У нас почему-то не выпадает (просто пишет в статусной строке "Too long (Recursive?) SEH chain"). vg Edit: >ожидается, что юзер кликнет в отладчике "go handled" (Shift+F9 в Olly) Следует читать 'ожидается, что юзер кликнет в отладчике "go handled" (F9 в Olly)'. Ибо "Shift+F9" это как раз правильное действие – "go unhandled", да.
Sol_Ksacap На сепшине отпадёт. Вобще юзермодным дебуггером нормальную антиотладку не обойти, в тойже оле столько нюансов, что нормально код который защищается отлаживать проблемно. Например точки останова про которые автор упамянул - оля их запоминает, а это значит что она их восстанавливает где не попадя. Классическая защита, которая реализована на основе всеюзабельных манав по распаковке вскрывается элементарно, чтото немного эффективное тут без ядерного дебуггера не обойтись. Теже сех-фреймы, механизм не системный, но почемуто отладчик следит за этим, тут и траблы возникают. Почитал статью по приведённой ссылке, улыбнуло: Автор почти понял, хотя затем совсем не туда полез в поисках решения. NtSetContextThread это один из трёх сервисов, которые загружают регистр флагов без корректировки TF. Незачем пытаться обнаружить трассировку, если можно выйти из под неё, например указанным сервисом, хотя не совсем удобно. После исполнения этого сервиса поток вернётся имея в контексте сброшенный TF, тоесть после вызова этого сервиса трассировочное исключение не возникнет и безразличен этот флажёк при входе в сервис. Конечно это должно вызываться как сервис, а не как винапи, в первом случае вызывается шлюз, во втором функционал высокоуровневый и контролировать его нельзя, тоесть там до входа в шлюз может быть взведён в контексте TF.
Замер времени выполнение кода - это не больше чем шаманство. Ну попала проверка в период активного свопа и все - приехали ) P.S. Про выполнение кода под виртуальными ОСями вообще молчу - там совсем другие "скорости".
dermatolog Про выполнение любого из сервисов в ядре я вобще молчу(а безних тред ничто.). Ваша виртуальная машина г_о_в_н_о!
dermatolog ну и что, что своп? несколько раз проверил - выкинул ошибочные замеры. скорость тоже меряется и масштабируется.
Clerk Я вас попрошу без перехода на личности, а то я тоже оскорбить могу - мало не покажется. GoldFinch Я как раз и писал что замер скорости кода чреват фалсами. Для троянов и прохей хрени это может и потянет с пивом, но в коммерческий софт я бы такое никогда не засунул.
dermatolog Вы виртуальные машины упомянули, а свою я обсудить не могу.. ибо не писал, тока вашу. GoldFinch Что проверил ?
Clerk Вы перепутали топики - здесь идет обсуждение исключительно вашего кодеса ) И слово г_о_в_н_о больше подходит именно к тому, что вы тут предлагаете для vg.
dermatolog Что именно ? Тогда не будим ничего обсуждать, используем IsDebuggerPresent() или как там она, налепим стопятцот циклов pushfd, добавим дебугпринтов и выкинем это фтопку..
Clerk Читаем еще раз: Замер времени выполнения кода - это не больше чем шаманство. На реальной системе количество циклов может плавать очень сильно и 0x1000 это совсем не показатель. Под варью к примеру получается порядка 0x400 без всякого дебага. Дальше тестируйте сами - у меня больше нет времени рассказывать что и как.
dermatolog Понятно. Предложите лучшее решение для обнаружения отладочного порта. Инфоклассы ProcessDebugPort и ProcessDebugObjectHandle не учитываем, так как есчо более не надёжно.
Clerk Так вот не падает же. Плагины убрали, Olly чистую запустили – всё равно не падает. Другое дело, что на нашей винде по умолчанию включена предварительная проверка цепочки SEH-фреймов [KEXECUTE_OPTIONS: KPROCESS.ExecuteOptions.DisableExceptionChainValidation == false, SetProcessDEPPolicy\NtSetInformationProcess] и эта самая проверка (да-да, всего лишь небольшой дополнительный цикл внутри RltDispatchException) не учитывает такого хитрого расклада и уходит в бесконечное закручивание на месте. Хех. Так, это мы к чему?.. Кто-нибудь с третьей сторороны может протестировать Olly на предмет её падения при выполнении следующего кода: Код (Text): nop mov eax, fs:[0] mov [eax], eax nop ud2 nop nop
Sol_Ksacap Падает я имел ввиду что процесс вылетает отлаживаемый, но никак не оля, впрочем без разницы. На счёт #15 есть несколько идей, не буду описывать тут, вобщем несколько событий доставляют сообщение на отладочный порт, доставка некоторых из них зависит от параметров сервисов, что теоретически должно привести к отношению, которое постоянно, в этом случае число вызовов не имеет значения.
Clerk О, ясно. Не рассматривали это как некий сорт антиотладки, поскольку в этом случае поведение под отладчиком (т.е падение программы) должно соответствовать поведению без оного. Базово – лишь экстравагантный способ самоубийства. Кстати. На нашей текущей системе (S2008 x64 SP1) не падает ничего, даже если отключить ранее упомянутую предпроверку seh-цепочек – просто идёт бесконечный цикл с вызовом одного и того же первого в цепочке хендлера (цепочка, собственно, при исполнении "mov eax,fs:[0] \ mov [eax],eax" превращается в петлю, да). Конечно, если хендлер вернёт что-нибудь отличное от 'ExceptionContinueSearch' и 'ExceptionNestedException', то цикл прервётся с последующим продолжением выполнения или же поднятием нового исключения, ага.
У меня тоже все нормально. Отладчик 2 раза сообщает "Too long (Recursive?) SEH chain", а после ud2 процесс уходит в завис из-за зацикливания SEH.