Page 1 of 1

Enumerate hardware devices (Windows)

Posted: Mon Jun 26, 2006 3:10 am
by mskuma
Code updated For 5.20+

I was interested to see if it's possible to do a 'machine fingerprint' (i.e. detect a machine's hardware add/remove changes) via listing up hardware devices periodically, so I came up with this.

Code: Select all

; How to enumerate hardware devices by using SetupDi calls
; mskuma 26 June 2006
; adapted from http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q259695
; (Windows only)

#DIGCF_PRESENT = $00000002
#DIGCF_ALLCLASSES = $00000004

#SPDRP_DEVICEDESC = $00000000

Structure SP_DEVINFO_DATA
  cbSize.l
  ClassGuid.GUID
  DevInst.l;    // DEVINST handle
  Reserved.l;
EndStructure
   
Procedure.s FingerprintMachineByEnumHardwareDevices()

  hDevInfo.l = 0
  DeviceInfoData.SP_DEVINFO_DATA
  i.l = 0
  devicesList.s = ""
  
  ; Create a HDEVINFO with all present devices
  
  hDevInfo = SetupDiGetClassDevs_(#Null,0, 0, #DIGCF_PRESENT | #DIGCF_ALLCLASSES)
  
  If hDevInfo = #INVALID_HANDLE_VALUE
    ProcedureReturn "0"
  EndIf
  
  ; Enumerate through all devices in Set
  
  DeviceInfoData\cbSize = SizeOf(SP_DEVINFO_DATA)
    
  While SetupDiEnumDeviceInfo_(hDevInfo, i, @DeviceInfoData) 
         
     DataT.l
     *buffer = #Null
     buffersize.l = 0
     
     ; Call function with null to begin with, 
     ; then use the returned buffer size (doubled)
     ; to allocate the buffer. Keep calling until
     ; success Or an unknown failure.
     ;
     ;  Double the returned buffersize to correct
     ;  For underlying legacy CM functions that 
     ;  Return an incorrect buffersize value on 
     ;  DBCS/MBCS systems.
     
     While Not SetupDiGetDeviceRegistryProperty_(hDevInfo,@DeviceInfoData,#SPDRP_DEVICEDESC,@DataT,*buffer,buffersize,@buffersize)
     
         If (GetLastError_() = #ERROR_INSUFFICIENT_BUFFER)
             ; Allocate the buffer size, using twice the size to avoid problems on W2k MBCS systems per KB 888609
             *buffer = AllocateMemory(buffersize*2)
         Else
             ; Insert error handling here
             Break
         EndIf
     
     Wend
     
     Debug "Device: " + PeekS(*buffer)  ; just for checking
     
     devicesList + PeekS(*buffer) ; build a string for purposes of doing a hash later
     
     If (*buffer)
       FreeMemory(*buffer)
     EndIf
     
     i+1  ; increment to next device
     
  Wend
  
  ; finish up
    
  If ( GetLastError_() <> #NO_ERROR And GetLastError_() <> #ERROR_NO_MORE_ITEMS )
     ; Insert error handling here
     ProcedureReturn "0"
  EndIf
  
  ; Cleanup
  SetupDiDestroyDeviceInfoList_(hDevInfo)
  
  ProcedureReturn MD5Fingerprint(@devicesList,Len(devicesList))
 
 EndProcedure
 
 ; testing
 
 Debug "Fingerprint = " + FingerprintMachineByEnumHardwareDevices()
Improvement suggestions welcome.

Re: Enumerate hardware devices (Windows)

Posted: Mon Jun 26, 2006 7:00 am
by NoahPhense
Very nice.. this will come in handy in my machine dependant algorythm.

- np

Posted: Mon Jun 26, 2006 2:21 pm
by Jan Vooijs
Nice,

Question does the USB not destroy your fingerprint? I mean if a USB external drive is (or not) connected? Same goes for the 1394 (FireWire)?

When i put (any one of the 8 devices in my USB ports [or not] I get another fingerprint... :oops: 8) :lol:

Even 'filtering' of USB devices like:

Code: Select all

If (FindString( PeekS(*buffer), "USB", 1) > 0)
     		Debug "--> Device: " + PeekS(*buffer) + " NOT inserted"  ; just for checking
     		devicesList + PeekS(*buffer) ; build a string for purposes of doing a hash later
     	EndIf
gives not the same finger print (there is an "generic device" also added for every USB stick inserted.

Better would be to find out exactly what kind of processor (the type AMD/INTEL which freq it is running on) and or which kind of memory (size DDR or DDR2 or dual channel).

But overal a nice (elegant) trick!!

Jan V.

Posted: Mon Jun 26, 2006 11:07 pm
by mskuma
Thanks for the comments.

Jan, yes adding/removing a USB device will change the fingerprint - which might be handy if you're on the lookout for an authorised USB device being plugged into a machine (potential IT security issue).

About processor - I agree. I think Droopy's lib will tell you the frequency, and if you use WMI to id the CPU (or use CPUID), both of which have been discussed on the forum before. I don't know how to detect memory type like Sandra does it - would be nice to investigate how do do that (might be another WMI call). Some memory chips even have a serial number, so that would be nice to get.