GitHub - KelvinMsft/DeviceMon: VT-based PCI device monitor (SPI)

DeviceMon is a Windows Driver that intercepts the communication between your PCI devices and kernel driver, acting as software JTAG

DeviceMon will be an on-going development to support more PCI devices. Currently it supports monitoring SPI controller behavior. With SPI behavior monitoring, anyone who sends a cycle to the SPI controller will captured by DeviceMon. This means theoretically Flash ROM attacks could be captured by DeviceMon. By intercepting a MMIO translation path, the communication between driver and devices could be easily exposed. Also, as an example, support for 64bit BAR address - Intel ME controller and support for USB xHCI controller

typedef struct _PCI_MONITOR_CFG
{
  UINT8         BusNumber;		// Device Bus
  UINT8         DeviceNum;		// Device Number
  UINT8         FuncNum;		// Device Function
  
  UINT8		BarOffset[6];		// BAR offset in PCI Config , check your chipset datasheet
  					// By default is 6 32bit BAR, if your device is 64bit BAR maxium is 3
					// for 64bit, please adding BarAddressWidth
					// LOWER and UPPER offset have to be in order as IntelMeDeviceInfo
					
  UINT8	       BarCount;		// Number of offset need to me monitored, check your chipset datasheet
  ULONG64      BarAddress[6];		// Obtained BAR address, it will be filled out runtime
  MMIOCALLBACK Callback;		// MMIO handler
  ULONG        BarAddressWidth[6];   	// 0 by default, PCI_64BIT_DEVICE affect BarOffset parsing n, n+1 => 64bit 
  
  OFFSETMAKECALLBACK Callback2;		// callback that indicate offset is 64bit 
					// offset combination is compatible for those 64bit combined BAR,
					// and it should take device-dependent bitwise operation. 
					
}PCIMONITORCFG, *PPCIMONITORCFG;
 
PCIMONITORCFG SpiDeviceInfo = 
{
 SPI_INTERFACE_BUS_NUMBER,		
 SPI_INTERFACE_DEVICE_NUMBER,		
 SPI_INTERFACE_FUNC_NUMBER ,		
 {
   SPI_INTERFACE_SPIBAR_OFFSET,	
   0,0,0,0,0				
 },	
 1,					
 { 0 , 0 , 0 , 0 , 0 , 0 },		
 { 0 , 0 , 0 , 0 , 0 , 0 },		
 SpiHandleMmioAccessCallback,		
 { 0 , 0 , 0 , 0 , 0 , 0 },		
 nullptr,				
};



PCIMONITORCFG IntelMeDeviceInfo = 
{
 INTEL_ME_BUS_NUMBER,			
 INTEL_ME_DEVICE_NUMBER,		
 INTEL_ME_1_FUNC_NUMBER,		
 {					
   INTEL_ME_BAR_LOWER_OFFSET,		
   INTEL_ME_BAR_UPPER_OFFSET,		
   0,0,0,0,				
 },					
 1,					
 { 0 , 0 , 0 , 0 , 0 , 0 },
 { 0 , 0 , 0 , 0 , 0 , 0 },		
 IntelMeHandleMmioAccessCallback,	
 {					
   PCI_BAR_64BIT ,			
   0 , 0 , 0 , 0 , 0 ,			
 },					
 IntelMeHandleBarCallback,		
};					




PCIMONITORCFG IntelMe2DeviceInfo = 
{
 INTEL_ME_BUS_NUMBER,	
 INTEL_ME_DEVICE_NUMBER,
 INTEL_ME_2_FUNC_NUMBER ,
 {
   INTEL_ME_BAR_LOWER_OFFSET,
   INTEL_ME_BAR_UPPER_OFFSET,
   0,0,0,0,
 },
 1,		
 { 0 , 0 , 0 , 0 , 0 , 0 },
 { 0 , 0 , 0 , 0 , 0 , 0 },
 IntelMeHandleMmioAccessCallback,
 {
   PCI_BAR_64BIT ,
   0 , 0 , 0 , 0 , 0 ,
 },
 IntelMeHandleBarCallback,
};



PCIMONITORCFG IntelMe3DeviceInfo = 
{
 INTEL_ME_BUS_NUMBER,	
 INTEL_ME_DEVICE_NUMBER,
 INTEL_ME_3_FUNC_NUMBER ,
 {
   INTEL_ME_BAR_LOWER_OFFSET,
   INTEL_ME_BAR_UPPER_OFFSET,
   0,0,0,0,
 },
 1,		
 { 0 , 0 , 0 , 0 , 0 , 0 },
 { 0 , 0 , 0 , 0 , 0 , 0 },	
 IntelMeHandleMmioAccessCallback,
 {
   PCI_BAR_64BIT ,
   0 , 0 , 0 , 0 , 0 ,
 },
 IntelMeHandleBarCallback,
};




PCIMONITORCFG IntelUsb3DeviceInfo = 
{
 INTEL_USB3_BUS_NUMBER,
 INTEL_USB3_DEVICE_NUMBER,
 INTEL_USB3_FUNC_NUMBER ,
 {
   INTEL_USB3_BAR_LOWER_OFFSET,
   0,0,0,0,0,
 },
 1,
 { 0 , 0 , 0 , 0 , 0 , 0 },
 { 0 , 0 , 0 , 0 , 0 , 0 },		
 IntelUsb3HandleMmioAccessCallback,
 { 0 ,	0 , 0 , 0 , 0 , 0 },
 nullptr,
};

PCIMONITORCFG MarvellNicDeviceInfo = 
{
  MARVELL_NIC_BUS_NUMBER,	
  MARVELL_NIC_DEVICE_NUMBER,
  MARVELL_NIC_FUNC_NUMBER ,
  {
   MARVELL_NIC_BAR_LOWER_OFFSET,
   MARVELL_NIC_BAR_HIGH_OFFSET,
   MARVELL_NIC_BAR1_LOWER_OFFSET,
   MARVELL_NIC_BAR1_HIGHT_OFFSET,
   0,0,
  },
  2,
  { 0 , 0 , 0 , 0 , 0 , 0 },
  { 0 , 0 , 0 , 0 , 0 , 0 },
  IntelNicHandleMmioAccessCallback,
 {
   PCI_BAR_64BIT ,	
   PCI_BAR_64BIT ,
   0 , 0 , 0 , 0 ,
 },
 IntelNicHandleBarCallback,
};
   

//Put your device config here. Engine will be able to distract them automatically.
PCIMONITORCFG g_MonitorDeviceList[] =
{
  SpiDeviceInfo,
  IntelMeDeviceInfo,
  IntelMe2DeviceInfo,
  IntelMe3DeviceInfo,
  IntelUsb3DeviceInfo,
  MarvellNicDeviceInfo
};
 
typedef ULONG64 (*OFFSETMAKECALLBACK)(
		ULONG64 UpperBAR,
		ULONG64 LowerBAR
	);
typedef bool(*MMIOCALLBACK)(
		GpRegisters*  Context,
		ULONG_PTR InstPointer,
		ULONG_PTR MmioAddress,
		ULONG	  InstLen,
		ULONG	  Access
	);
 

Because huge differences between PCI devices, you have to check device config from your data-sheet from your hardware manufacture.

A demo has captured a malware that starting the attack and dumping the SPI Flash ROM. Also, as following figure shown, two binary compared there's no any effect on dumped SPI Flash when VMM in the middle.

Except for the malware behavior capturing, DeviceMon is also a good helper for analysis device driver protocol. :)

Request for more device monitoring is welcome. please feel free to contact via kelvin.chan@microsoft.com