首页  编辑  

获取BIOS信息的一个单元

Tags: /超级猛料/Hardware.硬件相关/其它硬件/   Date Created:

(*******************************************************************************

*                                                                              *

* BIOS Help - read ROM BIOS on Windows 95/98/SE/ME/NT/2K/XP                    *

*                                                                              *

* Copyright (C) 2001, Nico Bendlin (nico@bendlin.de)                           *

*                                                                              *

* Compiler: Delphi 4.03/5.01/6.00                                              *

* Version: 1.03, 2001-09-02                                                    *

*                                                                              *

*******************************************************************************)

{ postum scriptum: sorry for the bad english, i wrote it in a hurry }

unit BiosHelp;

{$ALIGN ON}

{$MINENUMSIZE 4}

interface

uses

 Windows;

type

 PRomBiosDump = ^TRomBiosDump;

 TRomBiosDump = array [$000F0000..$000FFFFF] of Byte;

type

 TReadRomBiosMethod = (

   rrbmAutomatic, { Autodetect OS type and use proper method }

   rrbmGeneric,   { Use 16-bit COM program to dump the BIOS  }

   rrbmMemory,    { Read from memory (Win9x)                 }

   rrbmPhysical   { Read from physical memory object (WinNT) }

 );

function ReadRomBios(var Dump: TRomBiosDump; Method: TReadRomBiosMethod;

 Timeout: DWORD = INFINITE): Boolean;

function GetRomBiosBuffer(const Dump: TRomBiosDump; Address: Pointer;

 var Buffer; BufferSize: Cardinal): Cardinal;

function GetRomBiosString(const Dump: TRomBiosDump; Address: Pointer): string;

function GetRomBiosLongLong(const Dump: TRomBiosDump; Address: Pointer): LONGLONG;

function GetRomBiosDWord(const Dump: TRomBiosDump; Address: Pointer): DWORD;

function GetRomBiosWord(const Dump: TRomBiosDump; Address: Pointer): Word;

function GetRomBiosByte(const Dump: TRomBiosDump; Address: Pointer): Byte;

implementation

