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: Code: // // Enable InbvDisplayString calls to make it through to bootvid driver. // if (InbvIsBootDriverInstalled()) { InbvAcquireDisplayOwnership(); InbvResetDisplay(); [b]InbvSolidColorFill(0,0,639,479,4); // make the screen blue[/b] InbvSetTextColor(15); InbvInstallDisplayStringFilter((INBV_DISPLAY_STRING_FILTER)NULL); InbvEnableDisplayString(TRUE); // enable display string InbvSetScrollRegion(0,0,639,479); // set to use entire screen } интересующую нас строчку я выделил. тут происходит задание цвета фона. Нам надо только лишь его поменять. Поехали! Итак, мы пишем под Windows XP 2600. Откроем в IDA Pro код KeBugCheckEx: Code: .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, устанавливающей цвет фона экрана: Code: .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 функции - прочитать текущий цвет и записать новый. С учетом всего вышенаписнаного, вот вспомогательная функция для получения адреса байта, где лежит цвет фона: Code: PUCHAR GetBugcheckColorAddress() { DWORD addr = (DWORD) &KeBugCheckEx; addr += 0x17; addr = addr + 4 + *(DWORD*)addr; addr += 0x5EA; return (PUCHAR) addr; } Определим следующие два кода для DeviceIoControl: Code: #define IOCTL_FAULTDRIVER_GET_BUGCHECK_COLOR 0x0014 #define IOCTL_FAULTDRIVER_SET_BUGCHECK_COLOR 0x0024 Проследим, чтобы младшие 2 бита были сброшены - они показывают тип ввода-вывода при DeviceIoControl. 00 означает буферизированный ввод-вывод, он нам и нужен. Диспетчер ввода-вывода выделит системный буфер, скопирует пользовательский буфер в системный, мы его будем изменять как хотим, а потом системный буфер скопируется обратно в выходной. Напишем вот такую функцию для обработки IRP_MJ_DEVICE_CONTROL: Code: 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 число байт, которое нужно скопировать в пользовательский буфер из системного. Остальной код драйвера комментировать, думаю, не стоит: Code: #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 для этого. Я приведу только код юзермодных функций для работы с цветом: Code: // 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 Зеленый симпотичный, правда?
Мда. Совсем забыл сказать про цвета Придется экспериментально проверять. По дефолту стоит 4 (синий). Из экспериментов могу сказат, что 15 - белый 3 - болотный 7 - серый
Вот еще ссылка по теме: http://fanpotai.wordpress.com/2006/03/12/change-the-blue-screen-of-death-bsod-color-to-something-other-than-blue/
как и обещал. вот красный: Код красного цвета - 9. Кто желает - вот фрагмент BOOTVID.DLL, функция установки палитры: Code: .text:800115B3 xor esi, esi .text:800115B5 mov [ebp+var_40], esi .text:800115B8 mov [ebp+var_3C], 20h .text:800115BF mov [ebp+var_38], 2000h .text:800115C6 mov [ebp+var_34], 2020h .text:800115CD mov [ebp+var_30], 200000h .text:800115D4 mov [ebp+var_2C], 200020h .text:800115DB mov [ebp+var_28], 202000h .text:800115E2 mov [ebp+var_24], 202020h .text:800115E9 mov [ebp+var_20], 303030h .text:800115F0 mov [ebp+var_1C], 3Fh .text:800115F7 mov [ebp+var_18], 3F00h .text:800115FE mov [ebp+var_14], 3F3Fh .text:80011605 mov [ebp+var_10], 3F0000h .text:8001160C mov [ebp+var_C], 3F003Fh .text:80011613 mov [ebp+var_8], 3F3F00h .text:8001161A mov [ebp+var_4], 3F3F3Fh .text:80011621 .text:80011621 loc_80011621: ; CODE XREF: InitializePalette()+83j .text:80011621 push [ebp+esi*4+var_40] ; int .text:80011625 push esi ; Value .text:80011626 call _SetPaletteEntry@8 ; SetPaletteEntry(x,x) .text:8001162B inc esi .text:8001162C cmp esi, 10h .text:8001162F jb short loc_80011621 Выводы делайте сами, какой цвет какому номеру соответствует. Правда, тут не совсем RGB.
мд-ааа.мой ламерский мозг умрёт если я начну такое творить. сайт с бесплатной регистрацией сайтов не подскажите? ещё нужно какую нибудь фигню,которую можно прилепить к Exe и чтоб она мне прислала на мыло инфу с компа жертвы.
Надеюсь что никогда его не увижу, а если и увижу, то сомневаюсь что зеленый поднимет мне настроение =)
гг))) грейт, не перестаю удивляться твоему коду, неужели так трудно заюзать небольшой дизассемблер длинн и на его основе написать анализатор кода??!!! думаю что те, кто запустят твой рантайм-патчер на ядре, немного отличном от твоего будут в ахуе)
А мне интересно, зачем его перекрашивать? чтобы поставить вот такой же красный и в случае краха, чтобы п*здец еще и тебе самому настал?))