Enumerate hardware devices (Windows)

Share your advanced PureBasic knowledge/code with the community.
mskuma
Enthusiast
Enthusiast
Posts: 573
Joined: Sat Dec 03, 2005 1:31 am
Location: Australia

Enumerate hardware devices (Windows)

Post 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.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Re: Enumerate hardware devices (Windows)

Post by NoahPhense »

Very nice.. this will come in handy in my machine dependant algorythm.

- np
Jan Vooijs
Enthusiast
Enthusiast
Posts: 196
Joined: Tue Sep 30, 2003 4:32 pm
Location: The Netherlands

Post 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.
Life goes to Fast, Enjoy!!

PB 4 is to good to be true, wake up man it is NOT a dream THIS is a reality!!!

AMD Athlon on 1.75G, 1Gb ram, 160Gb HD, NVidia FX5200, NEC ND-3500AG DVD+RW and CD+RW, in a Qbic EO3702A and Win XP Pro SP2 (registered)
mskuma
Enthusiast
Enthusiast
Posts: 573
Joined: Sat Dec 03, 2005 1:31 am
Location: Australia

Post 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.
Post Reply