{###############################################################################

#                                                                              #

#                             GENERIC METHOD                                   #

#                                                                              #

# Create an temporary folder, save an 16bit COM program (RomDump.com) into it, #

# execute program redirected to an file (Rom.dmp, RomDump.com simply dumps the #

# memory range F000:0000-F000:FFFF to STDOUT), read dump file into the buffer, #

# and finally cleanup all temporary files and directories.                     #

#                                                                              #

# (the function RomDumpCode is x86 specific, which i wrote to generate 16-bit  #

#  code with the help of the 23-bit Delphi compiler, never try to execute the  #

#  pseudo-code in your program! it will not work in 32-bit protected mode)     #

#                                                                              #

###############################################################################}

{ *INTERNAL* - Pseudo 16-bit code }

type

 PRomDumpCodeInfo = ^TRomDumpCodeInfo;

 TRomDumpCodeInfo = (rdciStart, rdciEnd, rdciSize);

function _RomDumpCode(Info: TRomDumpCodeInfo): Pointer;

var

 CodeStart: Pointer;

 CodeEnd: Pointer;

begin

 asm

         JMP     @@End

         { *BEGIN* 16-bit code  }

         { -- never use it in your program! -- }

         { COM which writes ROM-BIOS to StdOut }

 @@Start:

         { Dump F000:0000-F000:FFFE }

         XOR     eDX, eDX  // DS = 0xF000   ; Data segment

         MOV     DH, 0F0h

         MOV     DS, eDX

         XOR     eDX, eDX  // DX = 0x0000   ; Data offset

         XOR     eCX, eCX  // CX = 0xFFFF   ; Data length

         DEC     eCX

         XOR     eBX, eBX  // BX = 0x0001   ; STDOUT (file handle)

         INC     eBX

         MOV     AH, 40h   // DosCall(0x40) ; INT21, DOS_WRITE_TO_HANDLE

         INT     21h

         JC      @@Exit    // On error exit ; AL = Error code

         { Dump F000:FFFF }

         XOR     eDX, eDX  // DS = 0xF000   ; Data segment

         MOV     DH, 0F0h

         MOV     DS, eDX

         XOR     eDX, eDX  // DX = 0xFFFF   ; Data offset

         DEC     eDX

         XOR     eCX, eCX  // CX = 0x0001   ; Data length

         INC     eCX

         MOV     eBX, eCX  // BX = 0x0001   ; STDOUT (file handle)

         MOV     AH, 40h   // DosCall(0x40) ; INT21, DOS_WRITE_TO_HANDLE

         INT     21h

         JC      @@Exit    // On error exit ; AL = Error code

         MOV     AL, 0     // no error      ; AL = 0

 @@Exit:

         MOV     AH, 4Ch   // DosCall(0x4C) ; INT21, DOS_TERMINATE_EXE

         INT     21h

 @@End:

         { *END* 16-bit code  }

         MOV     CodeStart, OFFSET @@Start

         MOV     CodeEnd, OFFSET @@End

 end;

 case Info of

   rdciStart:

     Result := CodeStart;

   rdciEnd:

     Result := CodeEnd;

   rdciSize:

     Result := Pointer(Cardinal(CodeEnd) - Cardinal(CodeStart));

 else

   Result := nil;

 end;

end;

{ *INTERNAL* - Save 16-bit code to file }

function _RomDumpCodeToFile(const Filename: string): Boolean;

var

 ComFile: THandle;

 Size: Cardinal;

begin

 Result := False;

 ComFile := CreateFile(PChar(Filename), GENERIC_WRITE, FILE_SHARE_READ, nil,

   CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

 if ComFile <> INVALID_HANDLE_VALUE then

 try

   Result := WriteFile(ComFile, _RomDumpCode(rdciStart)^,

     Cardinal(_RomDumpCode(rdciSize)), Size, nil) and

     (Size = Cardinal(_RomDumpCode(rdciSize)));

   if not Result then

     DeleteFile(PChar(Filename));

 finally

   CloseHandle(ComFile);

 end;

end;

{ *INTERNAL* - Execute 16-bit code redirected to file }

function _RomDumpCodeExecute(const Com, Dmp: string; Timeout: DWORD): Boolean;

var

 ComSpec: string;

 si: TStartupInfo;

 pi: TProcessInformation;

begin

 Result := False;

 SetLength(ComSpec, MAX_PATH);

 SetLength(ComSpec,

   GetEnvironmentVariable('ComSpec', PChar(@ComSpec[1]), MAX_PATH));

 if Length(ComSpec) > 0 then

 begin

   FillChar(si, SizeOf(TStartupInfo), 0);

   si.cb := SizeOf(TStartupInfo);

   si.dwFlags := STARTF_USESHOWWINDOW;

   si.wShowWindow := SW_HIDE;

   if CreateProcess(nil, PChar(ComSpec + ' /C ' + Com + ' > ' + Dmp),

     nil, nil, False, CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP, nil,

     nil, si, pi) then

   try

     Result := WaitForSingleObject(pi.hProcess, Timeout) <> WAIT_TIMEOUT;

   finally

     CloseHandle(pi.hProcess);

     CloseHandle(pi.hThread);

   end;

 end;

end;

function DirectoryExists(const Dir: string): Boolean;

var

 Attr: DWORD;

begin

 Attr := GetFileAttributes(PChar(Dir));

 Result := (Attr <> $FFFFFFFF) and

   (Attr and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY);

end;

{ Get BIOS dump the generic way }

function ReadRomBios16(var Buffer: TRomBiosDump; Timeout: DWORD): Boolean;

const

 TempSub = '~RomDmp';

 ComName = 'RomDump.com';

 DmpName = 'Rom.dmp';

var

 TempPath: string;

 TempDir: string;

 TempIdx: Integer;

 TempIdxStr: string;

 ComFile: string;

 DmpFile: string;

 DmpHandle: THandle;

 Written: DWORD;

begin

 Result := False;

 SetLength(TempPath, MAX_PATH);

 SetLength(TempPath, GetTempPath(MAX_PATH, PChar(@TempPath[1])));

 if Length(TempPath) > 0 then

 begin

   if (TempPath[Length(TempPath)] <> '\') then

     TempPath := TempPath + '\';

   TempIdx := 0;

   repeat

     Inc(TempIdx);

     Str(TempIdx, TempIdxStr);

     TempDir := TempPath + TempSub + TempIdxStr;

   until not DirectoryExists(TempDir);

   if CreateDirectory(PChar(TempDir), nil) then

   try

     TempDir := TempDir + '\';

     ComFile := TempDir + ComName;

     DmpFile := TempDir + DmpName;

     if _RomDumpCodeToFile(ComFile) then

     try

       if _RomDumpCodeExecute(ComFile, DmpFile, Timeout) then

       begin

         DmpHandle := CreateFile(PChar(DmpFile), GENERIC_READ,

           FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);

         if DmpHandle <> INVALID_HANDLE_VALUE then

         try

           FillChar(Buffer, SizeOf(TRomBiosDump), 0);

           Result := ReadFile(DmpHandle, Buffer, SizeOf(TRomBiosDump),

             Written, nil) and (Written = SizeOf(TRomBiosDump));

         finally

           CloseHandle(DmpHandle);

         end;

       end;

     finally

       DeleteFile(PChar(DmpFile));

       DeleteFile(PChar(ComFile));

     end;

   finally

     RemoveDirectory(PChar(TempDir));

   end;

 end;

end;

{###############################################################################

#                                                                              #

#                           DIRECT METHOD (Win9x)                              #

#                                                                              #

# Due to the fact that Windows 95/98/ME maps the BIOS into every Win32 process #

# for read access it is very simple to fill the buffer from memory.            #

#                                                                              #

###############################################################################}

function ReadRomBios9x(var Buffer: TRomBiosDump): Boolean;

begin

 Result := False;

 try

   FillChar(Buffer, SizeOf(TRomBiosDump), 0);

   Move(Pointer(Low(TRomBiosDump))^, Buffer, SizeOf(TRomBiosDump));

   Result := True;

 except

   // ignore exceptions

 end

end;

{###############################################################################

#                                                                              #

#                       PHYSICAL MEMORY METHOD (WinNT)                         #

#                                                                              #

# On Windows NT the ROM BIOS is only available through the named kernel object #

# '\Device\PhysicalMemory'. Because it is impossible to open kernel objects in #

# user mode with standard Win32 API functions we make use of NT's nativeAPI in #

# NtDll.dll ("NT-Layer") namely ZwOpenSection.                                 #

#                                                                              #

# (note: mostly there are two versions of every function ZwXxx and NtXxx. The  #

#  only difference in kernel mode is that the NtXxx version works in conside-  #

#  ration to security while ZwXxx not. But in user mode both work like NtXxx.) #

#                                                                              #

# At first the section is opened with ZwOpenSection. Normally we would proceed #

# ZwMapViewOfSection, ZwUnmapViewOfSection, and NtClose. But the functions are #

# more complex and there is no needing for it. With the handle (because we are #

# in the "very simple" user mode =) we now use MapViewOfFile, UnmapViewOfFile, #

# and CloseHandle to map an memory window (the ROM BIOS) into our process.     #

#                                                                              #

# Due to the fact that ZwOpenSection returns NT error-codes in case of failure #

# we have to translate it to an Win32 error-code (RtlNtStatusToDosError).      #

# All NT specific functions are dynamically loaded -- because the applications #

# should start on Win9x systems =)                                             #

#                                                                              #

###############################################################################}

{ For more information see Windows 2000/XP DDK  }

{ It works on Windows NT 4.0 too, use NtDll.dll }

type

 NTSTATUS = Integer;

const

 STATUS_SUCCESS        = NTSTATUS(0);

 STATUS_INVALID_HANDLE = NTSTATUS($C0000008);

 STATUS_ACCESS_DENIED  = NTSTATUS($C0000022);

type

 PUnicodeString = ^TUnicodeString;

 TUnicodeString = packed record

   Length: Word;

   MaximumLength: Word;

   Buffer: PWideChar;

 end;

const

 OBJ_INHERIT          = $00000002;

 OBJ_PERMANENT        = $00000010;

 OBJ_EXCLUSIVE        = $00000020;

 OBJ_CASE_INSENSITIVE = $00000040;

 OBJ_OPENIF           = $00000080;

 OBJ_OPENLINK         = $00000100;

 OBJ_KERNEL_HANDLE    = $00000200;

 OBJ_VALID_ATTRIBUTES = $000003F2;

type

 PObjectAttributes = ^TObjectAttributes;

 TObjectAttributes = record

   Length: ULONG;

   RootDirectory: THandle;

   ObjectName: PUnicodeString;

   Attributes: ULONG;

   SecurityDescriptor: PSecurityDescriptor;

   SecurityQualityOfService: PSecurityQualityOfService;

 end;

const

 ObjectPhysicalMemoryDeviceName = '\Device\PhysicalMemory';

 ObjectPhysicalMemoryName: TUnicodeString = (

   Length: Length(ObjectPhysicalMemoryDeviceName) * 2;

   MaximumLength: Length(ObjectPhysicalMemoryDeviceName) * 2 + 2;

   Buffer: ObjectPhysicalMemoryDeviceName;

 );

 ObjectPhysicalMemoryAccessMask: ACCESS_MASK = SECTION_MAP_READ;

 ObjectPhysicalMemoryAttributes: TObjectAttributes =(

   Length: SizeOf(TObjectAttributes);

   RootDirectory: 0;

   ObjectName: @ObjectPhysicalMemoryName;

   Attributes: OBJ_CASE_INSENSITIVE;

   SecurityDescriptor: nil;

   SecurityQualityOfService: nil;

 );

type

 TFNZwOpenSection = function(out SectionHandle: THandle;

   DesiredAccess: ACCESS_MASK; ObjectAttributes: PObjectAttributes): NTSTATUS;

   stdcall;

 TFNRtlNtStatusToDosError = function(Status: NTSTATUS): DWORD; stdcall;

const

 ntdll = 'ntdll.dll';

var

 ZwOpenSection: TFNZwOpenSection;

 RtlNtStatusToDosError: TFNRtlNtStatusToDosError;

function ReadRomBiosNt(var Buffer: TRomBiosDump; Timeout: DWORD): Boolean;

var

 NtLayer: HMODULE;

 Status: NTSTATUS;

 Section: THandle;

 View: Pointer;

begin

 Result := False;

 NtLayer := GetModuleHandle(ntdll);

 if NtLayer = 0 then

   SetLastError(ERROR_CALL_NOT_IMPLEMENTED)

 else

 begin

   if not Assigned(ZwOpenSection) then

     ZwOpenSection := GetProcAddress(NtLayer, 'ZwOpenSection');

   if not Assigned(RtlNtStatusToDosError) then

     RtlNtStatusToDosError := GetProcAddress(NtLayer, 'RtlNtStatusToDosError');

   if not (Assigned(ZwOpenSection) and Assigned(RtlNtStatusToDosError)) then

     SetLastError(ERROR_CALL_NOT_IMPLEMENTED)

   else

   begin

     Status := ZwOpenSection(Section, ObjectPhysicalMemoryAccessMask,

       @ObjectPhysicalMemoryAttributes);

     case Status of

       STATUS_SUCCESS:

         try

           View := MapViewOfFile(Section, ObjectPhysicalMemoryAccessMask, 0,

             Low(TRomBiosDump), SizeOf(TRomBiosDump));

           if Assigned(View) then

           try

             FillChar(Buffer, SizeOf(TRomBiosDump), 0);

             Move(View^, Buffer, SizeOf(TRomBiosDump));

             Result := True;

           finally

             UnmapViewOfFile(View);

           end;

         finally

           CloseHandle(Section);

         end;

       STATUS_ACCESS_DENIED:

         Result := ReadRomBios16(Buffer, Timeout);

     else

       SetLastError(RtlNtStatusToDosError(Status))

     end;

   end;

 end;

end;

{###############################################################################

#                                                                              #

#                               ReadRomBios                                    #

#                                                                              #

###############################################################################}

function ReadRomBios(var Dump: TRomBiosDump; Method: TReadRomBiosMethod;

 Timeout: DWORD = INFINITE): Boolean;

begin

 Result := False;

 case Method of

   rrbmAutomatic:

     if (Integer(GetVersion) < 0) then

     try

       Result := ReadRomBios9x(Dump);

     except

       Result := ReadRomBios16(Dump, Timeout);

     end

     else

       Result := ReadRomBiosNt(Dump, Timeout);

   rrbmGeneric:

     Result := ReadRomBios16(Dump, Timeout);

   rrbmMemory:

     Result := ReadRomBios9x(Dump);

   rrbmPhysical:

     Result := ReadRomBiosNt(Dump, Timeout);

 else

   SetLastError(ERROR_INVALID_PARAMETER);

 end;

end;

{###############################################################################

#                                                                              #

#     Utilities to simplify the access to data as generic standard types       #

#                                                                              #

###############################################################################}

function GetRomBiosBuffer(const Dump: TRomBiosDump; Address: Pointer;

 var Buffer; BufferSize: Cardinal): Cardinal;

begin

 Result := 0;

 if (Cardinal(Address) >= Low(TRomBiosDump)) and

   (Cardinal(Address) <= High(TRomBiosDump)) then

 begin

   Result := BufferSize;

   if (Cardinal(Address) + BufferSize > High(TRomBiosDump)) then

     Result := High(TRomBiosDump) - Cardinal(Address) + 1;

   Move(Dump[Cardinal(Address)], Buffer, Result);

 end;

end;

function GetRomBiosString(const Dump: TRomBiosDump; Address: Pointer): string;

begin

 Result := '';

 if (Cardinal(Address) >= Low(TRomBiosDump)) and

   (Cardinal(Address) <= High(TRomBiosDump)) then

   Result := string(PChar(@Dump[Cardinal(Address)]));

end;

function GetRomBiosLongLong(const Dump: TRomBiosDump; Address: Pointer): LONGLONG;

type

 PLongLong = ^LONGLONG;

begin

 Result := 0;

 if (Cardinal(Address) >= Low(TRomBiosDump)) and

   (Cardinal(Address) <= High(TRomBiosDump) - SizeOf(LONGLONG) + 1) then

   Result := PLongLong(@Dump[Cardinal(Address)])^;

end;

function GetRomBiosDWord(const Dump: TRomBiosDump; Address: Pointer): DWORD;

begin

 Result := 0;

 if (Cardinal(Address) >= Low(TRomBiosDump)) and

   (Cardinal(Address) <= High(TRomBiosDump) - SizeOf(DWORD) + 1) then

   Result := PDWORD(@Dump[Cardinal(Address)])^;

end;

function GetRomBiosWord(const Dump: TRomBiosDump; Address: Pointer): Word;

begin

 Result := 0;

 if (Cardinal(Address) >= Low(TRomBiosDump)) and

   (Cardinal(Address) <= High(TRomBiosDump) - SizeOf(Word) + 1) then

   Result := PWord(@Dump[Cardinal(Address)])^;

end;

function GetRomBiosByte(const Dump: TRomBiosDump; Address: Pointer): Byte;

begin

 Result := 0;

 if (Cardinal(Address) >= Low(TRomBiosDump)) and

   (Cardinal(Address) <= High(TRomBiosDump) - SizeOf(Byte) + 1) then

   Result := PByte(@Dump[Cardinal(Address)])^;

end;

end.

****************************************

下面是一个Demo:

program Test;

uses

 Windows,

 BiosHelp in 'BiosHelp.pas';

{$E exe}

{$R Icon.res}

const

 CRLF = #$0D#$0A;

function MyMessageBox(const Text: string; Icon: DWORD): LongBool;

var

 Params: TMsgBoxParams;

begin

 FillChar(Params, SizeOf(TMsgBoxParams), 0);

 with Params do

 begin

   cbSize := SizeOf(TMsgBoxParams);

   hwndOwner := GetDesktopWindow;

   hInstance := SysInit.HInstance;

   lpszText := PChar(Text);

   lpszCaption := 'BiosHelp sample';

   if (Icon <> 0) then

     dwStyle := Icon

   else

   begin

     dwStyle := MB_USERICON;

     lpszIcon := MakeIntResource(555);

   end;

 end;

 Result := MessageBoxIndirect(Params);

end;

const

 // Well known offsets... (only date seems to be always available)

 RomBiosDateOffset      = Pointer($000FFFF5);

 RomBiosNameOffset      = Pointer($000FE061);

 RomBiosCopyrightOffset = Pointer($000FE091);

 RomBiosIdOffset        = Pointer($000FEC71);

 

var

 Dump: TRomBiosDump;

begin

 if ReadRomBios(Dump, rrbmAutomatic) then

 begin

   MyMessageBox(

     'Your BIOS-Date: ' + GetRomBiosString(Dump, RomBiosDateOffset) + CRLF +

     CRLF +

     'Get BIOS info on Windows 95/98/SE/ME/NT/2K/XP' + CRLF +

     'with BiosHelp.pas for Delphi?4.03/5.01/6.01' + CRLF +

     CRLF +

     'Written 2001 by Nico Bendlin (nico@bendlin.de)', 0)

 end

 else

   MyMessageBox('Error on reading BIOS!', MB_ICONERROR);

end.