Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Hardware ID erstellen (https://www.delphipraxis.net/201431-hardware-id-erstellen.html)

DieDolly 22. Jul 2019 10:56


Hardware ID erstellen
 
Bei The Road To Delphi habe ich was gefunden
https://theroadtodelphi.com/2010/12/...i-and-the-wmi/

Gibt es vielleicht eine neuere weniger aggressive Möglichkeit eine Hardware ID zu erzeugen?
Kann man diese Unit überhaupt noch verwenden? Ich bekomme immer einen leeren String zurück,.

Delphi-Quellcode:
unit HardwareIDGenerator;

interface

uses
 System.Classes, System.SysUtils, Winapi.ActiveX, System.Win.ComObj, System.Variants;

type
 TMotherBoardInfo = (Mb_SerialNumber, Mb_Manufacturer, Mb_Product, Mb_Model);
 TMotherBoardInfoSet = set of TMotherBoardInfo;
 TProcessorInfo = (Pr_Description, Pr_Manufacturer, Pr_Name, Pr_ProcessorId, Pr_UniqueId);
 TProcessorInfoSet = set of TProcessorInfo;
 TBIOSInfo = (Bs_BIOSVersion, Bs_BuildNumber, Bs_Description, Bs_Manufacturer, Bs_Name, Bs_SerialNumber, Bs_Version);
 TBIOSInfoSet = set of TBIOSInfo;
 TOSInfo = (Os_BuildNumber, Os_BuildType, Os_Manufacturer, Os_Name, Os_SerialNumber, Os_Version);
 TOSInfoSet = set of TOSInfo;

const // properties names to get the data
 MotherBoardInfoArr: array [TMotherBoardInfo] of AnsiString = ('SerialNumber', 'Manufacturer', 'Product', 'Model');

 OsInfoArr: array [TOSInfo] of AnsiString = ('BuildNumber', 'BuildType', 'Manufacturer', 'Name', 'SerialNumber', 'Version');

 BiosInfoArr: array [TBIOSInfo] of AnsiString = ('BIOSVersion', 'BuildNumber', 'Description', 'Manufacturer', 'Name', 'SerialNumber', 'Version');

 ProcessorInfoArr: array [TProcessorInfo] of AnsiString = ('Description', 'Manufacturer', 'Name', 'ProcessorId', 'UniqueId');

type
 THardwareId = class
 private
  FOSInfo: TOSInfoSet;
  FBIOSInfo: TBIOSInfoSet;
  FProcessorInfo: TProcessorInfoSet;
  FMotherBoardInfo: TMotherBoardInfoSet;
  FBuffer: AnsiString;
  function GetHardwareIdHex: AnsiString;
 public
  // Set the properties to be used in the generation of the hardware id
  property MotherBoardInfo: TMotherBoardInfoSet read FMotherBoardInfo write FMotherBoardInfo;
  property ProcessorInfo: TProcessorInfoSet read FProcessorInfo write FProcessorInfo;
  property BIOSInfo: TBIOSInfoSet read FBIOSInfo write FBIOSInfo;
  property OSInfo: TOSInfoSet read FOSInfo write FOSInfo;
  property Buffer: AnsiString read FBuffer; // return the content of the data collected in the system
  property HardwareIdHex: AnsiString read GetHardwareIdHex; // get a hexadecimal represntation of the data collected
  procedure GenerateHardwareId; // calculate the hardware id
  constructor Create(Generate: Boolean = True); overload;
  Destructor Destroy; override;
 end;

implementation

function VarArrayToStr(const vArray: variant): AnsiString;
function _VarToStr(const V: variant): AnsiString;
var
 Vt: integer;
begin
 Vt := VarType(V);
 case Vt of
  varSmallint, varInteger:
   Result := AnsiString(IntToStr(integer(V)));
  varSingle, varDouble, varCurrency:
   Result := AnsiString(FloatToStr(Double(V)));
  varDate:
   Result := AnsiString(VarToStr(V));
  varOleStr:
   Result := AnsiString(WideString(V));
  varBoolean:
   Result := AnsiString(VarToStr(V));
  varVariant:
   Result := AnsiString(VarToStr(variant(V)));
  varByte:
   Result := AnsiChar(byte(V));
  varString:
   Result := AnsiString(V);
  varArray:
   Result := VarArrayToStr(variant(V));
 end;
end;

var
 i: integer;
begin
 Result := '[';
 if (VarType(vArray) and varArray) = 0 then
  Result := _VarToStr(vArray)
 else
  for i := VarArrayLowBound(vArray, 1) to VarArrayHighBound(vArray, 1) do
   if i = VarArrayLowBound(vArray, 1) then
    Result := Result + _VarToStr(vArray[i])
   else
    Result := Result + '|' + _VarToStr(vArray[i]);

 Result := Result + ']';
end;

function VarStrNull(const V: OleVariant): AnsiString; // avoid problems with null strings
begin
 Result := '';
 if not VarIsNull(V) then
  begin
   if VarIsArray(V) then
    Result := VarArrayToStr(V)
   else
    Result := AnsiString(VarToStr(V));
  end;
end;

{THardwareId}

constructor THardwareId.Create(Generate: Boolean = True);
begin
 inherited Create;
 CoInitialize(nil);
 FBuffer := '';
 // Set the propeties to be used in the hardware id generation
 FMotherBoardInfo := [Mb_SerialNumber, Mb_Manufacturer, Mb_Product, Mb_Model];
 FOSInfo := [Os_BuildNumber, Os_BuildType, Os_Manufacturer, Os_Name, Os_SerialNumber, Os_Version];
 FBIOSInfo := [Bs_BIOSVersion, Bs_BuildNumber, Bs_Description, Bs_Manufacturer, Bs_Name, Bs_SerialNumber, Bs_Version];
 FProcessorInfo := []; // including the processor info is expensive [Pr_Description,Pr_Manufacturer,Pr_Name,Pr_ProcessorId,Pr_UniqueId];
 if Generate then
  GenerateHardwareId;
end;

destructor THardwareId.Destroy;
begin
 CoUninitialize;
 inherited;
end;

// Main function which collect the system data.
procedure THardwareId.GenerateHardwareId;

var
 objSWbemLocator: OleVariant;
 objWMIService: OleVariant;
 objWbemObjectSet: OleVariant;
 oWmiObject: OleVariant;
 oEnum: IEnumvariant;
 iValue: LongWord;
 SDummy: AnsiString;
 Mb: TMotherBoardInfo;
 Os: TOSInfo;
 Bs: TBIOSInfo;
 Pr: TProcessorInfo;
begin;
 objSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
 objWMIService := objSWbemLocator.ConnectServer('localhost', 'root\cimv2', '', '');

 if FMotherBoardInfo <> [] then // MotherBoard info
  begin
   objWbemObjectSet := objWMIService.ExecQuery('SELECT * FROM Win32_BaseBoard', 'WQL', 0);
   oEnum := IUnknown(objWbemObjectSet._NewEnum) as IEnumvariant;
   while oEnum.Next(1, oWmiObject, iValue) = 0 do
    begin
     for Mb := Low(TMotherBoardInfo) to High(TMotherBoardInfo) do
      if Mb in FMotherBoardInfo then
       begin
        SDummy := VarStrNull(oWmiObject.Properties_.Item(MotherBoardInfoArr[Mb]).Value);
        FBuffer := FBuffer + SDummy;
       end;
     oWmiObject := Unassigned;
    end;
  end;

 if FOSInfo <> [] then // Windows info
  begin
   objWbemObjectSet := objWMIService.ExecQuery('SELECT * FROM Win32_OperatingSystem', 'WQL', 0);
   oEnum := IUnknown(objWbemObjectSet._NewEnum) as IEnumvariant;
   while oEnum.Next(1, oWmiObject, iValue) = 0 do
    begin
     for Os := Low(TOSInfo) to High(TOSInfo) do
      if Os in FOSInfo then
       begin
        SDummy := VarStrNull(oWmiObject.Properties_.Item(OsInfoArr[Os]).Value);
        FBuffer := FBuffer + SDummy;
       end;
     oWmiObject := Unassigned;
    end;
  end;

 if FBIOSInfo <> [] then // BIOS info
  begin
   objWbemObjectSet := objWMIService.ExecQuery('SELECT * FROM Win32_BIOS', 'WQL', 0);
   oEnum := IUnknown(objWbemObjectSet._NewEnum) as IEnumvariant;
   while oEnum.Next(1, oWmiObject, iValue) = 0 do
    begin
     for Bs := Low(TBIOSInfo) to High(TBIOSInfo) do
      if Bs in FBIOSInfo then
       begin
        SDummy := VarStrNull(oWmiObject.Properties_.Item(BiosInfoArr[Bs]).Value);
        FBuffer := FBuffer + SDummy;
       end;
     oWmiObject := Unassigned;
    end;
  end;

 if FProcessorInfo <> [] then // CPU info
  begin
   objWbemObjectSet := objWMIService.ExecQuery('SELECT * FROM Win32_Processor', 'WQL', 0);
   oEnum := IUnknown(objWbemObjectSet._NewEnum) as IEnumvariant;
   while oEnum.Next(1, oWmiObject, iValue) = 0 do
    begin
     for Pr := Low(TProcessorInfo) to High(TProcessorInfo) do
      if Pr in FProcessorInfo then
       begin
        SDummy := VarStrNull(oWmiObject.Properties_.Item(ProcessorInfoArr[Pr]).Value);
        FBuffer := FBuffer + SDummy;
       end;
     oWmiObject := Unassigned;
    end;
  end;

end;

function THardwareId.GetHardwareIdHex: AnsiString;
begin
 SetLength(Result, Length(FBuffer) * 2);
 BinToHex(PAnsiChar(FBuffer), PAnsiChar(Result), Length(FBuffer));
end;

end.

freimatz 22. Jul 2019 12:03

AW: Hardware ID erstellen
 
Nun ja, prinzipiell ist eine Hardware-ID immer problematisch. (Habe 20-30 Jahre Erfahrung damit)
Was ist wenn Komponenten ausgetauscht werden? Was ist mit virtuellen Maschinen?

MyRealName 22. Jul 2019 12:21

AW: Hardware ID erstellen
 
Ich habe auch schon den Fall gehabt, dass Nutzer mit unterschiedlichen Zugriffsrechten scheinbar nicht immer Zugriff auf die WMI Funktionen haben und dadurch nichts generiert wurde. Es gibt auch eine HardwareId.dll, die allerdings in Versuchen am gleichen Rechner nach jedem neustart zwischen verschiedenen Ids rumgesprungen ist. Also solange der Rechner nicht neu getsartet wrde, blieb die ID dieselbe, aber nach einem Neustart war es ein Lottospiel.

DieDolly 22. Jul 2019 12:24

AW: Hardware ID erstellen
 
Das Anwendungsgebiet dieses kleinen Programms ist in VMs eher unmöglich, da es von einer anderen 3D-Software abhängig ist, die in einer VM mit ziemlicher Sicherheit nicht korrekt lauffähig sein wird.

Ich erzeuge die ID jetzt so, ob das lasch genug ist?
Delphi-Quellcode:
HWID := THardwareId.Create(False);
 try
  HWID.OSInfo := []; // Keinerlei Betriebssystem-Informationen
  HWID.BIOSInfo := []; // Keinerlei BIOS-Informationen
  HWID.GenerateHardwareId;

  ID := HWID.HardwareIdHex);
 finally
  HWID.Free;
 end;
