Windows: достучаться до железа

    Меня всегда интересовало низкоуровневое программирование – общаться напрямую с оборудованием, жонглировать регистрами, детально разбираться как что устроено... Увы, современные операционные системы максимально изолируют железо от пользователя, и просто так в физическую память или регистры устройств что-то записать нельзя. Точнее я так думал, а на самом деле оказалось, что чуть ли не каждый производитель железа так делает!

    В чём суть, капитан?

    В архитектуре x86 есть понятие «колец защиты» («Ring») – режимов работы процессора. Чем ниже номер текущего режима, тем больше возможностей доступно исполняемому коду. Самым ограниченным «кольцом» является «Ring 3», самым привилегированным – «Ring -2» (режим SMM). Исторически сложилось, что все пользовательские программы работают в режиме «Ring 3», а ядро ОС – в «Ring 0»:

    Режимы работы x86 процессора
    Режимы работы x86 процессора

    В «Ring 3» программам запрещены потенциально опасные действия, такие как доступ к I/O портам и физической памяти. По логике разработчиков, настолько низкоуровневый доступ обычным программам не нужен. Доступ к этим возможностям имеют только операционная система и её компоненты (службы и драйверы). И всё бы ничего, но однажды я наткнулся на программу RW Everything:

    RW Everything действительно читает и пишет практически всё
    RW Everything действительно читает и пишет практически всё

    Эта программа была буквально напичкана именно теми функциями, которые обычно запрещаются программам «Ring 3» - полный доступ к физической памяти, I/O портам, конфигурационному пространству PCI (и многое другое). Естественно, мне стало интересно, как это работает. И выяснилось, что RW Everything устанавливает в систему прокси-драйвер:

    Смотрим последний установленный драйвер через OSR Driver Loader
    Смотрим последний установленный драйвер через OSR Driver Loader

    Прокси-драйвера

    В итоге получается обходной манёвр – всё, что программе запрещено делать, разработчик вынес в драйвер, программа устанавливает драйвер в систему и уже через него программа делает, что хочет! Более того – выяснилось, что RW Everything далеко не единственная программа, которая так делает. Таких программ не просто много, они буквально повсюду. У меня возникло ощущение, что каждый уважающий себя производитель железа имеет подобный драйвер:

    • Софт для обновления BIOS (Asrock, Gigabyte, HP, Dell, AMI, Intel, Insyde…)

    • Софт для разгона и конфигурации железа (AMD, Intel, ASUS, ASRock, Gigabyte)

    • Софт для просмотра сведений о железе (CPU-Z, GPU-Z, AIDA64)

    • Софт для обновления PCI устройств (Nvidia, Asmedia)

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

    Результаты краткого анализа пары десятков драйверов. Могут быть ошибки!
    Результаты краткого анализа пары десятков драйверов. Могут быть ошибки!

    Небольшая легенда:

    • Mem – чтение / запись физической памяти

    • PCI – чтение / запись PCI Configuration Space

    • I/O – чтение / запись портов I/O

    • Alloc – аллокация и освобождение физической памяти

    • Map – прямая трансляция физического адреса в вирутальный

    • MSR – чтение / запись x86 MSR (Model Specific Register)

    Жёлтым обозначены возможности, которых явно нет, но их можно использовать через другие (чтение или маппинг памяти). Мой фаворит из этого списка – AsrDrv101 от ASRock. Он устроен наиболее просто и обладает просто огромным списком возможностей, включая даже функцию поиска шаблона по физической памяти (!!)

    Неполный перечень возможностей AsrDrv101
    • Чтение / запись RAM

    • Чтение / запись IO

    • Чтение / запись PCI Configuration Space

    • Чтение / запись MSR (Model-Specific Register)

    • Чтение / запись CR (Control Register)

    • Чтение TSC (Time Stamp Counter)

    • Чтение PMC (Performance Monitoring Counter)

    • Чтение CPUID

    • Alloc / Free физической памяти

    • Поиск по физической памяти

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

    Через Python в дебри

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

    Первым делом нужно установить драйвер в систему и запустить его. Делаем "как положено" и сначала кладём драйвер (нужной разрядности!) в System32:

    #puts the driver into Windows/System32/drivers folder
    def SaveDriverFile(self):
      winPath = os.environ['WINDIR']
      sys32Path = os.path.join(winPath, "System32")
      targetPath = os.path.join(sys32Path, "drivers\\" + self.name + ".sys")
      file_data = open(self.file_path, "rb").read()
      open(targetPath, "wb").write(file_data)

    Раньше в похожих ситуациях я извращался с папкой %WINDIR%\Sysnative, но почему-то на моей текущей системе такого алиаса не оказалось, хотя Python 32-битный. (по идее, на 64-битных системах обращения 32-битных программ к папке System32 перенаправляются в папку SysWOW64, и чтобы положить файлик именно в System32, нужно обращаться по имени Sysnative).

    Затем регистрируем драйвер в системе и запускаем его:

    #registers the driver for further startup
    def RegisterDriver(self):
      serviceManager = win32service.OpenSCManager(None, None, 
                                                  win32service.SC_MANAGER_ALL_ACCESS)
      driverPath = os.path.join(os.environ['WINDIR'], 'system32\\drivers\\' + 
                                self.name + '.sys')
      serviceHandle = win32service.CreateService(serviceManager,self.name,self.name,
                                                 win32service.SERVICE_ALL_ACCESS, 
                                                 win32service.SERVICE_KERNEL_DRIVER, 
                                                 win32service.SERVICE_DEMAND_START, 
                                                 win32service.SERVICE_ERROR_NORMAL,
                                                 driverPath, None,0,None,None,None)
      win32service.CloseServiceHandle(serviceManager)
      win32service.CloseServiceHandle(serviceHandle)
    
    #starts the driver
    def RunDriver(self):
      win32serviceutil.StartService(self.name)

    А дальше запущенный драйвер создаёт виртуальный файл (кстати, та самая колонка "имя" в таблице с анализом дров), через запросы к которому и осуществляются дальнейшие действия:

    И ещё одна полезная программа для ползания по системе, WinObj
    И ещё одна полезная программа для ползания по системе, WinObj

    Тоже ничего особенного, открываем файл и делаем ему IoCtl:

    #tries to open the driver by name
    def OpenDriver(self):
        handle = win32file.CreateFile("\\\\.\\" + self.name, 
                                      win32file.FILE_SHARE_READ | 
                                      win32file.FILE_SHARE_WRITE, 
                                      0, None, win32file.OPEN_EXISTING, 
                                      win32file.FILE_ATTRIBUTE_NORMAL | 
                                      win32file.FILE_FLAG_OVERLAPPED, 
                                      None)
        if handle == win32file.INVALID_HANDLE_VALUE:
              return None
        return handle
    
    #performs IOCTL!
    def IoCtl(self, ioctlCode, inData, outLen=0x1100):
        out_buf = win32file.DeviceIoControl(self.dh,ioctlCode,inData,outLen,None)
        return out_buf

    Вот здесь чутка подробнее. Я долго думал, как же обеспечить адекватную обработку ситуации, когда таких "скриптов" запущено несколько. Не останавливать драйвер при выходе нехорошо, в идеале нужно смотреть, не использует ли драйвер кто-то ещё и останавливать его только если наш скрипт "последний". Долгие упорные попытки получить количество открытых ссылок на виртуальный файл драйвера ни к чему не привели (я получал только количество ссылок в рамках своего процесса). Причём сама система точно умеет это делать - при остановке драйвера с открытым файлом, он остаётся висеть в "Pending Stop". Если у кого есть идеи - буду благодарен.

    В конечном итоге я "подсмотрел", как это делают другие программы. Выяснилось, что большинство либо не заморачиваются, либо просто ищут запущенные процессы с тем же именем. Но одна из исследованных программ имела кардинально другой подход, который я себе и перенял. Вместо того, чтобы переживать по количеству ссылок на файл, просто на каждый запрос открываем и закрываем файл! А если файла нет, значит кто-то остановил драйвер и пытаемся его перезапустить:

    #perform IOCTL!
    def IoCtl(self, ioctlCode, inData, outLen=0x1100):
      #open driver file link
      driverHandle = self.OpenDriver()
      if driverHandle is None:
        self.ReinstallDriver()
        driverHandle = self.OpenDriver()
        #second try
        if driverHandle is None:
          return None
      #perform IOCTL
      out_buf = win32file.DeviceIoControl(driverHandle,ioctlCode,inData,outLen,None)
      #close driver file link
      win32file.CloseHandle(driverHandle)
      return out_buf

    А дальше просто реверсим драйвер и реализуем все нужные нам вызовы:

    class PmxInterface:
      def __init__(self):
        self.d = PmxDriver("AsrDrv101")
    
        def MemRead(self, address, size, access=U8):
          buf = ctypes.c_buffer(size)
          request = struct.pack("<QIIQ", address, size, access, 
                                ctypes.addressof(buf))
          if self.d.IoCtl(0x222808, request, len(request)):
            return bytearray(buf)
          else:
            return None
    
          def MemWrite(self, address, data, access=U8):
            buf = ctypes.c_buffer(data, len(data))
            request = struct.pack("<QIIQ", address, len(data), access, 
                                  ctypes.addressof(buf))
            return self.d.IoCtl(0x22280C, request, len(request)) is not None
          # (и все остальные тоже)

    И вуаля:

    Легко и непринуждённо в пару команд читаем физическую память
    Легко и непринуждённо в пару команд читаем физическую память

    PCI Express Config Space

    Немного отвлечёмся на один нюанс про PCIE Config Space. С этим адресным пространством не всё так просто - со времён шины PCI для доступа к её конфигурационному пространству используется метод с использованием I/O портов 0xCF8 / 0xCFC. Он применён и в нашем драйвере AsrDrv101:

    Чтение и запись PCI Config Space
    Чтение и запись PCI Config Space

    Но через этот метод доступны только 0x100 байт конфигурационного пространства, в то время как в стандарте PCI Express размер Config Space у устройств может быть достигать 0x1000 байт! И полноценно вычитать их можно только обращением к PCI Extended Config Space, которая замаплена где-то в адресном пространстве, обычно чуть пониже BIOS:

    Адресное пространство современного x86 компа, 0-4 ГБ
    Адресное пространство современного x86 компа, 0-4 ГБ

    На чипсетах Intel (ну, в их большинстве) указатель на эту область адресного пространства можно взять из конфига PCI устройства 0:0:0 по смещению 0x60, подробнее описано в даташитах:

    У AMD я такого не нашёл (наверняка есть, плохо искал), но сам факт неуниверсальности пнул меня в сторону поиска другого решения. Погуглив стандарты, я обнаружил, что указатель на эту область передаётся системе через ACPI таблицу MCFG

    А сами ACPI таблицы можно найти через запись RSDP, поискав её сигнатуру по адресам 0xE0000-0xFFFFF, а затем распарсив табличку RSDT. Отлично, здесь нам и пригодится функционал поиска по памяти. Получаем нечто такое:

    rsdp = self.PhysSearch(0xE0000, 0x20000, b"RSD PTR ", step=0x10)
    #use rsdt only for simplicity
    rsdt = self.MemRead32(rsdp + 0x10)
    (rsdtSign, rsdtLen) = struct.unpack("<II", self.MemRead(rsdt, 8, U32))
    if rsdtSign == 0x54445352: #RSDT
      headerSize = 0x24
      rsdtData = self.MemRead(rsdt + headerSize, rsdtLen - headerSize, U32)
      #iterate through all ACPI tables
      for i in range(len(rsdtData) // 4):
        pa = struct.unpack("<I", rsdtData[i*4:(i+1)*4])[0]
        table = self.MemRead(pa, 0x40, U32)
        if table[0:4] == b"MCFG":
          #we have found the right table, parse it
          (self.pciMmAddress, pciSeg, botBus, self.pciMmTopBus) = 
          	struct.unpack("<QHBB", table[0x2C:0x38])

    На всякий случай оставляем вариант для чипсетов Intel

    if self.PciRead16(PciAddress(0,0,0,0)) == 0x8086:
      #try intel way
      pciexbar = self.PciRead64(PciAddress(0,0,0,0x60))
      if pciexbar & 1:
        self.pciMmTopBus = (1 << (8 - ((pciexbar >> 1) & 3))) - 1
        self.pciMmAddress = pciexbar & 0xFFFF0000

    Всё, теперь осталось при необходимости заменить чтение PCI Express Config Space через драйвер на чтение через память. Теперь-то разгуляемся!

    Читаем BIOS

    В качестве примера применения нашего "тулкита", попробуем набросать скрипт чтения BIOS. Он должен быть "замаплен" где-то в конце 32-битного адресного пространства, потому что компьютер начинает его исполнение с адреса 0xFFFFFFF0. Обычно в ПК стоит флеш-память объёмом 4-16 МБ, поэтому будем "сканировать" адресное пространство с адреса 0xFF000000, как только найдём что-нибудь непустое, будем считать, что тут начался BIOS:

    from PyPmx import PmxInterface
    pmx = PmxInterface()
    
    for i in range(0xFF000000, 0x100000000, 0x10000):
      data = pmx.MemRead(i, 0x20)
      if data != b"\xFF"*0x20 and data != b"\x00"*0x20:
        biosLen = 0x100000000-i
        print("BIOS Found at 0x%x" % i)
        f = open("dump.bin", "wb")
        for j in range(0, biosLen, 0x1000):
          data = pmx.MemRead(i + j, 0x1000)
          f.write(data)
          break

    В результате получаем:

    Вот так в 10 строчек мы считали BIOS
    Вот так в 10 строчек мы считали BIOS

    Но подождите-ка, получилось всего 6 мегабайт, а должно быть 4 или 8 что-то не сходится. А вот так, у чипсетов Intel в адресное пространство мапится не вся флешка BIOS, а только один её регион. И чтобы считать всё остальное, нужно уже использовать SPI интерфейс.

    Не беда, лезем в даташит, выясняем, что SPI интерфейс висит на PCI Express:

    И для его использования, нужно взаимодействовать с регистрами в BAR0 MMIO по алгоритму:

    1. Задать адрес для чтения в BIOS_FADDR

    2. Задать параметры команды в BIOS_HSFTS_CTL

    3. Прочитать данные из BIOS_FDATA

    Пилим новый скрипт для чтения через чипсет:

    from PyPmx import PmxInterface, PciAddress, U32
    
    spi = PciAddress(0, 31, 5)
    pmx = PmxInterface()
    spiMmio = pmx.PciRead32(spi + 0x10) & 0xFFFFF000
    f = open("dump.bin", "wb")
    
    for i in range(0, 0x800000, 0x40):
      # write BIOS_FADDR
      pmx.MemWrite32(spiMmio + 0x08, i)
      # write BIOS_HSFTS_CTL
      #        read      0x40 bytes      start     clear fcerr & fgo
      cmd = (0 << 17) | (0x3F << 24) | (1 << 16) |         3
      pmx.MemWrite32(spiMmio + 0x04, cmd)
      # wait for read or error
      curCmd = pmx.MemRead32(spiMmio + 0x04)
      while curCmd & 3 == 0:
        curCmd = pmx.MemRead32(spiMmio + 0x04)
      # read BIOS_FDATA
      data = pmx.MemRead(spiMmio + 0x10, 0x40, U32)
      f.write(data)

    Исполняем и вуаля - в 20 строчек кода считаны все 8 МБ флешки BIOS! (нюанс - в зависимости от настроек, регион ME может быть недоступен для чтения).

    Точно так же можно делать всё, что заблагорассудится - делать снифер USB пакетов, посылать произвольные ATA команды диску, повышать частоту процессора и переключать видеокарты. И это всё - с обычными правами администратора:

    Немного помучившись, получаем ответ от SSD на команду идентификации
    Немного помучившись, получаем ответ от SSD на команду идентификации

    А если написать свой драйвер?

    Некоторые из вас наверняка уже подумали - зачем так изворачиваться, реверсить чужие драйвера, если можно написать свой? И я о таком думал. Более того, есть Open-Source проект chipsec, в котором подобный драйвер уже разработан.

    Зайдя на страницу с кодом драйвера, вы сразу наткнетесь на предупреждение:

    WARNING
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    !!
    !! Chipsec should only be run on test systems! 
    !! It should not be installed/deployed on end-user systems!
    !! 
    !! There are multiple reasons for that:
    !! 
    !! 1. Chipsec kernel drivers provide raw access to HW resources to 
    !! user-mode applications (like access to physical memory). This would 
    !! allow malware to compromise the OS kernel.
    !! 2. The driver is distributed as a source code. In order to load it
    !! on OS which requires signed drivers (e.g. x64 Microsoft Windows 7 
    !! and higher), you'll need to enable TestSigning mode and self-sign 
    !! the driver binary. Enabling TestSigning (or equivalent) mode also 
    !! turns off important protection of OS kernel.
    !!
    !! 3. Due to the nature of access to HW resources, if any chipsec module 
    !! issues incorrect access to these HW resources, OS can crash/hang.
    !!
    !! If, for any reason, you want to production sign chipsec driver and 
    !! deploy chipsec on end-user systems,
    !! DON'T!
    !!
    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    В этом предупреждении как раз и описываются все опасности, о которых я рассказывал в начале статьи - инструмент мощный и опасный, следует использовать только в Windows режиме Test Mode, и ни в коем случае не подписывать. Да, без специальной подписи на обычной системе просто так запустить драйвер не получится. Поэтому в примере выше мы и использовали заранее подписанный драйвер от ASRock.

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

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

    У меня под рукой нет Windows DDK, так что я взял 64-битный vfd.sys, скомпилированный неким critical0, и попросил dartraiden подписать его «древне-китайским способом». Такой драйвер успешно загружается и работает, если vfdwin запущена с правами администратора

    Драйвер из статьи действительно подписан, и действительно неким китайским ключом:

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

    Немного поиска этого имени в гугле, и я натыкаюсь на вот эту ссылку, откуда узнаю, что:

    • есть давно утёкшие и отозванные ключи для подписи драйверов

    • если ими подписать драйвер - он прекрасно принимается системой

    • малварщики по всему миру используют это для создания вирусни

    Основная загвоздка - заставить майкрософтский SignTool подписать драйвер истёкшим ключом, но для этого даже нашёлся проект на GitHub. Более того, я нашёл даже проект на GitHub для другой утилиты подписи драйверов от TrustAsia, с помощью которого можно подставить для подписи вообще любую дату.

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

    И в самом деле, китайская азбука
    И в самом деле, китайская азбука

    И точно так же, как и AsrDrv101, драйвер удалось без проблем запустить!

    А вот и наш драйвер запустился
    А вот и наш драйвер запустился

    Из чего делаю вывод, что старая идея с написанием своего драйвера вполне себе годная. Как раз не хватает функции маппинга памяти. Но да ладно, оставлю как TODO.

    Выводы?

    Как видите, имея права администратора, можно делать с компьютером практически что угодно. Будьте внимательны - установка утилит от производителя вашего железа может обернуться дырой в системе. Ну а желающие поэкспериментировать со своим ПК - добро пожаловать на низкий уровень! Наработки выложил на GitHub. Осторожно, бездумное использование чревато BSODами.

    Небольшой Update

    В Windows есть фича "Изоляция ядра", которая включает I/O MMU, защищает от DMA атак и так далее (кстати об этом - в следующих сериях)

    Так вот, при включении этой опции, некоторые драйвера (в том числе RW Everything и китайско-подписанный chipsec_hlpr) перестают запускаться:

    Тем не менее, рассмотренный пример утилиты на базе AsrDrv работает:

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 90

      +11
      Как видите, имея права администратора, можно делать с компьютером практически что угодно.
      На то он и администратор. Можно и руткит в прошивку мат.платы засадить.

      В Linux вот год назад задумались над тем, что неплохо было бы root-а сделать менее всемогущим.

      нюанс — в зависимости от настроек, регион ME может быть недоступен для чтения
      Зависит от того, насколько сильно вендор решил положить болт на рекомендации Intel. Привет MSI и Gigabyte у которых все регионы открыты на чтение и запись.

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

      И снова передаю привет Gigabyte, которая на недешевой мат.плате за 12к специально убрала (пункт есть, но принудительно скрыт) из настроек прошивки управление подсветкой, чтобы вынудить пользователя установить для этого софт в систему.

      На удивление кривые прошивки у этого вендора…
        +4
        Именно так, но я сталкивался с мнением, что воздействие с правами админа ограничивается софтом. Хотел продемонстрировать именно «железную» сторону.
          +2
          С видеокартой Gigabyte GTX980ti шел софт для разгона. И как то в играх наблюдались микрофризы. Удаление утилиты для «разгона» сразу решило проблему :D
            0
            Можно и руткит в прошивку мат.платы засадить.
            А есть какой-то способ защититься от этого?
              +1
              Современные ноутбуки с правильно настроенным Boot Guard защищены от этого (в теории).
                0
                Вот только с более-менее правильной настройкой Boot Guard-а идут всякие бизнес-серии, а не игровые acer/msi и т.п., но тут надо спросить у тех, кто регулярно это мониторит.
                  +1
                  Так на игровых намеренно разрешена модификация — мало ли что геймеры хотят себе настроить / переделать / разогнать.
                    0
                    Разгон и настройка на Boot Guard не влияют. Модификация — только в формате ноутбуков с заменяемой видеокартой, а таких не сказать, что очень много на рынке есть. Но и в таком случае BG надо хотя бы настроить, а не оставлять в factory состоянии, когда продвинутый идиот сможет туда свои ключи закинуть.
                +1
                Внимательно следить за тем, кто запрашивает повышение прав, не одобрять запросы без явной необходимости.

                Выбирать вендоров, которые уделяют должное внимание безопасности (Dell, HP, Apple).

                К сожалению, интернет, наоборот, пестрит советами «как отключить UAC». В итоге, все приложения работают с максимальными правами, берём какой-нибудь Flash Programming Tool и пишем что хотим, куда хотим. Удобно — да. Безопасно — нет.
                0
                Проекты OpenRGB и liquidctl не поддерживают данную материнскую плату? Мне они заменили всю проприетарщину вполне успешно.
              0
              малварщики по всему миру используют это для создания вирусни
              Лично не встречал вирусни, подписанной таким способом, но давным-давно как-то ради интереса подписал заведомо известный всем Conficker/Kido и посмотрел на реакцию антивирусов. Panda Antivirus, помню, этот тест провалил — добавление такой вот просроченно-отозванной подписи моментально сняло детект.
                0
                Это может быть по совсем иной причине — например для детекта используется хэш файла. Или последние 0x200 байт. Надо исследования проводить чтобы понять в чем именно причина…
                  +1
                  Думаю, там проще
                  I've noticed during testing against Anti-Virus over the years that each is different and each prioritize PE signatures differently, whether the signature is valid or not. There are some Anti-Virus vendors that give priority to certain certificate authorities without checking that the signature is actually valid, and there are those that just check to see that the certTable is populated with some value. It's a mess.
                +2
                Большая работа проделана! :-) Странно, что авторы драйверов не ограничивают тех, кто может с драйвером работать. По логике вещей надо бы проверять что вызывающий процесс подписан своей валидной подписью или что-то в том же духе
                  0

                  Ну ввобше да. Драйвер должен проверять подпись процессамэ который его загружает. И многие так уже делают. Была вирусня с подписанным драйвером от какой то софтины prcissmonitor или processhacer2 неипомню уже. Но драйвер там вообще ни чего не проверял. Еще и bof иам был вроде..

                    +5
                    И чем бы это помогло? Допустим мы делаем в драйвере А проверку того, что его юзает подписанная валидной подписью программа Б. Мелваря запускает программу Б, инжектит в неё свою дллку, запускает поток и лезет к драйверу. Драйвер проверяет подпись того, кто к нему стучится (программы Б) — всё ок!

                    Более того, тут нам даже никакое асиметричное шифрование не поможет, поскольку ключ для него в любом случае придётся вшить либо в драйвер, либо в программу — а значит его всегда можно будет достать.
                      0
                      Драйвер радостно может проверять что куда инжектится, загружается и так далее
                        +2
                        Наверняка может. И, возможно, эти техники реализованы в каких-нибудь там антивирусах. Но если мы пишем драйвер какой-нибудь моргалки светодиодами — будем ли мы заморачиваться на анализ всех возможных способов инжектинга и модификации кода? Нет, не будем.
                          0
                          Тогда вполне логично ожидать что те же самые АВ начнут детектить эти драйвера как потенциально опасное ПО после того, как они будут замечены в реальных атаках.
                            +2
                            С чего бы? Они же сами по себе не являются вредоносным кодом. Если в реальной атаке, например, будет использована команда «dir» — так её что, тоже надо детектить? Брешь в системе — это одно, а тот, кто использует эту брешь — это другое.
                              0
                              Это потенциально опасное ПО, как всякие там продукты nirsoft
                                +1
                                Всё вокруг — потенциально опасное ПО. В Windows баги десятками находят, апдейты офиса каждые 2 недели приходят, Хром вон кучу денег платит за найденные секьюрити-баги. Что ж это всё теперь — банить?
                                  +1
                                  Хром и винда хотя бы обновления получают. Авторы драйверов, подозреваю, не раз получали сообщения о том что надо бы как-то ограничивать тех, кто может с ними работать. Не приняли меры — их проблемы.
                            0
                            будем ли мы заморачиваться на анализ всех возможных способов инжектинга и модификации кода?


                            Похорошему это должны делать разработчики DDK. Можно усложнить взлом, но совсем предотвратить пока невозможно.

                            Я бы сделал какой-нибудь подписанный канал для вызова функций драйвера. То есть параметры вызова должны подписываться, а драйвер должен проверять валидность подписи и только после этого исполнять функцию.
                              +2
                              Ну так а где хранить ключи для подписи? Код приложения в user-space полностью доступен атакующему, код драйвера — тоже (это же просто исполняемый файл на диске, прочитать его всегда можно).
                          +9
                          Надо драйвера писать нормально, а не по принципу «Ну нам надо по памяти лазать и в порты писать, добавлю ка я в экспорт функции outw и mmap». Драйвер видеокарты должен лезть только в те ресурсы, которые использует видеокарта, а к ресурсам, которые нужны для её первоначальной настройки (да хоть 0xCF8 порты и компания), он не должен давать доступа по интерфейсам, которые доступны вне пространства ядра.
                            0
                            Надо, но если майкрософт вдруг решит НЕ пропускать драйвера, написанные не достаточно безопасно — мы с удивлением обнаружим, что 90% привычных железок (и куча просто програм) вдруг перестали работать. Чего только стоит подзабытая история с выходом Windows Vista, где Microsoft сделала безопасным графический стек для того чтобы драйвера видюх не валили винду с синим экраном — и это отложило поддержку висты производителями видеокарт НА ГОДЫ. Я своими глазами видел коробки видеокарт, которые наперёд маркетологами были маркированы лейбой «поддерживает Windows Vista», а потом поверх этой маркировкой были наклеены отдельные лейбы где было написано «сорри, поторопились, не поддерживает».
                              +1
                              Обратная совместимость она такая.

                              Да хоть даже CSM взять. 2020 год заканчивается, а его всё ещё не могут закопать. И попробуй это сделай, какой вой поднимется — «аааа, это сговор, чтобы меня любимого согнать с моей семёрочки на десятку, уууущемляют».
                                +1
                                Да блин, на новом железе установка семёрки превращается в установку XP на железо 2015 года — поставить то поставишь, а потом надо проявить мастерство гуглфу и найти какие-нибудь дрова, которые хоть как-то заработают. Да и пора уже стюардессу закопать наконец.
                                  0
                                  «А потом пилоты сказали „хватит разврата“ и выкопали стюардессу»?
                                    0
                                    Нет, это та стюардесса, которую уже один раз закопали и потом откопали.
                                  0
                                  вой поднимется — «аааа, это сговор, чтобы меня любимого согнать с моей семёрочки на десятку, уууущемляют».
                                  Есть куча промышленных систем, расчитанных на работу 10+ лет. И их полно на семёрке. А ещё полно банкоматов с XP ;)
                          +2
                          Несколько моментов:
                          1. При создании службы драйвера указывать путь к файлу (nullptr) необязательно при следующих условиях:
                            • Путь %SYSTEMROOT%\System32\drivers
                            • Имя файла драйвера (без расширения .sys) соответствует имени службы (менеджер служб развернет его в %SYSTEMROOT%\System32\drivers\<SERVICE_NAME>.sys)

                            Есть еще условия, но они не для случая из статьи.
                          2. Alloc/free физической памяти
                            Точно физической? Не виртуальной?
                          3. Способы найти открытые дескрипторы есть через NtQuerySystemInformation (через SystemHandleInformation или SystemObjectInformation), но они имеют некоторые неприятные недостатки.

                            +2
                            При создании службы драйвера указывать путь к файлу (nullptr) необязательно
                            Не знал, спасибо!
                            Точно физической? Не виртуальной?
                            Блока непрерывной некешируемой памяти (MmAllocateContiguousMemorySpecifyCache), с возвратом как виртуального, так и физического адреса. По факту дальше работа с этим блоком ведётся через функции чтения/записи физической памяти. Виртуальную можно и из Ring 3 выделить, тут чуть другой случай.
                            Способы найти открытые дескрипторы есть через NtQuerySystemInformation
                            Смотрел Sysinternals Handle, там вроде оно применялось, перебирает все процессы и все хэндлы в них, посчитал, что это как-то чересчур
                              0
                              Этот момент (с перебором и отображением хендлов в свой процесс), как раз, не очень сложный. А вот решения проблемы, если среди этих всех хендлов проскочит блокирующий pipe, в user-mode не существует. При попытке получить его символическое имя (в user-mode) поток заблокируется в ожидании данных в этом pipe и сбросить его не получится даже через TerminateThread. Ну а процесс останется висеть до ближайшей перезагрузки. Поэтому различные UnBlock, ProcessHacker и, да, ProcessExplorer, используют драйвер уровня ядра, где получают имя через ObQueryNameString (пример).

                              У SystemObjectInformation другой недостаток: должен быть включен глобальный FLG_ENABLE_HANDLE_TYPE_TAGGING, и тогда можно будет из тегов вытянуть имя файла (так работает, к примеру, openfiles.exe).

                              В целом соглашусь, что без уровня ядра найти референсы на драйвер изящным способом невозможно. А вот в Linux, кстати, можно даже в командной строке обычным поиском в /proc/{pid}/fd/
                            –1

                            Спасибо. Ещё одна причина для того чтобы игрушки ставить в виртуализированной винде. Как можно хранить свои банковские данные в системе где каждая вторая игра хочет установить свой системный драйвер?!
                            Но чтобы настолько наплевательски относится к пользователю как со стороны микрософт, так и ASRock и других… Они превысили мои самые смелые ожидания.

                              +1
                              Эм, Может лучше банковские данные в виртуализованную винду засунуть? Мне кажется, так оно надежнее.
                                0
                                Так ведь хостовая винда имеет доступ ко всей физической памяти, а виртуализированная — только к своей
                                  +3

                                  У меня ещё лучше — host Linux/vfio, винда с GPU в виртуальной машине. 95% нативной производительности в играх. Минимум софта на хосте.

                                    0
                                    А можно подробнее, что за виртуализация и какой образ винды для нее?
                                      –1

                                      На русском не видел информации. На английском можно начать с https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF
                                      Образ винды качать с микрософта по кличевым словам windows 10 iso, типа:
                                      https://www.microsoft.com/en-au/software-download/windows10ISO

                                        +1

                                        qemu/kvm + vfio лучшее решение ever, сам использую.
                                        На хосте боевая система на ядре linux, на виртуалке с проброшенной второй видюхой винда (нужна для связки осёл+dotnet (спасибо HP))
                                        при помощи synergy вторая система (неважно виртуалка или железка) работает так словно это второй монитор к основной системе, одна клавомышь, общий буфер обмена…
                                        удобно до жути, хотя если видюшка от зелёных (именно geforce, с quadro нет проблем) приходится немного пожонглировать костылями при первоначальной настройке.
                                        плюс virtio диск и сетёвка снимают часть нагрузки с хоста.


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


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

                                          0
                                          Поддерживаю. Хост — Linux, клиенты — windows, haiku. qemu/kvm + vfio Производительность на уровне нативной работы.
                                          Такое же решение (с VM) упоминается в тесте одного из российских вендоров безопасности (non-Negative Technologies)
                                  –5

                                  Как можно хранить свои банковские данные в винде впринципе?

                                  –2
                                  Хм. Есть программулинка «ArtMoney», которая заточена на то, чтобы в играх ставить бесконечные жизни и прочее. Она тоже просто тупо в память напрямую пишет.
                                    +12

                                    Там виртуальная память определённого процесса, а не физическая.

                                    0

                                    А вот интересно, как всякие анти-чит программы типа EAC к таким криво подписанным драйверам относятся?

                                      +1
                                      Зависит от кривости рук разработчика. Например, в Black Desert античит реагирует на FreePascal
                                        0
                                        Blizzard-овский Warden реагирует на запущенную IDA. Решил я как-то пореверсить совершенно сторонний бинарник, пока жду очередь в WoW… игра через небольшое время молча завершается.
                                          0
                                          У Black Desert вообще шаловливые ручки, почитав их ToS и посмотрев куда их бинарники тычатся удалил нафиг, вернул деньги и запросил удалить все данные, а то и за игру платишь и инфу им сливаешь, а в ToS кавардак т.к. по нему они инфу только для бесплатных игр могут собирать.
                                          0
                                          Относятся с неодобрением.
                                            0

                                            Вы проверяли? То, что тот же EAC не любит "test signing mode", это известно. но тут то ее нет?


                                            P.S. Что-то самому рисковать своим аккаунтом в WarThunder не хочется...

                                          +1
                                          Это всё не то чтобы вот прямо новость. Чтобы управлять железом — кто-то должен иметь право к нему лезть. И этот кто-то в сегодняшнем мире — корректно подписанный драйвер. И это ещё хорошо, потому что были у нас и времена WindowsXP, где подпись драйверов не была обязательной и каждый второй из них падал с «синим экраном» и времена Win3.1 где это могла сделать вообще любая программа, даже не драйвер. Сейчас-то, по крайней мере, драйвер надо подписать — уже много дураков и вирусописателей отсеивается.

                                          Хаки с подписью китайскими отозванными сертификатами будут работать ведь только на какой-то неапдейченой винде без доступа в Интернет?
                                            0

                                            Читерские сайты завалены разного рода driver mapper'ами под любые версии винды и задача их одна — загрузить и выполнить произвольный код в ядре без каких либо подписей. Спасибо веднорам и мс за их монолитное решето.

                                              0
                                              За что минусите этот комментарий?

                                              Всё верно, нет НИ ОДНОГО вендора, который бы своевременно закрывал подобные дыры или отзывал сертификаты. Всем абсолютно насрать.
                                              А какой-нибудь Асус вообще превратит все свои драйверы в тыкву, если пофиксит большинство подобных решёт отзывом сертификатов.

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

                                              Античиты давно уже на вендоров не надеются, а пилят свои способы защиты.
                                              Кстати, сами античиты — тот ещё рассадник дырявых god-mode API. Вышеупомянутый Black Desert — отличный пример того, как достаточно длительное время школьники хакали игру встроенным в неё же античитом :D
                                              +3
                                              WindowsXP, где подпись драйверов не была обязательной и каждый второй из них падал с «синим экраном»

                                              Ну не нужно преувеличивать.
                                              Сейчас-то, по крайней мере, драйвер надо подписать — уже много дураков и вирусописателей отсеивается.

                                              С другой стороны, состав драйверов не поменялся. Та же нвидиа, тот же реалтек.
                                                0
                                                Хаки с подписью китайскими отозванными сертификатами будут работать ведь только на какой-то неапдейченой винде без доступа в Интернет?
                                                Вот именно, что нет, я на последней обновлённой, с интернетом проверял. В этом и суть.
                                                  +3
                                                  Хаки с подписью китайскими отозванными сертификатами будут работать ведь только на какой-то неапдейченой винде без доступа в Интернет?
                                                  Всё работает на полностью обновлённой Windows 10 2004 и Windows 8.1, без перевода даты, без очистки хранилища отозванных сертификатов, с интернетом. В свойствах файла написано, что сертификат отозван, но всё работает идеально.

                                                  А год назад не работало. У одного из промежуточных сертификатов истёк срок действия. Я полагаю, это вызвало в Windows срабатывания какой-то ошибки, которая ведёт к успешной валидации сертификата в ядре.
                                                    0
                                                    Насчёт года не знаю, но это совершенно точно работало года 3 назад. Можно посмотреть на ru-board в варёзном топике Sandboxie. Пока программа не стала бесплатной, этим способом долгие годы подписывали её крякнутый драйвер.
                                                      0

                                                      Зачем же тогда на ru-board писали в инструкции о необходимости перевода даты на время установки сертификата, а также об очистке хранилища отозванных сертификатов, в середине 2017 года?
                                                      https://forum.ru-board.com/topic.cgi?forum=55&bm=1&topic=13065#1


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

                                                        0
                                                        А, я думал вы про то, что таким образом подписанный драйвер в принципе не работал год назад.

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

                                                        Кэш отозванных сертификатов, кстати, я никогда не очищал.
                                                          0
                                                          Иначе, это не защита, а фикция (проверяем только при установке, да ещё и онлайн).

                                                          Онлайн рубят для предотвращения синхронизации времени. Список отозванных и так хранится локально.
                                                            0
                                                            Можно же невалидный NTP сервер указать.
                                                    +2
                                                    и времена WindowsXP, где подпись драйверов не была обязательной и каждый второй из них падал с «синим экраном»

                                                    Эм… вы ОЧЕНЬ сильно преувеличиваете. Или, возможно, вы не так выразились или я не так понял. Имею большой опыт эксплуатации парка машин с XP с постоянной сменой оборудования и драйверов, на многих система стояла больше 10 лет (особенности производства). BSOD'ы были, конечно, но не так чтобы прям вот очень часто, я бы даже сказал, довольно редко. Да и дома у меня файловым сервером сейчас трудится старичок 2005 года сборки на Pentium 4 и с XP, с 2005 по 2011 бывший основным рабочим и игровым компьютером и переживший кучу апгрейдов, смен драйверов, тестов самописных драйверов и прочего, так я там BSOD видел раза 3 за 5 лет (система не переустанавливалась в этот период).
                                                      –1
                                                      брррр… сколько ж этот агрегат искричества сожрал впустую
                                                    0
                                                    Спасибо за статью! Я бы сказал в конце — бездумное использование черевато выходом из строй отдельных компонентов или всего компьютера целиком.
                                                      +2
                                                      Ну не, чтобы что-то действительно сломать, как раз нужно подумать. А так — BSOD и перезагрузка.
                                                        0
                                                        Ну как — если есть доступ к биосам устройств, их наверно можно стереть, а это уже поломка. Было так один раз когда прошивал видеокарту под Windows. Исправить смог только подключив другую PCI видеокарту.
                                                          +1
                                                          Так-то да, но чтобы перешить BIOS, нужно серьёзно вникнуть в даташиты и подумать. А бездумное использование в моём понимании это прочитать / записать случайные адреса, поиграться с MSR и CR, ну и так далее.
                                                            0
                                                            MSR достаточно чтобы спалить проц: достаточно его просто овервольтнуть
                                                        0
                                                        бездумное использование это вообще так себе идея
                                                          +2
                                                          Мой опыт работы в техподдержке говорит о том что самые хитрые и вредоносные действия (о которых я и подумать не мог) совершает самый неопытный пользователь.
                                                        +2
                                                        Чтение CPUID
                                                        Это вроде всегда и так доступно из ring 3.
                                                          0
                                                          Как и TSC, по крайней мере в ранних Windows 10 читался из ring 3.
                                                            0
                                                            TSC может запретить ОС, но по умолчанию разрешено, CPUID нельзя запретить (ну может только через виртуализацию, если заморочиться).
                                                          0
                                                          Меня вот что заинтересовало: на гитхабе в репозитории hzqst/FuckCertVerifyTimeValidity написано, что «project prevents the signtool from verifing cert time validity and let you sign your bin with outdated cert without changing system time manually».
                                                          У меня сейчас под рукой нет истёкшего сертификата, но я что, могу просто отмотать часы назад и подписать исполняемый файл или библиотеку истёкшим сертификатом вот так вот просто? Мне всегда казалось, что оно на timestamp.verisign.com/scripts/timestamp.dll лезет за временной меткой.
                                                            +1
                                                            но я что, могу просто отмотать часы назад и подписать исполняемый файл или библиотеку истёкшим сертификатом вот так вот просто?
                                                            Конкретно в этом случае сама программа для подписи проверяет время жизни сертификата, и не даёт подписать файл без перевода времени. Она не добавляет timestamp от центра сертификации в подпись.

                                                            Рабочую подпись без костылей можно сделать с помощью osslsigncode.

                                                            Но см. habr.com/ru/post/527006/#comment_22283138
                                                              +1
                                                              1) можно подписать без метки времени

                                                              2) HookSigntool позволяет использовать свой сервер для создания метки времени
                                                              +1
                                                              А возможно ли, не прибегая к каким-то совсем извращенным(а если прибегая, то к каким?) методам заполучить доступ к функциям Ring -1 или даже -2?
                                                              Также я слышал про то, что каким-то образом умельцы отключают Intel Management Engine(которые вроде как вообще -3), и аналогичное железо у AMD, это как-то связано с возможностью работы с -1 и -2 уровнями?
                                                                0
                                                                Там свои проверки и сертификаты.
                                                                  0
                                                                  ME/PSP вы отключить полностью не сможете на современных платах(в случае свежих АМДшных Райзенов оно вообще настройку памяти выполняет), перевести ME в режим HAP (доверенная платформа от АНБ) — можно, оно тогда вроде как прекращает быть доступным из системы, но кто его в реальности знает, что оно до этого делает. С "-1" и "-2" уровнями это никак не связано. Про SMM(-2) — доступ возможен если либо есть дыры (к примеру обработчик SMM не осуществляет проверку входных данных), либо если IBV конкретно накосячил и не закрыл доступ в SMRAM(чего я давно не встречал). Про -1 — надо изучать гипервизор, который крутится на этом уровне, можете почитать материалы на тему «Escape from virtual machine»
                                                                    0
                                                                    умельцы отключают Intel Management Engine
                                                                    Обрезают прошивку Management Engine, оставляя только секции кода, необходимого для инициализации железа (совсем без ME вы не сможете стартануть).
                                                                    –3
                                                                    Спасибо!
                                                                    Очередной раз понимаешь, что лучшая винда — виртуальная винда!
                                                                      +2
                                                                      Каждый раз читая подобные статьи вспоминаю про хакера в столовой
                                                                        0
                                                                        Хотелось бы внести еще 5 копеек про подобную опасность драйверов.
                                                                        githacks.org/xerox/vdm
                                                                        Целый фреймворк эксплуатации подобных драйверов, выставляющих в IoControl системные функции в обход проверок безопасности. Коллекция впечатляет, а самое страшное — коллекция далеко неполная.
                                                                        +1

                                                                        Мда, вот это решето. Самое печальное, что в остальных ОС ситуация скорее всего не лучше.

                                                                          0
                                                                          К слову, в Windows есть фича «Изоляция ядра», после которой часть драйверов перестаёт работать (RW Everything выдаёт ошибку, китайско-подписанный chipsec не запускается), но остальные драйвера (в том числе и рассмотренный в примере) продолжают функционировать.
                                                                            0
                                                                            Она, как я понял, для защиты от патчинга, и по определению в ней должны работать все легально подписанные драйвера. Насколько я помню, там запускается гипервизор, а сама винда как виртуалка. А уж гипервизор делает дополнительные проверки ядра и системных процессов.

                                                                          Only users with full accounts can post comments. Log in, please.