Windows: atteindre le matériel

J'ai toujours été intéressé par la programmation de bas niveau - pour communiquer directement avec l'équipement, jongler avec les registres, pour comprendre en détail comment ce qui fonctionne ... Hélas, les systèmes d'exploitation modernes isolent le plus possible le matériel de l'utilisateur, et il est tout simplement impossible d'écrire quelque chose dans la mémoire physique ou les registres de l'appareil. Plus précisément, je le pensais, mais en fait, il s'est avéré que presque tous les fabricants de matériel le font!

Quel est le point, capitaine?

Dans l'architecture x86, il existe un concept de «anneaux» - modes de fonctionnement du processeur. Plus le numéro du mode courant est bas, plus le code exécutable a de possibilités. La "sonnerie" la plus restreinte est "Ring 3", la plus privilégiée est "Ring -2" (mode SMM). Historiquement, tous les programmes utilisateur s'exécutent en mode Ring 3 et le noyau du système d'exploitation s'exécute en Ring 0:

Modes de fonctionnement du processeur x86
Modes de fonctionnement du processeur x86

Dans "Ring 3", les programmes ne sont pas autorisés à effectuer des actions potentiellement dangereuses telles que l'accès aux ports d'E / S et à la mémoire physique. Selon la logique des développeurs, un tel accès de bas niveau n'est pas nécessaire pour les programmes ordinaires. Seul le système d'exploitation et ses composants (services et pilotes) ont accès à ces fonctionnalités. Et tout irait bien, mais une fois que je suis tombé sur le programme RW Everything:

RW Tout lit et Ă©crit vraiment presque tout
RW Tout lit et Ă©crit vraiment presque tout

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

Nous regardons le dernier pilote installé via 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)

– «- », – . - :

Les résultats d'une brève analyse de quelques dizaines de conducteurs.  Il peut y avoir des erreurs!
. !

:

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

(, "" ), :

Et un autre programme utile pour explorer le système, 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
      # (   )

:

Lisez facilement et naturellement la mémoire physique en quelques commandes

PCI Express Config Space

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

Lire et Ă©crire l'espace de configuration PCI
PCI Config Space

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

Espace d'adressage d'un ordinateur x86 moderne, 0 Ă  4 Go
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

:

C'est ainsi que nous avons compté le BIOS en 10 lignes
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 , . - :

Ayant un peu souffert, on obtient une réponse du SSD à la commande d'identification
, 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 

, :

En fait, vous pouvez simplement regarder les informations de signature dans les propriétés .. Et j'ai étudié dans HEX
, .. HEX

, , , :

  • -

- SignTool , GitHub. , GitHub TrustAsia, .

- , ( ):

En effet, l'alphabet chinois
,

, AsrDrv101, !

Et voici notre chauffeur a commencé

, . . , TODO.

?

Comme vous pouvez le voir, disposant des droits d'administrateur, vous pouvez presque tout faire avec votre ordinateur. Soyez prudent - l'installation des utilitaires du fabricant de votre matériel peut entraîner un trou dans le système. Eh bien, ceux qui souhaitent expérimenter avec leur PC - bienvenue au bas niveau! J'ai posté le travail sur GitHub . Attention, une utilisation irréfléchie est lourde de BSOD.




All Articles