Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Фильтр необработанных исключений приложения

Как уже упоминалось раньше, если ОС не нашла подходящего обработчика исключений, она вызывает функцию UnhandledExceptionFilter. Эта функция находится в kernel32.dll и имеется во всех версиях Windows. В заголовочных файлах SDK она объявлена следующим образом:

LONG UnhandledExceptionFilter(_EXCEPTION_POINTERS *ExceptionInfo);

где ExceptionInfo – это указатель на структуру, которая описывает исключение и содержимое регистров во время возникновения исключения.

Назначение этой функции – показать диалоговое окно, сообщающее, что произошло необработанное исключение, и, в зависимости от того, находится приложение под отладкой или нет, передать управление отладчику или завершить поток. Еще одной функцией этого фильтра является вызов пользовательского обработчика необработанных исключений, который может быть установлен функцией SetUnhandledExceptionFilter.

Я сознательно не упоминал о функции SetUnhandledExceptionFilter, потому что ее использование имеет ряд важных недостатков, перекрывающих преимущества, предоставляемых ее использованием. Чтобы внести ясность, давайте рассмотрим ее код:

SetUnhandledExceptionFilter: 77E7E5A1 mov ecx,dword ptr [esp+4] 77E7E5A5 mov eax,dword ptr ds:[77ED73B4h] 77E7E5AA mov dword ptr ds:[77ED73B4h],ecx 77E7E5B0 ret 4

Как видно из кода, функция берет адрес, переданный ей в качестве параметра, и помещает его в системную область памяти, возвращая предыдущее значение. Т.е. она замещает установленный ранее обработчик новым. Такое поведение говорит, что использование этой функции может привести к тому, что обработчик может быть переустановлен кем угодно.

Вторым важным недостатком использования этой функции является невозможность отладки обработчика, поскольку функция UnhandledExceptionFilter передает управление отладчику до вызова пользовательского обработчика, мешая нормальной отладке.

Если вы согласны с перечисленными недостатками использования функции SetUnhandledExceptionFilter, то давайте подумаем, как получить управление во время возникновения необработанного исключения. Если вы не согласны, то можете пропустить следующий раздел и перейти непосредственно к разделу «Сбор и сохранение информации о состоянии процесса».

Получение управления

До сих пор речь шла о механизме обработки исключений, используемом в ОС Windows, и о том, как он используется компиляторами. Реализованный выше простой алгоритм подменяет установленный компилятором обработчик, что позволяет получить управление при возникновении в приложении необработанного исключения. Но алгоритм был рассчитан на однопоточное приложение, а это значительно сужает возможности его использования. Кроме всего прочего, если в приложении возникает необработанное исключение, то установленный Runtime-библиотекой обработчик вызывает функцию UnhandledExceptionFilter, которая также может вызваться операционной системой. Таким образом, функция UnhandledExceptionFilter является ключевой системной функцией, которая обрабатывает все необработанные исключения. Подмена этой функции позволила бы выполнить поставленную задачу.

Поскольку функция UnhandledExceptionFilter может быть вызвана как из обработчика Runtime, так и системой, то изменение ее адреса в таблице импортируемых функций может не решить всей проблемы, поэтому для большей надежности нужно изменить код функции UnhandledExceptionFilter так, что бы сразу после ее вызова управление попадало к нам. К статье прилагается проект ehfilter, в котором реализован класс CatUnhandledExceptionFilter, устанавливающий обработчик необработанных исключений. Объявление класса CatUnhandledExceptionFilter приведено ниже:

class CatUnhandledExceptionFilter { private:  friend LONG myUnhandledExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);    UINT_PTR m_oldSystemUnhandledFilter;    LONG UnhandledExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo); public:  CatUnhandledExceptionFilter();  ~CatUnhandledExceptionFilter();    ool HookUpUnhandledFilter(); };

где

m_oldSystemUnhandledFilter – адрес оригинальной функции UnhandledExceptionFilter.

myUnhandledExceptionFilter – дружественная классу функция-переходник, ее назначение и код будут рассмотрены ниже.

UnhandledExceptionFilter – наш фильтр необработанных исключений

HookUpUnhandledFilter – функция установки нашего фильтра исключений.

Проект ehfilter является обычной DLL, которая должна быть загружена в адресное пространство приложения. Во время загрузки библиотеки в файле main.cpp создается глобальная переменная gFeedBackFilter типа CatUnhandledExceptionFilter. Во время создания этой переменной в конструкторе определяется адрес функции UnhandledExceptionFilter и запоминается в переменной m_oldSystemUnhandledFilter. Когда в библиотеку приходит сообщение DLL_PROCESS_ATTACH, вызывается функция HookUpUnhandledFilter, которая устанавливает наш фильтр необработанных исключений.

Код функции HookUpUnhandledFilter приведен ниже:

bool CatUnhandledExceptionFilter::HookUpUnhandledFilter()

{

 if (m_oldSystemUnhandledFilter == 0)

 return false;

 

 DWORD addr = m_oldSystemUnhandledFilter;

 DWORD old = 0;

 if (TRUE == VirtualProtect((LPVOID)addr, 5, PAGE_READWRITE, &old))

 {

 unsigned char *p = (unsigned char*)addr;

 *p = 0xE9;

 UINT_PTR ehFilter = (UINT_PTR)myUnhandledExceptionFilter;

 addr += 5;

 ehFilter = ehFilter - addr;

 p++;

 DWORD *pp = (DWORD*)p;

 *pp = ehFilter;

 m_oldSystemUnhandledFilter += 5;

 VirtualProtect((LPVOID)addr, 5, old, &old);

 return true;

 }

 return false;

}

ПРИМЕЧАНИЕ

Этот код будет работать только в семействе ОС Windows NT. Дело в том, что 2 верхних гигабайта, где размещены системные библиотеки, в Windows 9х недоступны на запись из пользовательского (user) режима. – прим.ред.

     

Сначала функция проверяет, был ли найден системный обработчик UnhandledExceptionFilter. Если он не найден, функция возвращает false и завершает свою работу. Затем, поскольку необходимо писать в системную область памяти, изменяются атрибуты доступа к ней, что делает ее доступной для чтений/записи, и записывается инструкция безусловного перехода на функцию-переходник myUnhandledExceptionFilter. Функция-переходник имеет две цели – это вызвать фильтр и вернуть управление системной функции.

Приведенные в примере реализации функций HookUpUnhandledFilter и myUnhandledExceptionFilter являются сильно упрощенными и, конечно, неприменимы в реальной жизни. Мало того, попытка их применения может привести к печальным последствиям. Однако они достаточны для иллюстрации механизма подмены вызова системных функций. В реальности же необходимо дизассемблировать код функции UnhandledExceptionFilter, запоминать его и затем использовать при возврате управления. Но это в значительной мере усложнило бы код и могло скрыть основной его смысл, поэтому я решил оставить эту реализацию для демонстрации самого факта возможности подобных действий.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...