Arhn - архитектура программирования

Как сообщить о переполнении буфера стека в Windows?

В коде, показанном ниже, я использовал все задокументированные способы обнаружения исключения и создания диагностики. Он использует ключевые слова C++ try/catch, перехватывает исключения SEH с ключевыми словами расширения __try/__catch, использует WinAPI-функции AddVectoredExceptionHandler() и SetUnhandledExceptionFilter() для установки фильтров VEH/SEH.

Выполнение этого с Visual C++ 2003:
/GS: выводит "hello,world!" и завершается с кодом выхода 0.
/GS-: выводит "hello,world!" и завершается с кодом выхода 0.

Выполнение этого с Visual C++ 2013:
/GS: ничего не выводится, завершается кодом выхода -1073740791
/GS-: выводит "hello,world!" и завершается выходом с 0.

Как создать диагностику в скомпилированной программе VS2013 с действующим параметром /GS?

#include "stdafx.h"
#include <Windows.h>

#define CALL_FIRST 1  
#define CALL_LAST 0

LONG WINAPI MyVectoredHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
    UNREFERENCED_PARAMETER(ExceptionInfo);

    printf("MyVectoredHandler\n");
    return EXCEPTION_CONTINUE_SEARCH;
}

LONG WINAPI MyUnhandledExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
{
    printf("SetUnhandledExceptionFilter\n");

    return EXCEPTION_CONTINUE_SEARCH;
}

void f()
{
    __try
    {
        char p[20] = "hello,world!";
        p[24] = '!';
        printf("%s\n", p);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        printf("f() exception\n");
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    AddVectoredExceptionHandler(CALL_FIRST, MyVectoredHandler);
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

    try{
        f();
    }
    catch (...){
        printf("catched f exception\n");
    }
    return 0;
}
25.05.2016

  • Ваш код вызывает неопределенное поведение. Единственный надежный способ обнаружения — проверить границы перед выполнением доступа за пределы границ. 25.05.2016
  • ... например, что было бы сделано, если бы вы использовали тип контейнера, который выполняет обнаружение. например используя std::string для строк и индексируя его с помощью функции-члена at. 25.05.2016
  • Переполнение стека трудно обнаружить. Они срабатывают только при перезаписи кадра стека. Попробуйте включить исключение времени выполнения Границы массива превышены. Это может сработать. 25.05.2016

Ответы:


1

Функция CRT, которая обрабатывает обнаружение переполнения буфера стека, __report_gsfailure(), предполагает, что повреждение кадра стека было вызвано атакой вредоносного ПО. Такое вредоносное ПО традиционно связывалось с фильтрами исключений fs:[0] SEH (хранящимися во фрейме стека), чтобы получить обработчик исключений для запуска полезной нагрузки вредоносного ПО. Один из способов заставить данные превратиться в исполняемый код.

Так что функция CRT не может предположить, что создание исключения безопасно. И больше не входит в CRT, включенный в VS2013, восходит к ~ VS2005. Он будет отказоустойчивым, если ОС его поддерживает, а если нет, гарантирует, что зарегистрированный обработчик исключений VEH/SEH также не сможет увидеть исключение. Kaboom, вылет на рабочий стол без диагностики, если у вас не подключен отладчик.

Параметр /SAFESEH предотвращает подобные атаки вредоносных программ, поэтому они не так серьезны, как раньше. Если вы все еще находитесь на этапе, когда ваш код страдает от ошибок, приводящих к повреждению стека, а ваше приложение недостаточно популярно, чтобы стать мишенью вредоносного ПО, вы можете подумать о замене функции CRT.

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

Вставьте этот код где-нибудь рядом с вашей функцией main():

__declspec(noreturn) extern "C"
void __cdecl __report_gsfailure() {
    RaiseException(STATUS_STACK_BUFFER_OVERRUN, EXCEPTION_NONCONTINUABLE, 0, nullptr);
}

И планирую удалить его снова в ближайшее время.

25.05.2016
  • Ошибка ссылки при добавлении пользовательского __report_gsfailure: error LNK2005: ___report_gsfailure 已经在 LIBCMT.lib(gs_report.obj) 中定义 26.05.2016
  • Хм, это проверенный код, проверено, что он работает на VS2015. Понятия не имею, что говорит китайский текст, похоже, что gs_report.obj уже был загружен другой библиотекой, так что теперь их две. Используйте параметр компоновщика /VERBOSE, чтобы узнать, почему был использован файл gs_report.obj. И настоятельно, настоятельно одобряйте сборку с /MD вместо /MT. 26.05.2016
  • Спасибо за это решение. Согласно моим выводам, msvcrtd также вызывает еще один __report_gsfailure, поэтому это работает только в сборках Release. 28.11.2016

  • 2

    Нет решения заданного вопроса.

    Выход за пределы массива приводит к неопределенному поведению в стандартном C++, поэтому никакой конкретный результат не гарантируется. Неспособность дать надежный результат не является проблемой для компилятора — это допустимое поведение.

    Я не знаю ни одной реализации, которая гарантировала бы какое-либо конкретное поведение в ответ на переполнение - VS, конечно, этого не делает. Что неудивительно, поскольку от компиляторов этого не требуется (в этом, по сути, смысл неопределенного поведения). Причина этого заключается в том, что часто бывает трудно надежно или постоянно обнаруживать такие случаи.

    Это означает, что единственный непротиворечивый способ обнаружить переполнение массива — это проверить допустимость индексов массива ДО их использования для доступа к элементу массива и предпринять соответствующие действия (например, создать исключение, которое можно перехватить, вместо того, чтобы выполнять неверную операцию). Недостатком является то, что он не предоставляет простого и надежного способа обнаружения ошибок в произвольном коде, за исключением изменения всего кода для выполнения необходимых проверок.

    25.05.2016

    3

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

    Я попробовал решение с Visual Studio 2017, и мне пришлось внести пару изменений, чтобы решение скомпилировалось.

    Сначала мне пришлось изменить подпись __report_gsfailure, чтобы она соответствовала одному из заголовочных файлов Microsoft, чтобы исправить ошибку компиляции.

    __declspec(noreturn) extern "C" void __cdecl __report_gsfailure(_In_ uintptr_t _StackCookie)
    {
        RaiseException(STATUS_STACK_BUFFER_OVERRUN, EXCEPTION_NONCONTINUABLE, 0, nullptr);
    }
    

    Затем я столкнулся с ошибкой LNK2005, которую мне удалось исправить, добавив /FORCE:MULTIPLE в Linker->Command Line для свойств моего проекта.

    29.08.2019
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..