Ошибка: Failed to parse the Currency Converter XML document.
$15 729.37


Ошибка: Failed to parse the Currency Converter XML document.
$1 473.94


Ошибка: Failed to parse the Currency Converter XML document.
$2 073.18


Цветной экран смерти

Если ты кодил под 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

#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

Удачи, пока!

 

Интересное

Hаиболее часто задаваемые...
Данный спиок вопросов и ответов на них содержит наиболее частозадаваемые вопросы по использованию в своих программах для microsoftwindows 95 и microsoft windows nt 4.0 возможности оболочки,...
Подробнее...
Как сохранить зрение:...
Искусственный свет, светящиеся экраны телевизора и компьютера, электронные игры грубо и бесцеремонно воздействуют на органы зрения, которые постоянно перенапрягаются. Как защитить глаза и помочь...
Подробнее...
10 незаменимых команд FTP
FTP — важная утилита TCP/IP, предназначенная для пересылки файлов между системами. Одно из главных достоинств FTP — совместимость со множеством различных удаленных хост-систем: файлы можно...
Подробнее...
Почтовые функции в РНР
Одним из возможных применений imap функций является создание почтового демона, который будет управлять подпиской и отпиской пользователей от вашей почтовой рассылки. Для реализации этой задачи,...
Подробнее...
Работа с ADO в Microsoft Excel
Достаточно часто требуется сформировать отчет и вывести его не только на печать, но и выгрузить в Excel. Последнего можно добиться 2 способами, либо получить данные средствами языка Navision C/Al...
Подробнее...
Управление правами на...
Управление правами на доступ к данным (Information Rights Management,IRM) представляет собой стойкую технологию защиты информации на уровнефайлов. Она помогает защищать представленную в цифровом...
Подробнее...
Безопасность. Какой вопрос...
Думаю, у каждого при чтении специализированной литературы возникали вопросы по поводу тех или иных терминов. Но, как правило, поблизости обычно нет того, кто может объяснить их значение. Проблемы...
Подробнее...
Время выполнения SQL запросов
Итак, нам нужно засечь время, потраченное на выполнение SQL запросов ? Это не очень легко, но и не сложно. Начнем с определения задачи. Необходимо выдать полное время, затраченное на генерацию...
Подробнее...
Объектное программирование
Тип объект содержит: — поля: вектор, его размер и его идентификатор в символьном виде — методы: введение вектора, вывод вектора, сортировка за ростом элементов вектора.Реализовать экземпляр этого...
Подробнее...
Отправка по SMTP с...
1. Введение. Практически каждый, кто сталкивается с работой в инете на низком уровне при создании какой-либо почтовой программы, оповещалки, либо троя или кейлогера, напарывается на такой...
Подробнее...