Вряд ли пользователь домашнего ПК заинтересуется тем, чтобы блокировать устройства на своем ПК. Но если дело касается корпоративной среды, то все становится иначе. Есть пользователи, которым можно доверять абсолютно во всем, есть такие, которым можно что-то делегировать, и есть те, кому доверять совсем нельзя. Например, вы заблокировали доступ к Интернету одному из пользователей, но не заблокировали устройства этого ПК. В таком случае пользователю достаточно просто принести USB-модем, и Интернет у него будет. Т.е. простым блокированием доступа к Интернету дело не ограничивается.

Однажды примерно такая задача и стояла передо мной. Времени на поиск каких-либо решений в Интернете не было, да и они, как правило, небесплатные. Поэтому мне было проще написать такой драйвер, и его реализация отняла у меня один день.

В этой статье я расскажу немного теоретическую часть, на основе которой все строится, и расскажу принцип самого решения.

Также полные исходные коды могут быть найдены в папке USBLock хранилища git по адресу: https://github.com/anatolymik/samples.git.

Структура DRIVER_OBJECT


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

for ( ULONG i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
	DriverObject->MajorFunction[i] = DispatchCommon;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCleanup;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = DispatchAddDevice; 

Такая инициализация обычно выполняется при вызове системой точки входа драйвера, прототип которой изображен ниже.

NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ); 

Как видно из примера, сначала весь массив MajorFunction инициализируется одним и тем же обработчиком. В реальности типов запросов больше, чем в примере. Поэтому предварительно весь массив инициализируется так, чтобы запросы, которые не поддерживаются драйвером, обрабатывались корректно. Например, завершались с ошибкой. После инициализации массива обычно инициализируются обработчики для тех запросов, за которые драйвер отвечает.

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

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

Более подробно данная структура описана по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff544174(v=vs.85).aspx.

Структура DEVICE_OBJECT


Структура DEVICE_OBJECT представляет ту или иную функциональность драйвера. Т.е. эта структура может представлять физическое устройство, логическое устройство, виртуальное устройство или просто некий функционал, предоставляемый драйвером. Поэтому когда система будет посылать запросы, то в самом запросе она будет указывать адрес этой структуры. Таким образом, драйвер сможет определить, какой функционал от него запрашивается. Если не использовать такую модель, тогда драйвер может обрабатывать только какую-нибудь одну функциональность, а в современном мире это недопустимо. Прототип функции, которая обрабатывает конкретный запрос, приведена ниже.

NTSTATUS Dispatch( PDEVICE_OBJECT DeviceObject, PIRP Irp ); 

Массив MajorFunction ранее упомянутой структуры DRIVER_OBJECT содержит адреса обработчиков именно с таким прототипом.

Сама структура DEVICE_OBJECT всегда создается драйвером при помощи функции IoCreateDevice. Если система посылает запрос драйверу, то она всегда направляет его какому-либо DEVICE_OBJECT, как это следует из вышепредставленного прототипа. Также, прототип принимает второй параметр, который содержит адрес IRP-структуры. Эта структура описывает сам запрос, и она существует в памяти до тех пор, пока драйвер не завершит его. Запрос отправляется драйверу на обработку при помощи функции IoCallDriver как системой, так и другими драйверами.

Также со структурой DEVICE_OBJECT может быть связано имя. Таким образом, этот DEVICE_OBJECT может быть найден в системе.

Более подробно структура DEVICE_OBJECT описана по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff543147(v=vs.85).aspx. А структура IRP описана по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff550694(v=vs.85).aspx.

Фильтрация


Фильтрация являет собой механизм, который позволяет перехватывать все запросы, направленные к конкретному DEVICE_OBJECT. Чтобы установить такой фильтр, необходимо создать другой экземпляр DEVICE_OBJECT и прикрепить его к DEVICE_OBJECT, запросы которого необходимо перехватывать. Прикрепление фильтра выполняется посредством функции IoAttachDeviceToDeviceStack. Все DEVICE_OBJECT, прикрепленные к перехватываемому DEVICE_OBJECT, вместе с ним формируют так называемый стек устройства, как это изображено ниже.


Стрелкой изображено продвижение запроса. Сначала запрос будет обрабатываться драйвером верхнего DEVICE_OBJECT, затем драйвером среднего и, в конце концов, управление на обработку запроса получит драйвер целевого DEVICE_OBJECT. Также нижний DEVICE_OBJECT называется дном стека, т.к. он ни к кому не прикреплен.

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

PnP менеджер


PnP менеджер отвечает за диспетчеризацию устройств всей системы. В его задачи входит обнаружение устройств, сбор информации о них, загрузка их драйверов, вызов этих драйверов, управление аппаратными ресурсами, запуск и остановка устройств и их удаление.

Когда драйвер той или иной шины обнаруживает устройства на своих интерфейсах, то для каждого дочернего устройства он создает DEVICE_OBJECT. Этот DEVICE_OBJECT также называют Physical Device Object или PDO. Затем посредством функции IoInvalidateDeviceRelations он уведомляет PnP менеджер о том, что произошли изменения на шине. В ответ на это PnP менеджер посылает запрос с minor кодом IRP_MN_QUERY_DEVICE_RELATIONS с целью запросить список дочерних устройств. В ответ на этот запрос драйвер шины возвращает список PDO. Ниже изображен пример такой ситуации.


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

Как только PnP менеджер получит список всех PDO, он по отдельности соберет всю необходимую информацию об этих устройствах. Например, будет послан запрос с minor кодом IRP_MN_QUERY_ID. Посредством этого запроса PnP менеджер получит идентификаторы устройства, как аппаратные, так и совместимые. Также PnP менеджер соберет всю необходимую информацию о требуемых аппаратных ресурсах самим устройством. И так далее.

