# Часть 56

[\[Используемые материалы\]](https://github.com/yutewiyof/intro-rev-ida-pro/tree/e1367e11cc661f3d69c02ae5f733b7dd168bc5ab/.gitbook/assets/files/56.zip)

Давайте теперь рассмотрим драйвер, который запрограммирован с различными уязвимостями, чтобы понять, как их эксплуатировать. Как и всегда мы будем использовать **WINDOWS 7 SP1** без какого-либо патча безопасности. Мы знаем, что здесь всё будет работать. Затем мы увидим, какие изменения есть ниже и какие другие возможности существуют в новых системах. Но мы будем идти потихоньку и никуда не будем спешить.

У нас есть драйвер, скомпилированный с символами. У вас есть возможность эксплуатировать его практически всеми возможными способами. Он сделан специально для практики.

<https://github.com/hacksysteam/HackSysExtremeVulnerableDriver>

Реализованные уязвимости:

* Двойная выборка
* Переполнение пула
* Использование после освобождения
* Путаница в типах
* Переполнение стека
* Целочисленное переполнение
* Переполнение стека с флагом GS(Buffer Security Check)
* Перезапись арбитражного кода
* Разыменование нулевого указателя
* Неинициализированная переменная кучи
* Неинициализированная переменная стека
* Небезопасный доступ к ресурсам ядра

Мы будем начинать потихоньку. Сначала сделаем анализ переполнения стека.

Конечно, Вам нужно скопировать драйвер на целевую машину и загрузить его с помощью **OSR DRIVER LOADER**.

Мы копируем его с его **IDB** в локальную папку и открываем его в **IDA** чтобы начать анализ.

Хорошо. Как мы уже знаем здесь, у нас есть символы, которые облегчают нам много вещи. Но первое, что мы должны найти и что почти всегда распознаётся с символами или без, это структура **\_DRIVER\_OBJECT**, которая передается как аргумент в функцию **DRIVERENTRY**.

В этом случае у нас не так много проблем.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttv_6VmDeLyRx6R3y%2F01.png?generation=1563265868688813\&alt=media)

Здесь хорошо видна точка входа, и ее аргументы хорошо обнаружились.

Мы видим, что драйвер использует, как и в предыдущих примерах, **API** функцию **RTLINITUNICODESTRING** для инициализации структур.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6klRCRBzKr6k_Oh%2F56-02.png?generation=1563225023053135\&alt=media)

Напомним, что первым аргументом был указатель на структуру **UNICODE\_STRING**. Здесь мы видим **PUNICODE\_STRING**, т.е. указатель на структуру **UNICODE\_STRING**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6ktEJah_BdBp3vG%2F56-03.png?generation=1563225019836520\&alt=media)

Т.е. это буфер, куда драйвер сохранит длину строки в переменную типа **WORD**, Максимальная длина в следующем поле также имеет тип **WORD**, а указатель будет скопирован в строку юникода, которую мы передали как источник в третьем поле.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttv_kF3di7bsWzgQd%2F04.png?generation=1563265876065977\&alt=media)

Сначала инициализируется в нуль структура **DOSDEVICENAME**, которая также имеет тип **UNICODE\_STRING**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6l4PGWYq6BtOMdh%2F56-05.png?generation=1563225029899473\&alt=media)

Драйвер помещает в поле **LENGTH** нуль, помещая в него значение регистра **AX**, которое равно здесь **0**. А затем идет инструкция **STOSD**, которая копирует значение из регистра **EAX**, т.е. помещает нуль в адрес, куда указывает регистр **EDI**, т.е. в поле **MAXIMUMLENGHT**. А затем следующая инструкция **STOSW** копирует из регистра **AX** значение, т.е. нуль в два следующих байтах, т.е. помещая нуль в **6** байтов, т. е. инициализирует два оставшихся поля структуры, которые занимают **6** байтов (**1 WORD** и **DWORD**).

Компилятор только инициализирует структуру **DOSDEVICENAME**. Другая переменная, которая называется **DEVICENAME**, не равна нулю. Драйвер использует ее напрямую.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttva1WbXvflQBIGAY%2F06.png?generation=1563265878172117\&alt=media)

