Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Авторские статьи (https://forum.antichat.xyz/forumdisplay.php?f=31)
-   -   Цветной экран смерти (https://forum.antichat.xyz/showthread.php?t=33314)

_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_STRING_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
Зеленый симпотичный, правда? :)

_Great_ 13.02.2007 13:41

Мда. Совсем забыл сказать про цвета :)
Придется экспериментально проверять. По дефолту стоит 4 (синий).
Из экспериментов могу сказат, что
15 - белый
3 - болотный
7 - серый

AHTOLLlKA 13.02.2007 13:57

перекрасим бсод в эниСОД =)

ice1k 13.02.2007 14:02

Неплохо, Great! ;)
Цитата:

Сообщение от AHTOLLlKA
перекрасим бсод в эниСОД =)

ога =))

Deem3n® 13.02.2007 15:15

Вот еще ссылка по теме:
http://fanpotai.wordpress.com/2006/03/12/change-the-blue-screen-of-death-bsod-color-to-something-other-than-blue/

_Great_ 13.02.2007 16:44

как и обещал. вот красный:
http://img.secnull.info/images/246655rsod.png
Код красного цвета - 9.

Кто желает - вот фрагмент BOOTVID.DLL, функция установки палитры:

Код:

.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.

Masad 13.02.2007 16:49

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

ice1k 13.02.2007 17:00

Цитата:

Сообщение от Masad
мд-ааа.мой ламерский мозг умрёт если я начну такое творить. сайт с бесплатной регистрацией сайтов не подскажите? ещё нужно какую нибудь фигню,которую можно прилепить к Exe и чтоб она мне прислала на мыло инфу с компа жертвы.

Удали свой пост, чувак... =\

Ksander 13.02.2007 17:18

Надеюсь что никогда его не увижу, а если и увижу, то сомневаюсь что зеленый поднимет мне настроение =)

Cr4sh 15.02.2007 03:59

Цитата:

PUCHAR GetBugcheckColorAddress()
{
DWORD addr = (DWORD) &KeBugCheckEx;
addr += 0x17;
addr = addr + 4 + *(DWORD*)addr;
addr += 0x5EA;
return (PUCHAR) addr;
}
гг))) грейт, не перестаю удивляться твоему коду, неужели так трудно заюзать небольшой дизассемблер длинн и на его основе написать анализатор кода??!!!
думаю что те, кто запустят твой рантайм-патчер на ядре, немного отличном от твоего будут в ахуе)


Время: 11:20