После того, как вся необходимая информация будет собрана, PnP менеджер создаст так называемую DevNode, которая будет отражать состояние устройства. Также PnP создаст ветку реестра для конкретного экземпляра устройства или откроет существующую, если устройство ранее подключалось к ПК.

Следующая задача PnP — это запуск драйвера устройства. Если драйвер не был ранее установлен, тогда PnP будет ожидать установки. Иначе, при необходимости, PnP загрузит его и передаст ему управление. Ранее упоминалось, что поле DriverExtension->AddDevice структуры DRIVER_OBJECT содержит адрес обработчика, который вызывается всякий раз, когда система обнаруживает новое устройство. Прототип этого обработчика изображен ниже.

NTSTATUS DispatchAddDevice( 
	PDRIVER_OBJECT DriverObject, 
	PDEVICE_OBJECT PhysicalDeviceObject 
); 

Т.е. всякий раз, когда PnP обнаруживает устройство, управлением которого занимается тот или иной драйвер, вызывается зарегистрированный обработчик этого драйвера, где ему передается указатель на PDO. Информация об установленном драйвере также хранится в соответствующей ветке реестра.

В задачу обработчика входит создание DEVICE_OBJECT и его прикрепление к PDO. Прикрепленный DEVICE_OBJECT также называют Functional Device Object или FDO. Именно этот FDO и будет отвечать за работу устройства и представление его интерфейсов в системе. Ниже представлен пример, когда PnP завершил вызов драйвера, отвечающего за работу устройства.


Как отражено на примере, кроме драйвера самого устройства также могут быть зарегистрированы нижние и верхние фильтры класса устройства. Следовательно, если таковые имеются, PnP также загрузит их драйвера и вызовет их AddDevice обработчики. Т.е. порядок вызова драйверов следующий: сначала загружаются и вызываются зарегистрированные нижние фильтры, затем загружается и вызывается драйвер самого устройства, и в завершении загружаются и вызываются верхние фильтры. Нижние и верхние фильтры являются обычным DEVICE_OBJECT, которые создают драйвера и прикрепляют их к PDO в своих обработчиках AddDevice. Количество нижних и верхних фильтров не ограничено.

В этот момент стеки устройств полностью сформированы и готовы к работе. Поэтому PnP посылает запрос с minor кодом IRP_MN_START_DEVICE. В ответ на этот запрос все драйвера стека устройства должны подготовить устройство к работе. И если в этом процессе не возникло проблем, тогда запрос завершается успешно. В противном случае, если любой из драйверов не может запустить устройство, тогда он завершает запрос с ошибкой. Следовательно, устройство не будет запущено.

Также, когда драйвер шины определяет, что произошли изменения на шине, он посредством функции IoInvalidateDeviceRelations уведомляет PnP о том, что следует заново собрать информацию о подключенных устройствах. В этот момент драйвер не удаляет ранее созданный PDO. Просто при получении запроса с minor кодом IRP_MN_QUERY_DEVICE_RELATIONS он не включит этот PDO в список. Затем PnP на основании полученного списка опознает новые устройства и устройства, которые были отключены от шины. PDO отключенных устройств драйвер удалит тогда, когда PnP пошлет запрос с minor кодом IRP_MN_REMOVE_DEVICE. Для драйвера этот запрос означает, что устройство более никем не используется, и оно может быть безопасно удалено.

Более подробную информацию о модели драйверов WDM можно найти по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff548158(v=vs.85).aspx.

Суть решения


Суть самого решения заключается в создании верхнего фильтра класса USB-шины. Зарезервированные классы можно найти по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff553419(v=vs.85).aspx. Нас интересует класс USB с GUID равным 36fc9e60-c465-11cf-8056-444553540000. Как гласит MSDN, этот класс используется для USB хост контроллеров и хабов. Однако практически это не так, этот же класс используется, например, flash-накопителями. Это немного добавляет нам работы. Код обработчика AddDevice представлен ниже.