Другими словами, **DEVICENAME** - это строка, которая преобразуется в тип структуры **UNICODE\_STRING**. Другими словами, в её трех полях будет длина, максимальная длина и указатель, который мы передаем в строку источник. Он будет скопирован в третье поле.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvaAg8FOTerqT_X3%2F07.png?generation=1563265888056894\&alt=media)

В моей машине указатель находится по адресу **0x00016938**. Это смещение скопирует его в третье поле структуры.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvaHa5BmLMbYJaQG%2F08.png?generation=1563265887927396\&alt=media)

В **DOSDEVICENAME** вы будете создавать другой указатель **UNICODE\_STRING**. Я использую как источник эту другую строку.

Затем идёт вызов функции **IOCREATEDEVICE**. Мы помним, что вам нужно было создать **DEVICE OBJECT**, чтобы иметь возможность общаться с программами из пользовательского режима.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6lPhOzRf7zKfg4n%2F56-09.png?generation=1563225026117899\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvabIh6rpbQPu0-_%2F10.png?generation=1563265882751046\&alt=media)

Это будет почти всегда около точки входа в большинстве драйверов, которые взаимодействуют с программами в пользовательском режиме.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6lZXVf_wt2lUshG%2F56-11.png?generation=1563225015590975\&alt=media)

Последний аргумент, это указатель на вновь созданную структуру **DEVICE\_OBJECT**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvatpYVB_pBm4t5g%2F12.png?generation=1563265881990727\&alt=media)

Мы видим, что если результат создания устройства отрицательный, который проверяется в этом условном знаковом переходе, драйвер переходит к оранжевым блокам ошибок, а объект устройства удаляется с помощью функции **IODELETEDEVICE**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttvb0f68IbMpUbxjB%2F13.png?generation=1563265887058318\&alt=media)

Затем структура **DRIVEROBJECT** будет инициализироваться из регистра **ESI + 38**. Поскольку **ESI** указывает на **DRIVEROBJECT**, я нажимаю **T**. Я могу посмотреть, какое это поле (но это **DRIVER\_OBJECT** идём в **LOCAL TYPES** и синхронизируем типы)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6lmmxdALNiY9-HX%2F56-14.png?generation=1563225026208915\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvbGmRjz5rgtJlZS%2F15.png?generation=1563265868579370\&alt=media)

Т.е. это указатель на структуру **MAJORFUNCTION**, про которую мы помним, что он представляет собой таблицу указателей, которая, согласно позиции, приведет меня к разным функциям в зависимости от случая. Вспомните это, например.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvbOFTt1VqAslym6%2F16.png?generation=1563265880526315\&alt=media)

Первый указатель, т.е. тот, который находится в позиции **0**, является **IRP\_MJ\_CREATE** и драйвер будет переходить на него, когда вы вызываете функцию **CREATEFILE**, чтобы открыть дескриптор устройства. Второй указатель, т.е. со значением **0x1** находится в положении 4, так как он являются **DWORD** и т.д. Это означает, что обратно пропорционально, если у меня есть поле этой структуры по её смещению, чтобы знать, какой указатель нам нужен надо делить его на четыре. Из примера, который мы использовали в предыдущих драйверах давайте вспомним.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6m0q_INpYdvkoIQ%2F56-17.png?generation=1563225015850974\&alt=media)

Это соответствует значению **0x38/4**, т.е.

```
Python>hex(0x38/4)
0xE
```

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvbfNtpmGC7ng-l5%2F18.png?generation=1563265876442759\&alt=media)

Т.е. **0xE** соответствует **IRP\_MJ\_DEVICE\_CONTROL**, когда мы передали код **IOCTL** из режима пользователя. Этот указатель мы перезаписали с помощью обработчика, так что в соответствии с тем, какой код **IOCTL**, различные действия будут выполняться с помощью конструкции **SWITCH**. Например так.

В текущем случае, мы видим, что драйвер инициализирует значения начиная с указателя на начало таблицы **MAJORFUNCTION**. Он копирует значение регистра **EAX**, в которое помещается смещение функции, которая называется **\_IRP\_NOTIMPLEMENTEDHANDLERS**. Копирование происходит **0x1C** раз. Это значение передаётся в регистре **ECX**. Оно равно количеству указателей, которые нужно инициализировать.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2Fsync%2Fce8cf65282f2c3f781308dd8d30334adb89973cf.png?generation=1617135493408353\&alt=media)