Mainboard oder Prozessor müssten ausgetauscht werden, damit die ID ungültig wird. Das ist eher seltener der Fall denke ich.

Zitat:

Ich habe auch schon den Fall gehabt, dass Nutzer mit unterschiedlichen Zugriffsrechten scheinbar nicht immer Zugriff auf die WMI Funktionen haben und dadurch nichts generiert wurde.
Könnte das mit Adminrechten zusammenhängen?
Wie könnte man sonst an eine relativ eindeutige ID kommen? Ist die einer CPU eindeutig?

MyRealName 22. Jul 2019 13:29

AW: Hardware ID erstellen
 
Das problem ist, dass eigentlich NICHTS eindeutig ist. Es gibt CPUs, welche keine CPUID zurückgeben, es gibt mainboards, welche keine Seriennummer haben, alles nur so wie 00000-000-0000-00000
Von daher.. :gruebel:

DieDolly 22. Jul 2019 14:05

AW: Hardware ID erstellen
 
Wie siehts denn mit der SerialNumber des Betriebssystems aus zusammen mit anderen Werten?

MyRealName 22. Jul 2019 14:09

AW: Hardware ID erstellen
 
Ich glaube bei der Seriennummer des Betriebssystems zum Bsp. gibt Windows für diverse Hersteller wie Dell Sammelnummern raus und mehrere PC (also tausende) nutzen die gleiche Seriennummer. ich glaube, die kommt sogar direkt im BIOS, mein Windows Laptop hat immer sofort eine Seriennummer, wenn ich ihn installiere. selbst, als ich die festplatte getauscht habe und garnicht die Windows-version genommen habe, die original drauf war.

