線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2182
推到 Plurk!
推到 Facebook!

Getting the BIOS serial number

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-07-26 19:01:14 IP:61.221.xxx.xxx 未訂閱
Getting the BIOS serial number http://www.latiumsoftware.com/en/delphi/00050.php     
 For a simple copy-protection scheme we need to know whether the machine that is executing our application is the one where it was installed. We can save the machine data in the Windows Registry when the application is installed or executed for the first time, and then every time the application gets executed we compare the machine data with the one we saved to see if they are the same or not.    But, what machine data should we use and how do we get it? In a past issue we showed how to get the volume serial number of a logical disk drive, but normally this is not satisfying for a software developer since this number can be changed.    A better solution could be using the BIOS serial number. BIOS stands for Basic Input/Output System and basically is a chip on the motherboard of the PC that contains the initialization program of the PC (everything until the load of the boot sector of the hard disk or other boot device) and some basic device-access routines. Unfortunately, different BIOS manufacturers have placed the serial numbers and other BIOS information in different memory locations, so the code you can usually find in the net to get this information might work with some machines but not with others. However, most (if not all) BIOS manufacturers have placed the information somewhere in the last 8 Kb of the first Mb of memory, i.e. in the address space from $000FE000 to $000FFFFF. Assuming that "s" is a string variable, the following code would store these 8 Kb in it:      SetString(s, PChar(Ptr($FE000)), $2000);  // $2000 = 8196
We can take the last 64 Kb to be sure we are not missing anything:      SetString(s, PChar(Ptr($F0000)), $10000);  // $10000 = 65536
The problem is that it's ill-advised to store "large volumes" of data in the Windows Registry. It would be better if we could restrict to 256 bytes or less using some hashing/checksum technique. For example we can use the SHA1 unit (and optionally the Base64 unit) introduced in the Pascal Newsletter #17. The code could look like the following:    uses SHA1, Base64;    function GetHashedBiosInfo: string;
var
  SHA1Context: TSHA1Context;
  SHA1Digest: TSHA1Digest;
begin
  // Get the BIOS data
  SetString(Result, PChar(Ptr($F0000)), $10000);
  // Hash the string
  SHA1Init(SHA1Context);
  SHA1Update(SHA1Context, PChar(Result), Length(Result));
  SHA1Final(SHA1Context, SHA1Digest);
  SetString(Result, PChar(@SHA1Digest), sizeof(SHA1Digest));
  // Return the hash string encoded in printable characters
  Result := B64Encode(Result);
end;
This way we get a short string that we can save in the Windows Registry without any problems. You can take it as a sort of "BIOS serial number".    As an alternative to using SHA1 and Base64, you can use any checksum algorithm and binary-to-string conversion function of your liking. In the example below we use a simple algorithm that gets a 64-bit checksum and finally we convert it to a 16-chars string of hexadecimal digits:    function GetBiosCheckSum: string;
var
  s: int64;
  i: longword;
  p: PChar;
begin
  i := 0;
  s := 0;
  p := PChar($F0000);
  repeat
    inc(s, Int64(Ord(p^)) shl i);
    if i < 64 then inc(i) else i := 0;
    inc(p);
  until p > PChar($FFFFF);
  Result := IntToHex(s,16);
end;
Displaying the BIOS information    If we wanted to display the BIOS information we should parse the bytes to extract all null-terminated strings with ASCII printable characters at least 8-characters length, as it is done in the following function:    function GetBiosInfoAsText: string;
var
  p, q: pchar;
begin
  q := nil;
  p := PChar(Ptr($FE000));
  repeat
    if q <> nil then begin
      if not (p^ in [#10, #13, #32..#126, #169, #184]) then begin
        if (p^ = #0) and (p - q >= 8) then begin
          Result := Result   TrimRight(String(q))   #13#10;
        end;
        q := nil;
      end;
    end else
      if p^ in [#33..#126, #169, #184] then
        q := p;
    inc(p);
  until p > PChar(Ptr($FFFFF));
  Result := TrimRight(Result);
end;
Then we can use the return value for example to display it in a memo:    procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Text := GetBiosInfoAsText;
end;
WARNING: The code presented in this article won't work on Windows NT/2000, although some information about the BIOS and the system hardware can be found in the Windows Registry under the key HKEY_LOCAL_MACHINE\Hardware\Description\System, but not enough to identify a machine as far as I know...
系統時間:2017-12-15 16:23:50
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!