Другими словами, в начале вся таблица инициализирует этим указателем, который, по-видимому, не будет делать ничего. Это похоже на случай по умолчанию.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttvc-tfYbuDPRUdkG%2F20.png?generation=1563265866710463\&alt=media)

Поскольку регистр **EDX** хранит указатель на начало таблицы **MAJORFUNCTION**, его содержимым является позиция **0**, т.е.

```
+#define IRP_MJ_CREATE 0x00
+#define IRP_MJ_CREATE_NAMED_PIPE 0x01
+#define IRP_MJ_CLOSE 0x02
+#define IRP_MJ_READ 0x03
+#define IRP_MJ_WRITE 0x04
+#define IRP_MJ_QUERY_INFORMATION 0x05
+#define IRP_MJ_SET_INFORMATION 0x06
+#define IRP_MJ_QUERY_EA 0x07
+#define IRP_MJ_SET_EA 0x08
+#define IRP_MJ_FLUSH_BUFFERS 0x09
+#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
+#define IRP_MJ_SET_VOLUME_INFORMATION 0x0b
+#define IRP_MJ_DIRECTORY_CONTROL 0x0c
+#define IRP_MJ_FILE_SYSTEM_CONTROL 0x0d
+#define IRP_MJ_DEVICE_CONTROL 0x0e
+#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0f
+#define IRP_MJ_SCSI 0x0f
+#define IRP_MJ_SHUTDOWN 0x10
+#define IRP_MJ_LOCK_CONTROL 0x11
+#define IRP_MJ_CLEANUP 0x12
+#define IRP_MJ_CREATE_MAILSLOT 0x13
+#define IRP_MJ_QUERY_SECURITY 0x14
+#define IRP_MJ_SET_SECURITY 0x15
+#define IRP_MJ_POWER 0x16
+#define IRP_MJ_SYSTEM_CONTROL 0x17
+#define IRP_MJ_DEVICE_CHANGE 0x18
+#define IRP_MJ_QUERY_QUOTA 0x19
+#define IRP_MJ_SET_QUOTA 0x1a
+#define IRP_MJ_PNP 0x1b
+#define IRP_MJ_PNP_POWER 0x1b
+#define IRP_MJ_MAXIMUM_FUNCTION 0x1b
```

Мы будем создавать структуру **MAJORFUNCTION**.

```c
struct __MajorFunction{
    unsigned int _MJ_CREATE;
    unsigned int _MJ_CREATE_NAMED_PIPE;
    unsigned int _MJ_CLOSE;
    unsigned int _MJ_READ;
    unsigned int _MJ_WRITE;
    unsigned int _MJ_QUERY_INFORMATION;
    unsigned int _MJ_SET_INFORMATION;
    unsigned int _MJ_QUERY_EA;
    unsigned int _MJ_SET_EA;
    unsigned int _MJ_FLUSH_BUFFERS;
    unsigned int _MJ_QUERY_VOLUME_INFORMATION;
    unsigned int _MJ_SET_VOLUME_INFORMATION;
    unsigned int _MJ_DIRECTORY_CONTROL;
    unsigned int _MJ_FILE_SYSTEM_CONTROL;
    unsigned int _MJ_DEVICE_CONTROL;
    unsigned int _MJ_INTERNAL_DEVICE_CONTROL;
    unsigned int _MJ_SCSI;
    unsigned int _MJ_SHUTDOWN;
    unsigned int _MJ_LOCK_CONTROL;
    unsigned int _MJ_CLEANUP;
    unsigned int _MJ_CREATE_MAILSLOT;
    unsigned int _MJ_QUERY_SECURITY;
    unsigned int _MJ_SET_SECURITY;
    unsigned int _MJ_POWER;
    unsigned int _MJ_SYSTEM_CONTROL;
    unsigned int _MJ_DEVICE_CHANGE;
    unsigned int _MJ_QUERY_QUOTA;
    unsigned int _MJ_SET_QUOTA;
    unsigned int _MJ_PNP;
    unsigned int _MJ_PNP_POWER;
    unsigned int _MJ_MAXIMUM_FUNCTION;
};
```

