взломКрис КасперскиЭнциклопедияантиотладочныхприемовОбработка необрабатываемых исключенийОтладчики, работающие через MS Debugging API (OllyDbg, IDA-Pro, MS VC),вынуждены мириться с тем, что отладочные процессы «страдают» хроническимиособенностями поведения. Они «ломают» логику программы, и этос огромной выгодой используют защитные механизмы. В частности, APIфункцияSetUnhandledExceptionFilter() под отладчиком вообще не вызывается— вовсе не баг отладчика, а документированная фича системы!066FundamentalsРассматривая обработку структурных исключений в предыдущемвыпуске, мы мельком упомянули, что всякий процесс от рождения получаетпервичный обработчик структурных исключений, назначаемыйоперационной системой по умолчанию. Если программист забыл (илине захотел) назначать свои собственные обработчики, то все исключения,возникающие в ходе выполнения программы, попадают в пастьпервичного обработчика. Он расположен в NTDLL.DLL и, в зависимостиот настроек оси, либо вызывает «Доктора Ватсона», либо выводитзнаменитый диалог о критической ошибке с вариантами: «ОК»— завершить приложение в аварийном режиме и «Cancel» — вызыватьJust-in-Time отладчик (в роли которого может выступать и Ольга).То же самое происходит, если программист устанавливает один илинесколько обработчиков структурных исключений, но никто из них не всостоянии справиться с ситуацией — вот они и передают исключениедруг другу, пока оно не докатится до системного обработчика. Системныйобработчик легко подменить своим (было бы желание). Достаточновместо ссылки на предыдущий EXCEPTION_REGISTRATION затолкатьв поле prev значение «-1». Это будет свидетельствовать, что данныйобработчик — последний в цепочке.Как вариант, можно воспользоваться API-функцией SetUnhandledExceptionFilter(), перекрывающей обработчик исключенийверхнего уровня (top-level exception handler). Да, именно «верхнего»,поскольку Windows создавалась в Америке, расположенной на противоположнойстороне Земли, где люди ходят вверх ногами. Первичныйсистемный обработчик, с их точки зрения, находится на вершинепирамиды структурных исключений, в то время как русские программистысклоны рассматривать его как «основание». Но это все лирика, адело-то в том, что...Функция SetUnhandledExceptionFilter(), перекрываясистемный обработчик, в неволе работать отказывается, то естьполучает управление только, когда процесс не находится под от-xàêåð 07 /115/ 08
взломЗапуск тестовой программы под «чистой» Ольгой(без специальных plug-in’ов) приводит к детекцииотладчикаОтладчики Soft-Ice и Syser также «палятся», еслирычажок «I3HERE» установлен в положение «ON»ладчиком. В противном случае исключение передаетсянепосредственно самому отладчику. Это — задумкапроектировщиков, кстати сказать, довольно оригинальнаяи полезная. Если отладчика нет — установленныйпрограммистом обработчик берет управлениена себя и завершает работу программы максимальнокорректным образом. Если же процесс находится подотладкой, операционная система передает браздыправления отладчику, позволяя разобраться сситуацией, поскольку после завершения программыразбираться будет не с чем и некому.А теперь, внимание, вопрос! Что произойдет, если вобработчик, установленный SetUnhandledExceptionFilter(), воткнуть не код аварийного завершенияприложения, а кусок функционала, например,расшифровщик какой или просто пару строк на Си,меняющих значение флага under_debuuger? Правильно— мы получим великолепный способ детектаотладчиков прикладного уровня!Эксперимент — pro-n-contraSetUnhandledExceptionFilterНапишем простейшую тестовую программу, позволяющуюисследовать реакцию отладчиков на фильтр, установленныйфункцией SetUnhandledExceptionFilter().На crackme она никак не тянет (слишком прозрачна иэлементарна), но crackme мы написать завсегда успеем!Сейчас главное врубиться в тему и выяснить — наскольконадежен этот трюк, можно ли его обойти и если да, то как?Один из примеров реализации тестового стенда приведенниже.Исходный текст программы SetUnhandledExceptionFilter,демонстрирующей технику использования функции дляборьбы с отладчиками#include char dbgnoo[]= "debugger is not detected";char dbgyes[]= "debugger is detected :-)";// we expect debugger by defaultchar *p = dbgyes;xàêåð 07 /115/ 08LONG souriz(struct _EXCEPTION_POINTERS *ExceptionInfo){// if we’re here, process is _not_ underdebuggerp = dbgnoo;// skip INT 03 (CCh) commandExceptionInfo->ContextRecord->Eip++;// we want the program to continue executionreturn EXCEPTION_CONTINUE_EXECUTION;}nezumi(){// supersede the default top-level exceptionhandler by souriz() procSetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)&souriz);__asm {int 03 ; // generate an exception}OllyDbg 1.xимеет коварный баг!Ольга версии 1.10 имеет неприятный баг — если непосредственно заINT 03h следует команда PUSHFD, заталкивающая флаги в стек, отладчикедет крышей и теряет управление над отлаживаемой программой,даже если мы нажимаем / (Step Into/Step Over). Для демонстрациибага достаточно воткнуть в листинг пару команд PUSHFD/POPFD. А вот те же самые команды, отделенные от INT 03h одной илинесколькими инструкциями NOP (или любыми другими) работают вполненормально.В Ольге 2.х ошибка уже исправлена, однако, учитывая, что 2.х все еще находится встадии разработки, основным инструментом хакеров остается Ольга 1.10 с багомна борту.067