DieDolly 22. Jul 2019 14:14

AW: Hardware ID erstellen
 
Also es muss nicht weltweit absolut eindeutig sein. Es sollte nur relativ eindeutig sein.

Würde da OS Seriennummer, Bios-Versions-String und Name des PCs sowie Nutzers nicht reichen?

Oder reicht ganz simple die Seriennummer aller Laufwerke?

HolgerX 22. Jul 2019 14:20

AW: Hardware ID erstellen
 
Hmm..

Welche HardwareID soll es den sein?

Der Client selber?
- Wenn als FatClient läuft
- Wenn auf Theminal Server aufgeschaltet (Wechseln eventuell bei jedem Login)
- Wenn auf VirtualDesktop aufgeschaltet
- Wenn als Host für eine VM
Vom Therminalservern?
Von der VM welche auf dem Client läuft?

Durch Virtualisierung und TherminSessions sind alle Informationen wie Prozessor, MAC, Bios und Co einfach nicht 'Eindeutig'...

(Aber ich glaube einen solchen Thread um eine System ID hatten wir schon öffters.. ;) )

DieDolly 22. Jul 2019 14:28

AW: Hardware ID erstellen
 
Mein Programm soll ganz einfach nur eine ID erzeugen, die für dieses System mehr oder weniger eindeutig ist. Ob es jetzt unter 1 Millionen Systemen eins gibt mit derselben ID ist mir egal.