Я знаю, что это указатели, но для нашего случая я буду использовать тип **UNSIGNED INT** и это будет работать. Проблема состоит в том, что это локальные типы. При использовании операции **INSERT**, **IDA** не принимают структуру. Поэтому я буду экспортировать её. Я добавляю структуру и перезагружаю ее с помощью **FILE→ LOAD FILE→ PARSE C HEADER FILE**

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6mQMOmNBZCRY0lL%2F56-21.png?generation=1563225022998082\&alt=media)

Я добавил структуру в **ЗАГОЛОВОЧНЫЙ ФАЙЛ**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvcM6JagZcxdYkIV%2F22.png?generation=1563265877568241\&alt=media)

Теперь возникает вопрос

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvcTBBGYnn-z1H5o%2F23.png?generation=1563265885830596\&alt=media)

Я позволял себе редактировать внутри структуры **DRIVER\_OBJECT**, тип **MAJORFUNCTION** в **LOCAL TIPES** ?

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6mkVloemaJW7ahJ%2F56-24.png?generation=1563225026136848\&alt=media)

Мы видим, что я изменил структуре определение поля **MAJORFUNCTION**. Внутри структуры **DRIVER\_OBJECT** для того, чтобы она была типа **\_\_MAJORFUNCTION**, который я определил.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttvco8-Th7skqf2vl%2F25.png?generation=1563265881513509\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6mqD6QEVs4eX755%2F56-26.png?generation=1563225026332559\&alt=media)

Мы видим, что сейчас, если поля определены с их именами каждого указателя.

Когда мы нажимаем **T**, мы не можем выбрать структуру **DRIVER\_OBJECT**, потому что регистр **EDX** указывает на таблицу **MAJORFUNCTION**, поэтому я выбираю последнюю.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvdBUlwOtC5PJqmG%2F27.png?generation=1563265886471285\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6myI3JBPvXRLITB%2F56-28.png?generation=1563225029207462\&alt=media)

Сейчас стало намного лучше. Все в порядке. Я определил функции, которые будут использоваться, т. е. **\_MJ\_CREATE**, **\_MJ\_CLOSE**, **\_MJ\_DEVICE\_CONTROL** и те, которые будет вызываться, когда драйвер останавливается через функцию **DRIVERUNLOAD**.

Очевидно, когда из режима пользователя мы вызвали функцию **CREATEFILE**, вызывается функция, которая перезаписывает поле **\_MJ\_CREATE**. Когда мы передаем **IOCTL** код в функцию **DEVICEIOCONTROL**, вызывается **\_MJ\_DEVICE\_CONTROL**. Когда вызывается функция **CLOSEHANDLE**, драйвер вызывает ту, которая перезаписывает поле **\_MJ\_CLOSE**. И когда драйвер останавливается, вызывается та, которая перезаписывает функцию **DRIVERUNLOAD**.

Мы будем смотреть на функцию, которая будет вызываться при передаче **IOCTL**.

Мы синхронизируем структуру **IRP** из вкладки **LOCAL TYPES**.

Как мы видели в части **53**, поле **60** из **IRP** указывает на структуру **\_IO\_STACK\_LOCATION**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6n2W-TEFQR-LqlU%2F56-29.png?generation=1563225022519451\&alt=media)

Регистр **ESI** указывает на **\_IO\_STACK\_LOCATION**, поэтому все, что равно **ESI** + **XXX**, будет полем вышеупомянутой структуры. После синхронизации из вкладки **LOCAL TYPES**.

Напомним, что у структуры **\_IO\_STACK\_LOCATION** есть несколько опций. Я выберу ту, которая соответствует **IOCONTROLCODE**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvdfLPTRsVIowYYB%2F30.png?generation=1563265887093251\&alt=media)

Мы видим, что в соответствии с кодом **IOCTL, SWITCH** отправляет нас в разные блоки и что они помечены типом уязвимости, который имеет каждый путь.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6nG4aSUDlv9KDNy%2F56-31.png?generation=1563225023499392\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6nJbrLJ8XhABsL3%2F56-32.png?generation=1563225031598008\&alt=media)

Здесь есть один блок, который говорит нам, что он имеет **STACKOVERFLOW**. Поэтому вам не нужно слишком сильно себя утруждать и искать переполнение.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttve7yLQ32zdjd1Ok%2F33.png?generation=1563265877170413\&alt=media)

Мы видим, что есть два аргумента, которые передают в регистре **EDI** структуру **IRP** а в регистре **ESI IRPSP** - это имя переменной типа **\_IO\_STACK\_LOCATION**, которая была в регистре **ESI**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttveFpjltezGHNUxp%2F34.png?generation=1563265889203415\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6nchCAdq0nyGv6l%2F56-35.png?generation=1563225021761139\&alt=media)

Это указатель на входной буфер. Также в этой же субструктуре находится **IOCONTROLCODE** и длина входного и выходного буфера. Предположительно эти значения передаются то же. Давайте посмотрим, что с ними делать.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttveVrAwEC84RwuvM%2F36.png?generation=1563265881210800\&alt=media)

Мы видим, что этот **SIZE** и этот буфер передаются в функцию **\_TRIGGERSTACKOVERFLOW**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvecqzepvH9XRs6a%2F37.png?generation=1563265877038001\&alt=media)

Мы видим, что драйвер помещает нуль с помощью регистра **ESI** в первый **DWORD** буфера **KERNELBUFFER** и затем с помощью функции **MEMSET** помещает нуль в следующий **DWORD**, так как происходит сложение **KERNELBUFFER + 4**, и получается размер **0x7FC**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6npGyLaR2LFd7bj%2F56-38.png?generation=1563225023019013\&alt=media)

Вышеупомянутый буфер имеет длину **512** \* **4**, так как это массив **DWORD** (**DD**), поэтому общая длина в десятичной системе равна:

```
512 * 4
Out[64]: 2048
```

В **HEX** это

```
hex(2048)
Out[65]: '0x800'
```

Поэтому, поместив в первый **DWORD** нуль, а затем в оставшиеся **0x7FC байт**. Действительно, драйвер заполнит весь буфер размером **0x800** нулями. (**0x7FC** + **4** = **0x800)**

Затем драйвер вызовет функцию **PROBEFORREAD**, которая проверит, выровнен ли входной буфер в пользовательском режиме и находится ли он в пользовательском пространстве.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6nvFkoKyPzg75AZ%2F56-39.png?generation=1563225022398562\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljttvf2Q1khj2sOYiER%2F40.png?generation=1563265884402712\&alt=media)

Затем драйвер печатает указатели буферов и их размеры.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjrSx7vPF_6hdeduZel%2F-LjrT6o7fiYdTlHZ69gt%2F56-41.png?generation=1563225031777221\&alt=media)

Здесь мы ясно видим переполнение стека, поскольку драйвер использует размер, который я передаю ему как данные для копирования из входного буфера в пользовательский, в буфер в ядре, который является назначением.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvfNXVfodLwyOVpi%2F42.png?generation=1563265879840077\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-LjttvfZ1U67dtwtKOyr%2F43.png?generation=1563265876987088\&alt=media)

Здесь мы видим, что при печати размера буфера ядра, драйвер используйте тот, который находится в регистре **ESI**, который является константой **0x800**, но при выполнении функции **MEMCPY** он используйте аргумент **SIZE**, который я передал ему, без каких-либо проверок, которые будут приводить к переполнению стека и поскольку здесь нет **COOKIE**, он будет легко переполняться.

В следующей части мы будем делать скрипт с эксплуатацией. На этом здесь, мы закончим анализ.

Автор оригинального текста — Рикардо Нарваха.

Перевод и адаптация на русский язык — Яша Яшечкин.

Перевод специально для форума системного и низкоуровневого программирования - WASM.IN

06.11.2018

[**Источник: ricardonarvaja.info**](http://ricardonarvaja.info/WEB/IDA%20DESDE%20CERO/CURSO%20DE%20IDA%20TUTES/56-INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO.docx)
