Windows: chegando ao hardware

Sempre me interessei por programação de baixo nível - comunicar-me diretamente com o equipamento, fazer malabarismos com registros, entender em detalhes como o que funciona ... Infelizmente, os sistemas operacionais modernos isolam o hardware do usuário o máximo possível e é simplesmente impossível escrever algo na memória física ou nos registros do dispositivo. Mais precisamente, pensei que sim, mas na verdade descobri que quase todos os fabricantes de hardware fazem isso!

Qual é o ponto, capitão?

Na arquitetura x86, há um conceito de "anéis" - modos de operação do processador. Quanto menor o número do modo atual, mais possibilidades estarão disponíveis para o código executável. O "ring" mais restrito é "Ring 3", o mais privilegiado é "Ring -2" (modo SMM). Historicamente, todos os programas do usuário são executados no modo Anel 3, e o kernel do sistema operacional é executado no Anel 0:

Modos operacionais para processador x86
Modos operacionais para processador x86

«Ring 3» , I/O . , . ( ). , RW Everything:

RW Everything realmente lê e escreve quase tudo
RW Everything

, «Ring 3» - , I/O , PCI ( ). , , . , RW Everything -:

Vemos o último driver instalado através do 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)

– «- », – . - :

Os resultados de uma breve análise de algumas dezenas de motoristas.  Pode haver erros!
. !

:

  • 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)

(, "" ), :

E outro programa útil para rastrear o sistema, 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
      # (   )

:

Ler a memória física de forma fácil e natural em alguns comandos

PCI Express Config Space

PCIE Config Space. - PCI I/O 0xCF8 / 0xCFC. AsrDrv101:

Ler e escrever o espaço de configuração PCI
PCI Config Space

0x100 , PCI Express Config Space 0x1000 ! PCI Extended Config Space, - , BIOS:

Espaço de endereço de um computador x86 moderno, 0-4 GB
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

:

É assim que contamos o BIOS em 10 linhas
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 , . - :

Tendo sofrido um pouco, obtemos uma resposta do SSD ao comando de identificação
, 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 

, :

Como se viu, você pode apenas olhar as informações de assinatura nas propriedades. E eu estudei em HEX
, .. HEX

, , , :

  • -

- SignTool , GitHub. , GitHub TrustAsia, .

- , ( ):

Na verdade, o alfabeto chinês
,

, AsrDrv101, !

E aqui está o nosso driver iniciado

, . . , TODO.

?

Como você pode ver, tendo direitos de administrador, você pode fazer quase tudo com o seu computador. Tenha cuidado - a instalação de utilitários do fabricante do hardware pode resultar em uma falha no sistema. Bem, aqueles que querem experimentar com seu PC - bem-vindos ao nível baixo! Publiquei o trabalho no GitHub . Cuidado, o uso impensado é repleto de BSODs.




All Articles