Und da ist die Frage, ob OS Seriennummer, PC-Name, Nutzer-name, BIOS-Versions-String und Festplatten-IDs nicht schon ausreichen.

HolgerX 22. Jul 2019 14:38

AW: Hardware ID erstellen
 
Hmm..

Zitat:

Zitat von DieDolly (Beitrag 1437298)
Mein Programm soll ganz einfach nur eine ID erzeugen, die für dieses System mehr oder weniger eindeutig ist. Ob es jetzt unter 1 Millionen Systemen eins gibt mit derselben ID ist mir egal.

Und da ist die Frage, ob OS Seriennummer, PC-Name, Nutzer-name, BIOS-Versions-String und Festplatten-IDs nicht schon ausreichen.

Und da liegt der Hund begraben:

OS Seriennummer
- Dürfte auf Terminserver mit Datacenter-Lizenz überall gleich sein...
BIOS-Versions-String
- wohl auch
Festplatten-IDs
- Die ID der virtuellen oder realen Festplatte, wenn überhaupt vorhanden?
Nutzer-name
- Dieser ist Schall und Rauch und wird eventuell an vielen PCs gleichzeitig verwendet.

PC-Name
- Diesen gibt es zu mindestens je Kunde nur einmal in seinem Netz.
- Allerdings könnte es dann mit Virtual Desktops Probleme geben, da dort der Name immer beim rollout wechselt, bzw. alle Clients wechselnd auch immer wieder andere VD bekommen können..

Es ist somit nicht einfach ein System 'Eindeutig' zu identifizieren.. ;)

Ein lokal benutzter FatClient, da kannst Du diese Hardsware-IDs (Serial HD/Bios/CPU..) 'grob' verwenden, aber wenn es virtual wird... dann ist es damit fast schon vorbei.

DieDolly 22. Jul 2019 14:40

AW: Hardware ID erstellen
 
Ich habe keine Ahnung was ein Terminserver sein soll aber ich kann dir sagen, dass mein Programm nur auf ganz normalen PCs läuft und niemals auf irgendwelchen Enterprise-Datacenter-Simsallabim-PCs.

Sherlock 22. Jul 2019 14:42

AW: Hardware ID erstellen
 
Was möchtest Du mit der HardwareID erreichen? Registrierte Anwender sollen Deine Software einfacher erneut installieren können? Mit einem ausgewechselten Stück Hardware (SSD?) geht das in der Regel schon schief. Den PC des Anwenders als Dongle zu nutzen war mal eine populäre Sache, weswegen man ja auch bei Intel sogar Seriennummern in die CPU einbaute. Allerdings ist das 10 Jahre her, und seither haben sich viel zu viele gemeldet, die das nicht so toll fanden, und auch gute Gründe dafür gaben. Und austricksen lässt sich das mit VMs ohnehin allzu leicht.