NTSTATUS UsbCreateAndAttachFilter( 
	PDEVICE_OBJECT PhysicalDeviceObject, 
	bool UpperFilter 
) {

	SUSBDevice*		USBDevice;
	PDEVICE_OBJECT		USBDeviceObject = nullptr;

	ULONG			Flags;

	NTSTATUS		Status = STATUS_SUCCESS;

	PAGED_CODE();

	for ( ;; ) {

		// если нижний фильтр уже прикреплен, тогда здесь больше делать нечего
		if ( !UpperFilter ) {
			USBDeviceObject = PhysicalDeviceObject;
			while ( USBDeviceObject->AttachedDevice ) {
				if ( USBDeviceObject->DriverObject == g_DriverObject ) {
					return STATUS_SUCCESS;
				}
				USBDeviceObject = USBDeviceObject->AttachedDevice;
			}
		}

		// создаем фильтр
		Status = IoCreateDevice(
			g_DriverObject,
			sizeof( SUSBDevice ),
			nullptr,
			PhysicalDeviceObject->DeviceType,
			PhysicalDeviceObject->Characteristics,
			false,
			&USBDeviceObject
		);
		if ( !NT_SUCCESS( Status ) ) {
			break;
		}

		// инициализируем флаги созданного устройства, копируем их из объекта к 
		// которому прикрепились
		Flags = PhysicalDeviceObject->Flags & 
		 (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
		USBDeviceObject->Flags |= Flags;

		// получаем указатель на нашу структуру
		USBDevice = (SUSBDevice*)USBDeviceObject->DeviceExtension;

		// инициализируем деструктор
		USBDevice->DeleteDevice = DetachAndDeleteDevice;

		// инициализируем обработчики
		for ( ULONG i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
			USBDevice->MajorFunction[i] = UsbDispatchCommon;
		}
		USBDevice->MajorFunction[IRP_MJ_PNP] = UsbDispatchPnp;
		USBDevice->MajorFunction[IRP_MJ_POWER] = UsbDispatchPower;

		// инициализируем семафор удаления устройства
		IoInitializeRemoveLock( 
			&USBDevice->Lock, 
			USBDEVICE_REMOVE_LOCK_TAG, 
			0, 
			0 
		);

		// заполняем структуру
		USBDevice->SelfDevice = USBDeviceObject;
		USBDevice->BaseDevice = PhysicalDeviceObject;
		USBDevice->UpperFilter = UpperFilter;

		// инициализируем paging семафор
		USBDevice->PagingCount = 0;
		KeInitializeEvent( &USBDevice->PagingLock, SynchronizationEvent, true );

		// прикрепляем устройство к PDO
		USBDevice->LowerDevice = IoAttachDeviceToDeviceStack( 
			USBDeviceObject, 
			PhysicalDeviceObject 
		);
		if ( !USBDevice->LowerDevice ) {
			Status = STATUS_NO_SUCH_DEVICE;
			break;
		}

		break;

	}

	// в зависимости от результата делаем

	if ( !NT_SUCCESS( Status ) ) {

		// отчистку

		if ( USBDeviceObject ) {
			IoDeleteDevice( USBDeviceObject );
		}

	} else {

		// или сбрасываем флаг инициализации
		USBDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

	}

	return Status;

}

static NTSTATUS DispatchAddDevice( 
	PDRIVER_OBJECT DriverObject, 
	PDEVICE_OBJECT PhysicalDeviceObject 
) {

	UNREFERENCED_PARAMETER( DriverObject );

	return UsbCreateAndAttachFilter( PhysicalDeviceObject, true );

}

Как следует из примера, мы создаем DEVICE_OBJECT и прикрепляем его к PDO. Таким образом, мы будем перехватывать все запросы, направленные к USB-шине.

В нашу задачу входит перехватывать запросы с minor кодом IRP_MN_START_DEVICE. Код обработчика этого запроса изображен ниже.

static NTSTATUS UsbDispatchPnpStartDevice( SUSBDevice* USBDevice, PIRP Irp ) {

	bool		HubOrComposite;
	NTSTATUS	Status;

	PAGED_CODE();

	for ( ;; ) {

		// проверить, позволено ли устройству работать, также обновить
		// информацию об устройстве, является ли оно хабом или композитным
		Status = UsbIsDeviceAllowedToWork( &HubOrComposite, USBDevice );
		if ( !NT_SUCCESS( Status ) ) {
			break;
		}
		USBDevice->HubOrComposite = HubOrComposite;

		// продвинуть запрос
		Status = ForwardIrpSynchronously( USBDevice->LowerDevice, Irp );
		if ( !NT_SUCCESS( Status ) ) {
			break;
		}

		break;

	}

	// завершаем запрос
	Irp->IoStatus.Status = Status;
	IoCompleteRequest( Irp, IO_NO_INCREMENT );

	// и освобождаем устройство
	IoReleaseRemoveLock( &USBDevice->Lock, Irp );

	return Status;

}

Как изображено на рисунке, обработчик вызывает функцию UsbIsDeviceAllowedToWork. Эта функция выполняет все необходимые проверки, чтобы определить, разрешено ли устройству работать. В первую очередь функция позволяет всегда работать хабам и композитным устройствам, клавиатурам и мышам. А также тем устройствам, которые находятся в списке разрешенных. Если функция возвращает неуспешный код возврата, тогда запрос завершается с ошибкой. Таким образом, работа устройства будет заблокирована.

Обратите внимание: функция определяет, является ли устройство хабом или композитным устройством. Это необходимо потому, что, как уже было упомянуто, класс устройств, который используется для хабов и хост контроллеров, используется не только этими устройствами. А нам в первую очередь необходимо контролировать дочерние устройства только хабов, хост контроллеров и композитных устройств. Т.е. для хабов и композитных устройств дополнительно перехватывается запрос перечисления дочерних устройств, на этом этапе, важно также прикрепить ко всем дочерним устройствам фильтр, и этот фильтр будет нижним. В противном случае контроль над дочерними устройствами будет потерян.

Все упомянутые определения выполняются на основе идентификаторов устройств.

Заключение


Несмотря на свою простоту в моем случае данный драйвер достаточно эффективно решает поставленную задачу. Хотя из недостатков следует выделить обязательную перезагрузку после того, как список разрешенных устройств будет обновлен. Чтобы устранить этот недостаток, драйвер потребуется несколько усложнить. Еще большим недостатком является полное блокирование устройства, а не частичное. Описание, представленное выше, не раскрывает всех деталей реализации. Сделано это было намеренно, и упор был сделан больше на саму концепцию. Желающие разобраться во всем до конца могут ознакомиться с исходным кодом.
Поделиться с друзьями
-->

Комментарии (86)


  1. Ivan_83
    14.06.2017 12:17
    -6

    Более 1к строк шаблонной копипасты кода только чтобы в мастдае написать простенький драйвер который портит юзби.
    А потом этот драйвер ещё нужно подписать специальным сертификатом за несколько сотен зелёных иначе венда его грузить не будет.

    На других системах проблема решается правкой конфигов udev/devd.


    1. anatolymik
      14.06.2017 12:22
      -1

      Очень интересное утверждение.

      На счет шаблонов, а где их нет?

      Я правильно понимаю что конфиг udev/devd не портит USB? Т.е. если это драйвер, значит портит, а если конфиг, который читает драйвер, то не портит. Так?

      Касательно конфигов, как уже было упомянуто, драйвер простой, его вполне можно доработать чтобы не требовалась перезагрузка. Более того, если идти дальше, можно много внести всяких гибкостей, например блокирование записи и т.д. У вас это получиться на других системах простой правкой конфига?


      1. Kolyuchkin
        14.06.2017 13:30
        +3

        Функционала UDEV хватит, чтобы писать гибкие правила проверки и блокировки устройств, в том числе и с привязкой к временным промежуткам)


        1. anatolymik
          14.06.2017 13:33
          -1

          Хватит. Но когда речь идет о гибкости которая не заложена, по-моему, подобный подход решит эту проблему. Я не утверждал о простой блокировки записи. Безусловно мы его смешиваем с анализом и принятием решения динамически. В прошлом посте я выразился не точно. Извиняюсь.

          Ну и речь в статье, все-таки не об UDEV)))


          1. Kolyuchkin
            14.06.2017 13:41
            +2

            Дорогой автор, успокойтесь)) Ваша статья, как «вводный краткий курс» в системное программирование под ОС семейства MS Windows, имеет место быть — в свое время она бы мне помогла. Вот если бы Вы в статье уделили внимание еще и написанию inf-файлов, было бы совсем хорошо. А вот мониторить и конфигурировать драйвер можно через WMI-интерфейс.


            1. anatolymik
              14.06.2017 13:48
              -1

              конфигурировать драйвер можно через WMI-интерфейс

              Расскажите, как с USB решить дело. Я решений не искал. Было бы интересно узнать.


              1. Kolyuchkin
                14.06.2017 14:28
                +2

                Приведу просто ссылку — вот


                1. anatolymik
                  14.06.2017 14:29
                  -1

                  WMI будет работать только когда драйвер его поддерживает. Драйвер шины USB поддерживает соответствующий функционал и предоставляет для него интерфейсы? Вопрос заключался в этом.


                  1. Kolyuchkin
                    14.06.2017 14:37
                    +2

                    Он будет поддерживаться, если вы в драйвере зарегистрируете соответствующего агента)) В DDK все описано и есть примеры.


                    1. anatolymik
                      14.06.2017 14:37
                      -1

                      Еще раз, драйвер USB в Windows, его поддерживает? И если да, то какие интерфейсы управления он предоставляет?


                      1. Kolyuchkin
                        14.06.2017 15:35
                        +2

                        Еще раз отвечаю, зачем Вам знать, поддерживает ли этот интерфейс существующий драйвер USB? Вы в своем фильтр-драйвере его поддержите и настраиваете с помощью него свои «белые (черные)» списки)


                        1. anatolymik
                          14.06.2017 15:38
                          -1

                          Драйвер USB шины, должен зарегистрироваться с WMI как провайдер. Иначе он не будет управляться через WMI.

                          Вы в своем фильтр-драйвере его поддержите и настраиваете с помощью него свои «белые (черные)» списки)

                          А тогда фильтр зачем?


                          1. Kolyuchkin
                            14.06.2017 15:44
                            +3

                            А Вы разве не фильтр-драйвер написали? В своей статье Вы так его и обозвали — фильтр верхнего уровня.


                            1. anatolymik
                              14.06.2017 15:48
                              -3

                              А это вопрос к вам был? Зачем фильтр, если через WMI управлять можно? Вы утверждали что в фильтре надо это сделать.


                              1. Kolyuchkin
                                14.06.2017 17:37
                                +2

                                Фух, устал я)) Ваш фильтр-драйвер Вам нужен для реализации Вашей логики блокировки подключения «ненужных» USB-устройств. А вот конфигурировать список «ненужных» USB-устройств предлагаю реализовать через WMI. Вот и все. Сами же писали, что в этом у вас недоработка, что при изменении списка «ненужных» USB-устройств требуется перезагрузить компьютер.


                                1. anatolymik
                                  14.06.2017 17:39
                                  -5

                                  Недоработка и недостаток не одно и тоже.

                                  А прикрутив я WMI к своему фильтру, чтобы я выиграл стратегически? Кроме потерянного времени?


                                  1. Kolyuchkin
                                    14.06.2017 17:50
                                    +4

                                    Вот за то время, которое Вы потратили на пререкания со мной, Вы могли бы уже прикрутить к своему драйверу провайдер WMI, и время не было бы потрачено зря — Вам новые знания, Вашим читателям польза. И, по моему сугубо-субъективному мнению, время, потраченное на приобретение новых знаний и применение этих знаний на практике, никогда не станет потерянным. Я не вижу смысла продолжать эту ветвь комментариев — засим откланиваюсь.


                                    1. anatolymik
                                      14.06.2017 17:51
                                      -4

                                      Ваша позиция понятна. «В интернете кто-то не прав» (С).


                        1. anatolymik
                          14.06.2017 15:40

                          Тоже ссылку приведу: вот


      1. Ivan_83
        15.06.2017 14:34
        -1

        Я не против шаблона, я против того что он такой охренительно большой.
        У вас же там сплошные затычки, что мешало индусам реализовать в ядре простую логику уровня:
        if (NULL == cb_proc) {
        и вот тут код возврата из затычки.
        }
        ?
        (А вообще я уже забыл, может оно там так и сделано, вроде обязательным был только AddDevice и он же был как то отдельно от прочих хэндлеров, и тогда претензия не к индусам а к вам).

        Потом, что во фре что в линухе архитектура дров более удачная, там вот этого всего непотребства нет, дрова там много проще, а функционал не уступает.

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

        Чтобы понять что происходит на других системах нужно понять что там всё по другому.
        Например, обычно юзер не может монтировать диски.
        У меня диски монтируются простым скриптом, который вызывается из devd при обнаружении дисковых устройств.
        Разумеется, поправив этот скрипт или просто скопировавав и поменяв rw на ro и прописав в devd вызов копии для списка устройств можно добиться что диск будет монтироваться только для чтения.

        Но если хочется через жопу, те ядро, то на фре можно накорябать geom ноду, которая будет на 99% состоять из шаблона-затычек, и только для записи там будет ретурн с ошибкой, ну и вешать её через тот же devd.
        А ещё никто не запрещает взять и наколбасить прямо в коде юзби подсистемы всё что хочется.

        Плюс ты тут ничего не написал про отладку всего это счастья.
        Даже как хотя бы просто там понапихать везде printf() и потом ловить сообщения. В других ОС такой проблемы нет при отладке, даже более того, есть сразу встроенные отладчики, которые можно сделать чтобы вызывались при краше ОС/драйвера. Ну и корки пишутся и там вполне подробно может быть что и где упало, вплоть до номера строчки и содержимого этой строчки.

        А что до общения с драйвером, обычно делают какое то устройство, из проги его открывают через CreateFile() и херачат туда ioctl(). Потом правда оказывается что кто то таким образом позволяет любым приложениям перезаписывать/читать любой участок ядерной памяти, но это отдельная тема :)

        2 VBKesha
        Проверку отключить можно, но появится достающая надпись везде что мастдай в режиме разработчика/отладки, ты серьёзно предлагаешь так жить после отладки?
        Единственный рабочий бесплатный вариант, который может быть всё ещё доступен это опенсорсить драйвер и просить ребят из реактос чтобы подписали.

        2 redmanmale
        2 Saymon
        http://netlab.dhis.org/wiki/ru:hardware:huawei:e3272
        HiLink и NCM режимы работы.
        Но модем должен быть предварительно настроен чтобы он сразу был виден при подключении, а то по дефолту там часто режим когда виден сидюк, с которого вкорячивается софт, который просто посылает или eject сидюку или специальный код, это часто гасит сидюк и активирует всё остальное.


        1. anatolymik
          15.06.2017 14:57
          +1

          Вы вообще о чем?


  1. gjf
    14.06.2017 12:42
    -8

    Автор начал с того, что существующие решения небесплатные, а затем сваял драйвер, который ещё нужно дорабатывать и — о чудо! — который нужно небесплатно подписать, чтобы он заработал на современных ОС.
    Я ничего не упустил?


    1. anatolymik
      14.06.2017 12:55
      +6

      Мне казалось, что заголовок гласит о написании, а не предложении абсолютно бесплатного решения.

      О каких современных ОС идет речь? Драйвер работает на всех ОС.


      1. gjf
        14.06.2017 12:59
        -8

        Любая статья предполагает обоснование необходимости.
        Если кодили just for fun — ок, но только Ваш fun малоинтересен. Уровня задачки начального курса программирования на уровне ядра. Да и справились Вы так себе — да и сами написали, что ещё пилить и пилить.
        Попробуйте использовать свой драйвер на любой поддерживаемой в настоящий момент 64-разрядной ОС Windows.


        1. anatolymik
          14.06.2017 13:05
          +5

          Использую, работает. Прежде чем утверждать подобное стоило бы проверить.

          Задача не just for fun, она вышла из практики, была реальная потребность. Если вам этот fun не интересен, поправьте, но по-моему, вас никто не заставляет давать какие-либо комментарии на этот счет. Если не интересно, зачем вообще читать?

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

          Справился безусловно так себе.

          А вообще, вы просто передергиваете мои слова, тем самым меняя смысл.


          1. gjf
            14.06.2017 13:10
            -8

            Если задача из жизни, которую Вы не хотите, чтобы обсуждали — зачем о ней здесь писать? Хабр предполагает конструктивную критику, а не только восторженные вопли.
            Вы пишите, что была реальная необходимость, и Вы задачу решили — эээ, в Вашей компании нет ни одного компьютера под управлением 64-разрядной ОС позже Windows 7 включительно? Вы так и не услышали: без подписи на этих системах драйвер работать не будет! Так в чём тогда интересность и ценность Вашего решения?


            1. anatolymik
              14.06.2017 13:17
              +2

              Например, вы заблокировали доступ к Интернету одному из пользователей, но не заблокировали устройства этого ПК. В таком случае пользователю достаточно просто принести USB-модем, и Интернет у него будет. Т.е. простым блокированием доступа к Интернету дело не ограничивается.

              В самом начале, я написал практическую потребность, извиняюсь если написал размыто.

              Вы пишите, что была реальная необходимость, и Вы задачу решили — эээ, в Вашей компании нет ни одного компьютера под управлением 64-разрядной ОС позже Windows 7 включительно?

              Я драйвер подписываю.

              Несмотря на свою простоту в моем случае данный драйвер достаточно эффективно решает поставленную задачу.

              Я явно сказал что в моем случае.

              Вы так и не услышали: без подписи на этих системах драйвер работать не будет!

              Еще раз, я писал о разработке, а не об обходе проверки подписи.

              Так в чём тогда интересность и ценность Вашего решения?

              Решать вам, и остальным читателям.


              1. gjf
                14.06.2017 13:22
                -8

                То есть у Вас или Вашей компании есть деньги на сертификат для подписи драйвера, но нет денег на решение проблемы подключения сторонних устройств?
                И в итоге специалист, имеющий доступ к сертификату, целый день тратит на написание драйвера, который к тому же потом требует доработки?
                Извините, но если бы Вы работали в моей компании, после этого я бы Вас уволил.
                Но Вы правы: всегда может быть иное мнение. Посмотрим, что скажут другие.
                Для себя я всё понял, спасибо за диалог.


                1. anatolymik
                  14.06.2017 13:23
                  +2

                  Вы прям стратег!


                1. Roman_Cherkasov
                  14.06.2017 13:29
                  +4

                  Не кажется глупым решением уволить человека, который справился с задачей, без дополнительных трат и проприетарного ПО? И потом искать замену? Странное решение на мой скромный взгляд.


                  1. gjf
                    14.06.2017 13:37
                    -10

                    Если решение на уровне учителя информатики в школе — тогда да. Но тут, как видите, не тот уровень.
                    Специалист на работе должен заниматься работой. Его рабочий день стоит дороже софта для блокировки.
                    Кроме того, если за день он не успел отладить простой драйвер до состояния «больше недостатков нет» — тогда он точно не на своём месте.


                1. VBKesha
                  14.06.2017 13:41
                  +1

                  Вы правда не знаете что проверку подписи можно отключить?


                  1. gjf
                    14.06.2017 21:14
                    -2

                    Переводом в тестовый режим? Знаю, на рабочих станциях не использую. Лишняя брешь защиты.


                1. HonoraryBoT
                  14.06.2017 14:34
                  +5

                  Не подскажете название вашей компании? Просто на заметку.


                  1. janekprostojanek
                    14.06.2017 15:48
                    +3

                    Да нет у него никакой компании… И в компанию автора на место автора его бы не взяли


                    1. anatolymik
                      14.06.2017 15:51
                      +2

                      Может и есть, просто он там один, на должности генерального директора. Увольняет всех.


                  1. gjf
                    14.06.2017 21:20
                    -3

                    Извините, вакансий нет. Спросите автора статьи — судя по всему, работа у них не пыльная.


                    1. anatolymik
                      14.06.2017 21:30
                      +1

                      Ну да, не пыльная. С киркой и отбойным молотком ходить не надо. Кнопочки там всякие нажимаю.


        1. dartraiden
          15.06.2017 06:41

          Во-первых, проверка подписи отключается в Windows штатно, во-вторых, не секрет (вы это точно знаете), что в сети гуляет утилита, позволяющая подписать особым просроченным сертификатом любой драйвер, а MS закрыть уязвимость, используемую этим сертификатом не может, предпочитая игнорировать проблему.


          1. gjf
            15.06.2017 07:14
            -1

            Штатно — это перевод в тестовый режим. Слово «тестовый» Вам ничего не говорит? Да, на своём личном компьютере я для разработки могу включить такой режим, могу отключить UAC и постоянно работать под админом — но это не есть решение для рабочих станций, где необходима нормальная работа ОС и нормальный, штатный уровень безопасности.
            «Утилита в сети» — это украденый сертификат с китайской программой для подписи.
            Ребята, мы здесь обсуждаем решения для компании или пиратские обходы дома на завалинке? Давайте мухи — отдельно, котлеты — отдельно.


          1. WRP
            15.06.2017 09:07

            А можете дать ссылку на эту утилиту с просроченным сертификатом или более полную информацию? Спасибо.


  1. gdt
    14.06.2017 15:08

    Спасибо, очень интересно. На прошлой работе стояла похожая задача — надо было запретить подключение к определённому usb хабу всех устройств, кроме usb накопителей. Т. к. это было ПО для терминалов, я просто сделал перехват сообщений WM_DEVICECHANGE, и принудительно отрубал все устройства с требуемого хаба, которые не являются usbstorage.


    1. anatolymik
      14.06.2017 15:10

      Вырубали через SetupAPI?


      1. gdt
        14.06.2017 16:24

        Насколько я помню, да, давненько уже было. В крайнем случае можно devcon'ом рубить.


        1. anatolymik
          14.06.2017 16:48

          О таком решении я и не думал. В целом хорошее. Но в моем случае оно бы не подошло.


          1. HonoraryBoT
            14.06.2017 21:38

            У такого решения есть проблема с открытыми хэндлами. SetupApi не отключит девайс с открытыми хэндлами, а устройство (та же флэшка) может, например, быть занята при запущенном приложении автозапуска. До появления уведомления о новом устройстве можно успеть много чего на нем открыть. Вариант — перебирать хэндлы и закрывать их вручную, что не очень хорошо сказывается на стабильности работы приложений.


            1. gdt
              16.06.2017 19:47

              Не понимаю, о каких открытых хэндлах в данном случае идёт речь, если честно. Сообщение WM_DEVICECHANGE передаётся до тех пор, пока не обработается. Чисто теоретически, на замусоренной системе, кто-то может успеть его обработать раньше. Но тогда моя программа его не получит. Или мы говорим о разных вещах.
              P.S. в моём конкретном случае было допустимо рубить устройства devcon'ом (издержки производства, иногда, например, на уже поставленных терминалах отходит питание от купюроприёмника, и devcon — единственный способ программно вернуть устройство в рабочее состояние).


  1. redmanmale
    14.06.2017 15:29
    +1

    Безотносительно кода, решение весьма странное.
    Если у пользователя нет прав администратора, то задачу можно решить проще, стандартными средствами контроля доступа, а если права есть, то он может просто использовать обычный драйвер, разве нет?


    1. anatolymik
      14.06.2017 15:32
      +1

      Приведите пример стандартных средств.


      1. Saymon
        14.06.2017 16:10

        Извините, я давно usb-свистками не пользовался, но разве они уже могут устанавливать свои драйвера и софт, который требуется им для работы, без прав админа?


        1. anatolymik
          14.06.2017 16:11

          Ну тут разграничение прав, админ ставит софт, пользователь использует


          1. Saymon
            14.06.2017 16:18

            0_о А зачем админу сначала ставить софт для работы usb-модема, а затем писать драйвер, чтобы этот usb-модем не мог работать?


            1. anatolymik
              14.06.2017 16:22
              +1

              А дело только в модемах? Во-вторых, много драйверов в современных Windows предустановлены.


              1. Saymon
                14.06.2017 16:34

                Пример то был с модемом. И очевидно, что он не очень удачный. На моей практике, когда пользователи пытались подобным образом обойти блокировку на развлекательные ресурсы, то они обломались.Операционные системы win-7, win-8 на тот момент были.


                1. anatolymik
                  14.06.2017 16:40

                  У USB устройств есть классы, у этих классов устройств часто бывает стандартный интерфейс. Для этого стандартного интерфейса есть предустановленный драйвер в системе. И?


                  1. Saymon
                    14.06.2017 16:48

                    Вы на практике сталкивались с тем, чтобы удалось использовать usb-модем без установки дополнительного ПО?


                    1. anatolymik
                      14.06.2017 16:51

                      Именно так. Не надо только путать современные модемы, с модемами времен Windows XP.
                      Еще раз, для стандартного класса USB устройства в системе может присутствовать драйвер. Сейчас сетевые адаптеры есть работающие по USB. И никакого спец. софта для них не нужно.


                    1. Roman_Cherkasov
                      22.06.2017 10:54

                      Ни один Yota модем, которыми я к сожалению — вынужден с завидной периодичностью пользоваться — не устанавливает никакие драйвера. Windows 7 — 10. На XP говорят приходится что то ставить, но к сожалению возможности проверить — нет.


      1. redmanmale
        14.06.2017 16:47

        Возможно я не прав, но чтобы модем заработал, ему надо создать новое подключение (обычно это делает ПО модема при установке).


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


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


        1. anatolymik
          14.06.2017 16:49

          В том и прелесть, что люди подключили модем без прав админа.


          1. Saymon
            14.06.2017 16:54

            А можете модель модема озвучить?


            1. anatolymik
              14.06.2017 16:55

              Не могу, знаю только сам факт. Т.к. ИТ'шники обращались с такой просьбой.


              1. Saymon
                14.06.2017 17:09
                +1

                Тогда не факт, что это факт. Вполне вероятно либо прошляпили админский доступ, либо юзер оказался достаточно продвинутым и упорным, чтобы ломануть учетку локального админа, например включил встроенного администратора. Беглый поиск по интернету не выявил модель usb-модема, которую можно установить без прав админа. Так что вполне вы занимались написание велосипеда из за не отлаженных должным образом политик и регламентов.Если пользователь установивший вопреки правилам модем не понес никакого наказания, и не было подробного расследования для выявления факта халатности админов, где гарантия, что тот же самый юзер в следующий раз не получит снова права админа и не удалит из системы этот самописный драйвер?


                1. anatolymik
                  14.06.2017 17:13

                  Я написал, а ваше дело мне верить или нет. Есть люди которым вы верите, есть которым я.

                  Я еще раз подчеркну, в Windows предустановленных драйверов огромная масса. Полагаться на то что устройство потребует особой установки, не очень верно. Т.к. не дает максимальной гарантии.

                  P.S. На счет наказаний немного ставит в ступор. Вы встречали когда-нибудь человека которого всегда наказывали только по делу?


                  1. Saymon
                    14.06.2017 17:34

                    А в чем ступор? Первая превентивная мера защиты от несанкционированного доступа это письменное уведомление о санкциях за этот доступ под роспись. Выпуск соответствующего документа это первое, что я прошу от руководства клиента, когда они хотят в чем то ограничить пользователей. Как я и указал выше вопрос правильных политик и регламентов.

                    И лично я не ставлю под сомнение лично Вашу честность. Но вот сама предыстория вызывает сомнения.

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


                    1. anatolymik
                      14.06.2017 17:42
                      +1

                      Как показывает практика, в регламентах любой компании всегда есть дыры. Если цель ходить и заниматься справедливостью, тогда да. Хороший подход. Если ликвидировать вариант угрозы на корню, тогда технически. Пусть техника думает. Человеческий фактор никто не отменял. Да и ходить и заниматься воспитанием людей не самое интересное занятие. Лучше, если они не будут иметь технической возможности.


                      1. Saymon
                        14.06.2017 17:52
                        +1

                        Вы не поняли. Вопрос не в абстрактной справедливости, а в рациональности. Где гарантия что, использование вашего решения по обходу подписи драйверов не нанесет значительный урон безопасности? Или что не создаст проблем при подключении устройств, драйвера к которому писали «индусы», но вот именно их и нужно подключить именно к этому рабочему месту? Конечно надежней запретить использование металлических кухонных ножей, но заставлять всех использовать одноразовые пластиковые не рационально.


                        1. anatolymik
                          14.06.2017 17:56

                          Вы не поняли. Вопрос не в абстрактной справедливости, а в рациональности. Где гарантия что, использование вашего решения по обходу подписи драйверов не нанесет значительный урон безопасности?

                          В каком месте я обхожу подпись драйверов?

                          Или что не создаст проблем при подключении устройств, драйвера к которому писали «индусы», но вот именно их и нужно подключить именно к этому рабочему месту?

                          С таким подходом лучше тогда вообще ничего не делать, т.к. любое решение может нанести вред. Какие проблемы может породить фильтрация обычных запросов PnP, который писала Microsoft?

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

                          По-моему, вы перевернули все с ног на голову.


                          1. Saymon
                            14.06.2017 18:18

                            В каком месте я обхожу подпись драйверов?


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

                            Какие проблемы может породить фильтрация обычных запросов PnP, который писала Microsoft?
                            Вам разве не приходилось еще сталкиваться с тем что «это не должно приводить к проблемам» не обязательно означает, что «это действительно не привело к проблемам». Особенно когда дело касается Microsoft. :)

                            По-моему, вы перевернули все с ног на голову.
                            там опечатка была, поэтому фраза действительно получилась бессмысленной. Возможно Вам приходилось читать притчу «про хакера и начальника столовой»?

                            Ну опять же вернусь к тому, что Ваше решение в итоге не защищает от того, кто будет специально искать как его обойти\сломать, т.к. нужно не только совершенствовать замки, но и ловить взломщиков.


                            1. anatolymik
                              14.06.2017 18:33
                              +1

                              Вам разве не приходилось еще сталкиваться с тем что «это не должно приводить к проблемам» не обязательно означает, что «это действительно не привело к проблемам». Особенно когда дело касается Microsoft. :)

                              Я много с чем сталкивался. И Microsoft последняя в списке. Статистически. Вообще когда говорят «особенно Microsoft» — все становиться ясно.

                              Ну опять же вернусь к тому, что Ваше решение в итоге не защищает от того, кто будет специально искать как его обойти\сломать

                              Ну сломайте kernel mode драйвер. Обойдите его механизмы. Вы сейчас сказали в целом правильную вещь, но бессмысленную. Т.к. из такого утверждения следует что не надо ничего писать, потому что это сломают.


                1. gjf
                  14.06.2017 21:18
                  -5

                  Сдаётся мне, что отсутствие модели модема, отсутствие понимания автором защиты драйверов подписью, откровенно высосанные из пальца детали истории, отсутствие исходников и скомпилированного детища, а также активность на Хабре в рабочее время намекает, что статья — копипаста, не имеющая ничего общего с реальностью.
                  В принципе, согласен в этом с Ivan_83.


                  1. anatolymik
                    14.06.2017 21:31
                    -2

                    "А чё они говорят что у меня бомбит, когда у меня не бомбит"(С)


                1. VBKesha
                  14.06.2017 22:17

                  Я очень давно не видел этих модемов, но те что видел лет 5 назад были обычно составными устройствами состоящими из диска с дрова и ком порта(CDC). иногда с возможность работы как USB сетевуха. Многие из них требовали спец софт для активации CDC/Сетевухи. Однако их можно было потом заставить остаться в этом состоянии. В Win7 и выше вроде бы есть дрова для CDC COM порта. Насчёт USB сетевухи не уверен. Остаётся только вопрос можно ли с неадминской учеткой создавать сетевое подключение.


                  1. DaemonGloom
                    15.06.2017 07:19
                    +1

                    Дрова для некоторых USB сетевых карт есть изначально в windows 7 и более новых. Если нужно модемное подключение, то с неадминской учётки можно создать новое подключение, но нельзя запомнить пароль для всех пользователей — только для своего. Чего вполне хватает для получения интернета на устройстве. Чаще всего, новое подключение не нужно вообще, хватит стандартного сетевого подключения, создаваемого windows для каждой сетевой карты.


                1. semax95
                  15.06.2017 07:56

                  Многие модемы умеют прикидываться сетевой картой и прав админа для них не нужно, в системе уже все есть, сам в универе так делал.
                  Если у вас телефон на android подключите его как usb модем, думаю вы удивитесь.
                  Технология называется ndis


                  1. Saymon
                    15.06.2017 11:35
                    -1

                    Отличное замечание! Да действительно, для подключение смартфона ( я проверял Android)
                    в качестве модема на win10 никаких драйверов и ПО не требуется.Но это меня натолкнуло на мысль, что мы слишком зациклились на модемах и подключению по usb. Действительно пользователь может подрубить к компу и usb-wifi( современные свистки большей частью тоже без установки драйверов), а смартфон превратить в точку доступа одним нажатием, и воткнуть сетевую карту wi-fi в pci слот на материнке, и принести роутер, который может использвать в качестве wan подключения wi-fi со смартфона либо также подключать usb-модем в роутер, а компьютер подключить по Ethernet. Соответственно в двух последних случаях метод защиты автора не будет действовать, но зато будет действовать банальное отключение Dhcp на брэндмауре.


                    1. anatolymik
                      15.06.2017 11:38

                      Можно фильтровать и PCI. Как вы себе представляете что пользователь рабочего ПК вставил плату? Нет можно конечно. Вы такое видели, среди не разработчиков?


                      1. Saymon
                        15.06.2017 11:44

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


                        1. anatolymik
                          15.06.2017 11:48

                          А как же ваши ранее упомянутые регламенты компании, расследования инцидентов и система наказаний? На которые, как я понял, надо ставить приоритет, а не на технические решения.

                          А воткнуть плату для человека хоть раз собиравшего-разбиравшего комп не проблема и таких людей среди пользователей достаточно.

                          Сколько я видел людей работающих за ПК, они кнопки с трудом нажимают. Что уж говорить о подключении сетевой платы.

                          И потом, PCI это все-таки не hot-plug. Когда USB массовый. Даже если и так, вы слишком много уделяете внимания вещам, которые по своей натуре маловероятны. Целесообразно ли тратить на защиту от таких случаев много сил?


                          1. Saymon
                            15.06.2017 11:53

                            А как же ваши ранее упомянутые регламенты компании, расследования инцидентов и система наказаний? На которые, как я понял, надо ставить приоритет, а не на технические решения.

                            Человека уволили в этот же день. Он как раз на испытательном сроке был.

                            Два правила на брендмауре это быстрее чем писать драйвер по всевозможные варианты usb и pci устройств.


                            1. anatolymik
                              15.06.2017 11:57

                              Ну понятно. Без комментариев.


            1. Taciturn
              15.06.2017 12:19

              Yota WLTUBA-107, например.


  1. mrkaban
    14.06.2017 15:51
    +1

    Штука интересная, однако, мне кажется, что где-то видел бесплатное ПО для решения подобного вопроса, так сходу название вспомнить не могу.


    1. anatolymik
      14.06.2017 15:52
      -3

      Вполне может быть. Я не утруждал себя поисками.


  1. Antelle
    15.06.2017 00:24

    Вряд ли пользователь домашнего ПК заинтересуется тем, чтобы блокировать устройства на своем ПК

    Полезные применения тоже есть, чтобы в комп не совали всякое.


    1. gdt
      16.06.2017 19:53

      Домашнего ПК да. А если у вас есть терминал МФУ — например, вы печатаете с USB, будет очень неприятно, если какой-нибудь умник подойдёт к вашему терминалу с USB клавиатурой.