_Great_
13.02.2007, 13:39
Article: Цветной экран смерти
Author: Great
Date: 13.02.2007
Lang: C/C++ kernel mode
Note: Ко всем приелось уже знакомое сокращение - BSoD (Blue Screen of Death, Синий Экран Смерти). А что если... сделать его не синим. А, например, серым. Или зеленым?
UPD: прежде чем прочитать, рекомендую в конце статьи найти ссылки на скриншоты и посмотреть :)
Если ты кодил под Ring 0, то знаешь, что за показ экрана смерти ответственны функции ядра KeBugCheck и KeBugCheckEx.
Правда, это реализовано немного по-разному в Windows 2000 и ниже и в Windows XP и выше.
В Windows 2000 всю работу делает KeBugCheckEx, а KeBugCheck - обертка.
В Windows XP KeBugCheckEx и KeBugCheck - обертки, всю работу делает внутренняя неэкспортируемая функция ядра KeBugCheck2.
Где-то в теле функции происходит задание фона для экрана смерти. Мы попробуем его найти и пропатчить прямо в памяти. Для простоты мы будем писать для Windows XP, а отчасти и из-за того, что сейчас она установлена на большем числе компьютеров, чем Windows 2000.
Поскольку все смещения и т.п. сильно зависят от билда, тут есть два пути - прописать смещения жестко для каждого билда или искать нужные данные динамически. Чтобы не усложнять себе жизнь, мы выберем первый вариант и пропишем смещения только для системы "Windows XP build 2600".
Посмотрим на код функции KeBugCheck2:
//
// Enable InbvDisplayString calls to make it through to bootvid driver.
//
if (InbvIsBootDriverInstalled()) {
InbvAcquireDisplayOwnership();
InbvResetDisplay();
InbvSolidColorFill(0,0,639,479,4); // make the screen blue
InbvSetTextColor(15);
InbvInstallDisplayStringFilter((INBV_DISPLAY_STRIN G_FILTER)NULL);
InbvEnableDisplayString(TRUE); // enable display string
InbvSetScrollRegion(0,0,639,479); // set to use entire screen
}
интересующую нас строчку я выделил. тут происходит задание цвета фона.
Нам надо только лишь его поменять. Поехали!
Итак, мы пишем под Windows XP 2600. Откроем в IDA Pro код KeBugCheckEx:
.text:0045C303 _KeBugCheckEx@20 proc near
.text:0045C303 BugCheckCode = dword ptr 8
.text:0045C303 BugCheckParameter1= dword ptr 0Ch
.text:0045C303 BugCheckParameter2= dword ptr 10h
.text:0045C303 BugCheckParameter3= dword ptr 14h
.text:0045C303 BugCheckParameter4= dword ptr 18h
.text:0045C303
.text:0045C303 mov edi, edi
.text:0045C305 push ebp
.text:0045C306 mov ebp, esp
.text:0045C308 push 0 ; int
.text:0045C30A push [ebp+BugCheckParameter4] ; int
.text:0045C30D push [ebp+BugCheckParameter3] ; int
.text:0045C310 push [ebp+BugCheckParameter2] ; int
.text:0045C313 push [ebp+BugCheckParameter1] ; int
.text:0045C316 push [ebp+BugCheckCode] ; int
.text:0045C319 call _KeBugCheck2@24 ; KeBugCheck2(x,x,x,x,x,x)
Вот тут как раз и вызывается внутренняя функция KeBugCheck2. Опкод этой команды CALL выглядит так: E8 9CF4FFFF. E8 - код команды call, 9CF4FFFF - смещение KeBugCheck2 относительно следующей команды. Адрес команды call равен 0045C319, + 1 байт, мы получим 0045C31A - адрес смещения.
0045C31Ah - 0045C303h (адрес KeBugCheckEx) = 17h - то есть адрес смещения функции KeBugCheck2 лежит через 17h байт после начала KeBugCheckEx.
Что ж.. нам это пригодится. Глянем внутрь KeBugCheck2 и найдем вызов InbvSolidColorFill, устанавливающей цвет фона экрана:
.text:0045BDA3 push 4
.text:0045BDA5 push 1DFh
.text:0045BDAA mov ebx, 27Fh
.text:0045BDAF push ebx
.text:0045BDB0 push esi
.text:0045BDB1 push esi
.text:0045BDB2 call _InbvSolidColorFill@20 ; InbvSolidColorFill(x,x,x,x,x)
Так-так. PUSH 4 - как раз заталкивание в стек цвета фона (4 - синий). Опкод команды PUSH 4 выглядит так: 6A 04 PUSH 4. Нам нужно изменить операнд команды PUSH. Адрес начала KeBugCheck2 - 0045B7BA, адрес операнда команды PUSH - 0045BDA4. Не нужно быть гением, чтобы посчитать разницу - 5EA.
Вот мы и собрали все нужные нам данные. Приступим к кодерской части.
Реализация будет такова - мы напишем драйвер ядра, у которого по DeviceIoControl можно вызвать 2 функции - прочитать текущий цвет и записать новый.
С учетом всего вышенаписнаного, вот вспомогательная функция для получения адреса байта, где лежит цвет фона:
PUCHAR GetBugcheckColorAddress()
{
DWORD addr = (DWORD) &KeBugCheckEx;
addr += 0x17;
addr = addr + 4 + *(DWORD*)addr;
addr += 0x5EA;
return (PUCHAR) addr;
}
Определим следующие два кода для DeviceIoControl:
#define IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR 0x0014
#define IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR 0x0024
Проследим, чтобы младшие 2 бита были сброшены - они показывают тип ввода-вывода при DeviceIoControl. 00 означает буферизированный ввод-вывод, он нам и нужен. Диспетчер ввода-вывода выделит системный буфер, скопирует пользовательский буфер в системный, мы его будем изменять как хотим, а потом системный буфер скопируется обратно в выходной.
Напишем вот такую функцию для обработки IRP_MJ_DEVICE_CONTROL:
NTSTATUS DriverIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION pisl = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG BuffSize = pisl->Parameters.DeviceIoControl.InputBufferLength;
PUCHAR pBuff = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Information = 0;
switch(pisl->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR:
if (pBuff && pisl->Parameters.DeviceIoControl.OutputBufferLength >= 1)
{
DPRINT("[~] DeviceIoControl : IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR");
__try
{
if(*NtBuildNumber != 2600)
{
DPRINT("[!] This driver supports only Windows XP build 2600, current build is %d", *NtBuildNumber);
status = STATUS_ILLEGAL_FUNCTION;
break;
}
PUCHAR lpBugcheckColor = GetBugcheckColorAddress();
*pBuff = *lpBugcheckColor;
DPRINT("[+] Search completed. Address is 0x%08x, bugcheck color is %02x", lpBugcheckColor, *pBuff);
Irp->IoStatus.Information = 1;
status = STATUS_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
Irp->IoStatus.Status = status = GetExceptionCode();
Irp->IoStatus.Information = 0;
DPRINT("[!] Unhandled exception %.x", status);
break;
}
}
break;
case IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR:
DPRINT("Buffer size = %d", BuffSize);
if (pBuff && BuffSize >= 1 && pisl->Parameters.DeviceIoControl.OutputBufferLength >= 1)
{
DPRINT("[~] DeviceIoControl : IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR");
__try
{
if(*NtBuildNumber != 2600)
{
DPRINT("[!] This driver supports only Windows XP build 2600, current build is %d", *NtBuildNumber);
status = STATUS_ILLEGAL_FUNCTION;
break;
}
PUCHAR lpBugcheckColor = GetBugcheckColorAddress();
BYTE oldcolor = *lpBugcheckColor;
DPRINT("[+] Search completed. Address is 0x%08x, bugcheck color is %02x", lpBugcheckColor, oldcolor);
DPRINT("[~] Requested color is %02x", *pBuff);
*lpBugcheckColor = *pBuff;
*pBuff = oldcolor;
DPRINT("[+] New color set: %02x, color returned: %02x", *lpBugcheckColor, *pBuff);
Irp->IoStatus.Information = 1;
status = STATUS_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
Irp->IoStatus.Status = status = GetExceptionCode();
Irp->IoStatus.Information = 0;
DPRINT("[!] Unhandled exception %.x", status);
break;
}
}
break;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
Я думаю, стоит кое-что пояснить. Сначала мы получаем текущий стек ввода-вывода, адрес системного буфера и размеры входного и выходного буферов.
Дальше смотрим, что же от нас хотят - прочитать или установить новый цвет. Основной код обернут в __try/__except, чтобы, не дай Бог, случайно не уронить систему, если что.
Мы проверяем NtBuildNumber - номер билда ОС и ругаемся, если он не 2600. Дальше мы получаем адрес байта с цветом фона и химичим с ним. Выставляем в Irp->IoStatus.Information число байт, которое нужно скопировать в пользовательский буфер из системного.
Остальной код драйвера комментировать, думаю, не стоит:
#define _X86_
#include <ntddk.h>
#define DPRINT DbgPrint
UNICODE_STRING DeviceName;
UNICODE_STRING SymbolicLinkName;
PDEVICE_OBJECT deviceObject;
void DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
IoDeleteSymbolicLink (&SymbolicLinkName);
if(deviceObject)
IoDeleteDevice (deviceObject);
DPRINT ("[+] Driver unloaded");
}
extern "C" PUSHORT NtBuildNumber;
NTSTATUS DriverIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DriverCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
DPRINT("[~] Driver loading");
RtlInitUnicodeString(&DeviceName, L"\\Device\\faultdriver");
RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\faultdriver");
status = IoCreateDevice(DriverObject,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&deviceObject);
if (!NT_SUCCESS(status))
{
DPRINT("[-] Failed to create device. IoCreateDevice returned %x", status);
return STATUS_UNSUCCESSFUL;
}
deviceObject->Flags |= DO_BUFFERED_IO;
status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
if (!NT_SUCCESS(status))
{
DPRINT("[-] Failed to create symbolic link. IoCreateSymbolicLink returned %x", status);
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
// Set dispath routines
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction [IRP_MJ_CREATE] =
DriverObject->MajorFunction [IRP_MJ_CLOSE ] = DriverCreateClose;
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL ] = DriverIoControl;
DPRINT("[+] Driver initialization successful");
return STATUS_SUCCESS;
}
Теперь у нас готов работающий драйвер, который умеет оперировать с цветом фона для экрана смерти.
Напишем несложное GUI для этого. Я приведу только код юзермодных функций для работы с цветом:
// User mode API
#define IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR 0x0014
#define IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR 0x0024
UCHAR GetCurrentBugcheckColor()
{
HANDLE hDevice = CreateFile("\\\\.\\faultdriver", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if(hDevice == INVALID_HANDLE_VALUE)
return -1;
DWORD ret;
char buffer;
if(!DeviceIoControl(
hDevice,
IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR,
&buffer, sizeof(buffer),
&buffer, sizeof(buffer),
&ret,
0
))
{
CloseHandle(hDevice);
return -1;
}
else
{
CloseHandle(hDevice);
return buffer;
}
}
UCHAR SetCurrentBugcheckColor(UCHAR cNew)
{
HANDLE hDevice = CreateFile("\\\\.\\faultdriver", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if(hDevice == INVALID_HANDLE_VALUE)
return -1;
DWORD ret;
char buffer = cNew;
if(!DeviceIoControl(
hDevice,
IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR,
&buffer, sizeof(buffer),
&buffer, sizeof(buffer),
&ret,
0
))
{
CloseHandle(hDevice);
return -1;
}
else
{
CloseHandle(hDevice);
return buffer;
}
}
Вот и все :) Бинарники и сорсы можно найти тут: http://cribble.by.ru/bugcheck.rar
Для запуска нужно распаковать GUI-программку и бинарник драйвера в одну директорию и запустить EXEшник (он сам загрузит драйвер и выгрузит по окончании работы).
В соотв. каталогах в rar'e находятся проекты с сорцами для компилера Microsoft Visual C++ 6.0
Для тестирования пригодится программка М.Руссиновича "NotMyFault", которую можно скачать тут: http://www.sysinternals.com/Files/Notmyfault.zip
Удачи, пока!
ЗЫ. Посмотреть, как это выглядит, можно на скриншотах:
http://img255.imageshack.us/img255/1978/deathob9.png
http://img503.imageshack.us/img503/6316/xexe2zs3.png
http://img520.imageshack.us/img520/6940/xexe3if0.png
Зеленый симпотичный, правда? :)
Author: Great
Date: 13.02.2007
Lang: C/C++ kernel mode
Note: Ко всем приелось уже знакомое сокращение - BSoD (Blue Screen of Death, Синий Экран Смерти). А что если... сделать его не синим. А, например, серым. Или зеленым?
UPD: прежде чем прочитать, рекомендую в конце статьи найти ссылки на скриншоты и посмотреть :)
Если ты кодил под Ring 0, то знаешь, что за показ экрана смерти ответственны функции ядра KeBugCheck и KeBugCheckEx.
Правда, это реализовано немного по-разному в Windows 2000 и ниже и в Windows XP и выше.
В Windows 2000 всю работу делает KeBugCheckEx, а KeBugCheck - обертка.
В Windows XP KeBugCheckEx и KeBugCheck - обертки, всю работу делает внутренняя неэкспортируемая функция ядра KeBugCheck2.
Где-то в теле функции происходит задание фона для экрана смерти. Мы попробуем его найти и пропатчить прямо в памяти. Для простоты мы будем писать для Windows XP, а отчасти и из-за того, что сейчас она установлена на большем числе компьютеров, чем Windows 2000.
Поскольку все смещения и т.п. сильно зависят от билда, тут есть два пути - прописать смещения жестко для каждого билда или искать нужные данные динамически. Чтобы не усложнять себе жизнь, мы выберем первый вариант и пропишем смещения только для системы "Windows XP build 2600".
Посмотрим на код функции KeBugCheck2:
//
// Enable InbvDisplayString calls to make it through to bootvid driver.
//
if (InbvIsBootDriverInstalled()) {
InbvAcquireDisplayOwnership();
InbvResetDisplay();
InbvSolidColorFill(0,0,639,479,4); // make the screen blue
InbvSetTextColor(15);
InbvInstallDisplayStringFilter((INBV_DISPLAY_STRIN G_FILTER)NULL);
InbvEnableDisplayString(TRUE); // enable display string
InbvSetScrollRegion(0,0,639,479); // set to use entire screen
}
интересующую нас строчку я выделил. тут происходит задание цвета фона.
Нам надо только лишь его поменять. Поехали!
Итак, мы пишем под Windows XP 2600. Откроем в IDA Pro код KeBugCheckEx:
.text:0045C303 _KeBugCheckEx@20 proc near
.text:0045C303 BugCheckCode = dword ptr 8
.text:0045C303 BugCheckParameter1= dword ptr 0Ch
.text:0045C303 BugCheckParameter2= dword ptr 10h
.text:0045C303 BugCheckParameter3= dword ptr 14h
.text:0045C303 BugCheckParameter4= dword ptr 18h
.text:0045C303
.text:0045C303 mov edi, edi
.text:0045C305 push ebp
.text:0045C306 mov ebp, esp
.text:0045C308 push 0 ; int
.text:0045C30A push [ebp+BugCheckParameter4] ; int
.text:0045C30D push [ebp+BugCheckParameter3] ; int
.text:0045C310 push [ebp+BugCheckParameter2] ; int
.text:0045C313 push [ebp+BugCheckParameter1] ; int
.text:0045C316 push [ebp+BugCheckCode] ; int
.text:0045C319 call _KeBugCheck2@24 ; KeBugCheck2(x,x,x,x,x,x)
Вот тут как раз и вызывается внутренняя функция KeBugCheck2. Опкод этой команды CALL выглядит так: E8 9CF4FFFF. E8 - код команды call, 9CF4FFFF - смещение KeBugCheck2 относительно следующей команды. Адрес команды call равен 0045C319, + 1 байт, мы получим 0045C31A - адрес смещения.
0045C31Ah - 0045C303h (адрес KeBugCheckEx) = 17h - то есть адрес смещения функции KeBugCheck2 лежит через 17h байт после начала KeBugCheckEx.
Что ж.. нам это пригодится. Глянем внутрь KeBugCheck2 и найдем вызов InbvSolidColorFill, устанавливающей цвет фона экрана:
.text:0045BDA3 push 4
.text:0045BDA5 push 1DFh
.text:0045BDAA mov ebx, 27Fh
.text:0045BDAF push ebx
.text:0045BDB0 push esi
.text:0045BDB1 push esi
.text:0045BDB2 call _InbvSolidColorFill@20 ; InbvSolidColorFill(x,x,x,x,x)
Так-так. PUSH 4 - как раз заталкивание в стек цвета фона (4 - синий). Опкод команды PUSH 4 выглядит так: 6A 04 PUSH 4. Нам нужно изменить операнд команды PUSH. Адрес начала KeBugCheck2 - 0045B7BA, адрес операнда команды PUSH - 0045BDA4. Не нужно быть гением, чтобы посчитать разницу - 5EA.
Вот мы и собрали все нужные нам данные. Приступим к кодерской части.
Реализация будет такова - мы напишем драйвер ядра, у которого по DeviceIoControl можно вызвать 2 функции - прочитать текущий цвет и записать новый.
С учетом всего вышенаписнаного, вот вспомогательная функция для получения адреса байта, где лежит цвет фона:
PUCHAR GetBugcheckColorAddress()
{
DWORD addr = (DWORD) &KeBugCheckEx;
addr += 0x17;
addr = addr + 4 + *(DWORD*)addr;
addr += 0x5EA;
return (PUCHAR) addr;
}
Определим следующие два кода для DeviceIoControl:
#define IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR 0x0014
#define IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR 0x0024
Проследим, чтобы младшие 2 бита были сброшены - они показывают тип ввода-вывода при DeviceIoControl. 00 означает буферизированный ввод-вывод, он нам и нужен. Диспетчер ввода-вывода выделит системный буфер, скопирует пользовательский буфер в системный, мы его будем изменять как хотим, а потом системный буфер скопируется обратно в выходной.
Напишем вот такую функцию для обработки IRP_MJ_DEVICE_CONTROL:
NTSTATUS DriverIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION pisl = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG BuffSize = pisl->Parameters.DeviceIoControl.InputBufferLength;
PUCHAR pBuff = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Information = 0;
switch(pisl->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR:
if (pBuff && pisl->Parameters.DeviceIoControl.OutputBufferLength >= 1)
{
DPRINT("[~] DeviceIoControl : IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR");
__try
{
if(*NtBuildNumber != 2600)
{
DPRINT("[!] This driver supports only Windows XP build 2600, current build is %d", *NtBuildNumber);
status = STATUS_ILLEGAL_FUNCTION;
break;
}
PUCHAR lpBugcheckColor = GetBugcheckColorAddress();
*pBuff = *lpBugcheckColor;
DPRINT("[+] Search completed. Address is 0x%08x, bugcheck color is %02x", lpBugcheckColor, *pBuff);
Irp->IoStatus.Information = 1;
status = STATUS_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
Irp->IoStatus.Status = status = GetExceptionCode();
Irp->IoStatus.Information = 0;
DPRINT("[!] Unhandled exception %.x", status);
break;
}
}
break;
case IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR:
DPRINT("Buffer size = %d", BuffSize);
if (pBuff && BuffSize >= 1 && pisl->Parameters.DeviceIoControl.OutputBufferLength >= 1)
{
DPRINT("[~] DeviceIoControl : IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR");
__try
{
if(*NtBuildNumber != 2600)
{
DPRINT("[!] This driver supports only Windows XP build 2600, current build is %d", *NtBuildNumber);
status = STATUS_ILLEGAL_FUNCTION;
break;
}
PUCHAR lpBugcheckColor = GetBugcheckColorAddress();
BYTE oldcolor = *lpBugcheckColor;
DPRINT("[+] Search completed. Address is 0x%08x, bugcheck color is %02x", lpBugcheckColor, oldcolor);
DPRINT("[~] Requested color is %02x", *pBuff);
*lpBugcheckColor = *pBuff;
*pBuff = oldcolor;
DPRINT("[+] New color set: %02x, color returned: %02x", *lpBugcheckColor, *pBuff);
Irp->IoStatus.Information = 1;
status = STATUS_SUCCESS;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
Irp->IoStatus.Status = status = GetExceptionCode();
Irp->IoStatus.Information = 0;
DPRINT("[!] Unhandled exception %.x", status);
break;
}
}
break;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
Я думаю, стоит кое-что пояснить. Сначала мы получаем текущий стек ввода-вывода, адрес системного буфера и размеры входного и выходного буферов.
Дальше смотрим, что же от нас хотят - прочитать или установить новый цвет. Основной код обернут в __try/__except, чтобы, не дай Бог, случайно не уронить систему, если что.
Мы проверяем NtBuildNumber - номер билда ОС и ругаемся, если он не 2600. Дальше мы получаем адрес байта с цветом фона и химичим с ним. Выставляем в Irp->IoStatus.Information число байт, которое нужно скопировать в пользовательский буфер из системного.
Остальной код драйвера комментировать, думаю, не стоит:
#define _X86_
#include <ntddk.h>
#define DPRINT DbgPrint
UNICODE_STRING DeviceName;
UNICODE_STRING SymbolicLinkName;
PDEVICE_OBJECT deviceObject;
void DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
IoDeleteSymbolicLink (&SymbolicLinkName);
if(deviceObject)
IoDeleteDevice (deviceObject);
DPRINT ("[+] Driver unloaded");
}
extern "C" PUSHORT NtBuildNumber;
NTSTATUS DriverIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DriverCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
DPRINT("[~] Driver loading");
RtlInitUnicodeString(&DeviceName, L"\\Device\\faultdriver");
RtlInitUnicodeString(&SymbolicLinkName, L"\\DosDevices\\faultdriver");
status = IoCreateDevice(DriverObject,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&deviceObject);
if (!NT_SUCCESS(status))
{
DPRINT("[-] Failed to create device. IoCreateDevice returned %x", status);
return STATUS_UNSUCCESSFUL;
}
deviceObject->Flags |= DO_BUFFERED_IO;
status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
if (!NT_SUCCESS(status))
{
DPRINT("[-] Failed to create symbolic link. IoCreateSymbolicLink returned %x", status);
IoDeleteDevice(deviceObject);
return STATUS_UNSUCCESSFUL;
}
// Set dispath routines
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction [IRP_MJ_CREATE] =
DriverObject->MajorFunction [IRP_MJ_CLOSE ] = DriverCreateClose;
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL ] = DriverIoControl;
DPRINT("[+] Driver initialization successful");
return STATUS_SUCCESS;
}
Теперь у нас готов работающий драйвер, который умеет оперировать с цветом фона для экрана смерти.
Напишем несложное GUI для этого. Я приведу только код юзермодных функций для работы с цветом:
// User mode API
#define IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR 0x0014
#define IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR 0x0024
UCHAR GetCurrentBugcheckColor()
{
HANDLE hDevice = CreateFile("\\\\.\\faultdriver", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if(hDevice == INVALID_HANDLE_VALUE)
return -1;
DWORD ret;
char buffer;
if(!DeviceIoControl(
hDevice,
IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR,
&buffer, sizeof(buffer),
&buffer, sizeof(buffer),
&ret,
0
))
{
CloseHandle(hDevice);
return -1;
}
else
{
CloseHandle(hDevice);
return buffer;
}
}
UCHAR SetCurrentBugcheckColor(UCHAR cNew)
{
HANDLE hDevice = CreateFile("\\\\.\\faultdriver", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if(hDevice == INVALID_HANDLE_VALUE)
return -1;
DWORD ret;
char buffer = cNew;
if(!DeviceIoControl(
hDevice,
IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR,
&buffer, sizeof(buffer),
&buffer, sizeof(buffer),
&ret,
0
))
{
CloseHandle(hDevice);
return -1;
}
else
{
CloseHandle(hDevice);
return buffer;
}
}
Вот и все :) Бинарники и сорсы можно найти тут: http://cribble.by.ru/bugcheck.rar
Для запуска нужно распаковать GUI-программку и бинарник драйвера в одну директорию и запустить EXEшник (он сам загрузит драйвер и выгрузит по окончании работы).
В соотв. каталогах в rar'e находятся проекты с сорцами для компилера Microsoft Visual C++ 6.0
Для тестирования пригодится программка М.Руссиновича "NotMyFault", которую можно скачать тут: http://www.sysinternals.com/Files/Notmyfault.zip
Удачи, пока!
ЗЫ. Посмотреть, как это выглядит, можно на скриншотах:
http://img255.imageshack.us/img255/1978/deathob9.png
http://img503.imageshack.us/img503/6316/xexe2zs3.png
http://img520.imageshack.us/img520/6940/xexe3if0.png
Зеленый симпотичный, правда? :)