Da Du ja ohnehin eine DB und Onlineverbindung dazu herstellen mußt, ist es viel einfacher, User und Registrierungsschlüssel abzufragen (so wie Embarcadero...nur eben besser, bitte), als irgendwelche HardwareIDs, die durch semiambitionierte Anwender geändert werden können, schlicht durch Austausch von ein bis zwei Komponenten.

Wie bei jedem Kopierschutz möchte ich anregen, sehr genau darüber nachzudenken, ob Zeit und Aufwand, die in den Kopierschutz gesteckt werden, nicht besser im eigentlichen Programm aufgehoben sind. Höhere Qualität erzeugt zufriedenere Kunden, die wiederum die beste Werbung für ein Produkt sind, die man für Geld nicht kaufen kann.

Sherlock

DieDolly 22. Jul 2019 14:44

AW: Hardware ID erstellen
 
Zitat:

Da Du ja ohnehin eine DB und Onlineverbindung dazu herstellen mußt, ist es viel einfacher, User und Registrierungsschlüssel abzufragen
Das habe ich alles schon und eben Probleme mit Nutzern die ihre Daten weitergeben.

HolgerX 22. Jul 2019 14:46

AW: Hardware ID erstellen
 
Hmm..

Zitat:

Zitat von DieDolly (Beitrag 1437303)
Ich habe keine Ahnung was ein Terminserver sein soll aber ich kann dir sagen, dass mein Programm nur auf ganz normalen PCs läuft und niemals auf irgendwelchen Enterprise-Datacenter-Simsallabim-PCs.

Grob gesagt:
Einen Terminserver hast Du schon dann, wenn Du dich per RDP auf einen anderen PC aufschaltets. Dann ist dieser automatisch der Terminalserver....

Im gewerblichen Bereich werden dort z.B. Citrix-Terminservewr verwendet, welche eine virtuelle Umgebung für viele Clients gleichzeitig bereitstellen.

DieDolly 22. Jul 2019 14:47

AW: Hardware ID erstellen
 
Solch einen Fall wird es bei mir definitiv niemals geben.

johndoe049 22. Jul 2019 23:36

AW: Hardware ID erstellen
 
Hallo,

ich "hacke" mich mal frech hier rein :)

In meiner Software verwende ich auch eine Hardware ID.

Nicht wegen Kopierschutz, sondern wegen Zuordnung von Systemkonfiguration, Benutzererkennung, etc.

Früher, so Windows XP, wurde mal gesagt, dass Windows eine Installations ID pro Installation erzeugt. Wo steht diese in der Registry bei Windows 10, oder gibt es das nicht mehr? Bei Benutzern legt Windows angeblich nicht nur den Namen, sondern auch eine eindeutige Sicherheitskennung an. Gibt es das auch noch bei Windows 10?

Mir geht es nur darum, dass ich einen PC möglichst genau über interne Daten erkennen kann.

Danke.
Johndoe049

DieDolly 23. Jul 2019 00:14

AW: Hardware ID erstellen
 
Meinst du die MachineGUID?
https://www.nextofwindows.com/the-be...indows-machine

Leider steht da nicht seit wann es das schon gibt. Das Bild sieht aber nach Windows 7 aus. Das sollte lange genug sein.
Diese MachineGUID könnte man zusätzlich nehmen. Aber nur die würde ich nicht. Die kann man doch ändern?

So wie da im dem Artikel steht würde ich aber auch nicht die Festplatten-Seriennummern nehmen. Das dauert sehr lange die Nummern per WMI zu sammeln. Fast 1 Sekunde bei mir trotz SSD und ordentlichem Prozessor.

dummzeuch 23. Jul 2019 08:53

AW: Hardware ID erstellen
 
Vielleicht reicht es ja schon, in der Registry einen bestimmten Key anzulegen (pro User) und dort eine frisch erzeugte GUID reinzuschreiben? Die ist dann auch eindeutig pro Windows-Installation und User. (Es sei denn, jemand cloned die Platte.)

Ob das ausreicht, kommt auf den Anwendungsfall an. Als Kopierschutz reicht es nicht.

kompi 25. Jul 2019 15:46

AW: Hardware ID erstellen
 
In der Winapi.Windows gibt es die Methode "GetVolumeinformation". Damit lässt sich ohne großen Aufwand, und zudem sehr schnell, auch die Seriennummern der Laufwerke bestimmen. Man benötigt dafür keine WMI Abfrage.

Gruß Kompi


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz