Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Как прочитать ROM-BIOS?

01.01.2007

An Example of this unit is availabe as Demo Download.

////////////////////////////////////////////////////////////////////////////////
//
//                            BIOS Helper for Delphi
//
//               BIOS related utilities for Win9x and WinNT(i386)
//
////////////////////////////////////////////////////////////////////////////////
//
//  The Original Code is:
//   BiosHelp.pas, released 2001-09-02.
//
//  The Initial Developer of the Original Code is Nico Bendlin.
//
//  Portions created by Nico Bendlin are
//   Copyright (C) 2001-2003 Nico Bendlin. All Rights Reserved.
//
//  Contributor(s):
//   Nico Bendlin<nicode@gmx.net>
//
//  The contents of this file are subject to the Mozilla Public License Version
//  1.1 (the "License"); you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
//
//  Software distributed under the License is distributed on an "AS IS" basis,
//  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
//  the specific language governing rights and limitations under the License.
//
//  Alternatively, the contents of this file may be used under the terms of
//  either the GNU General Public License Version 2 or later (the "GPL"), or
//  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
//  in which case the provisions of the GPL or the LGPL are applicable instead
//  of those above. If you wish to allow use of your version of this file only
//  under the terms of either the GPL or the LGPL, and not to allow others to
//  use your version of this file under the terms of the MPL, indicate your
//  decision by deleting the provisions above and replace them with the notice
//  and other provisions required by the GPL or the LGPL. If you do not delete
//  the provisions above, a recipient may use your version of this file under
//  the terms of any one of the MPL, the GPL or the LGPL.
//
////////////////////////////////////////////////////////////////////////////////
//
//  Revision:
//
//    2003-02-15  2.00 [NicoDE]
//                     - generic dump method completely rewritten
//                     - default range is now E000:0000-F000:FFFF
//
////////////////////////////////////////////////////////////////////////////////
 
{$IFDEF CONDITIONALEXPRESSIONS}
 
{$DEFINE DELPHI6UP}
 
{$IF NOT DEFINED(VER140)}
   
{$DEFINE DELPHI7UP}
 
{$IFEND}
{$ENDIF}
 
unit
BiosHelp {$IFDEF DELPHI6UP} platform {$ENDIF};
 
{$MINENUMSIZE 4}
{$WEAKPACKAGEUNIT}
{$IFDEF DELPHI7UP}
 
{$WARN UNSAFE_TYPE OFF}
 
{$WARN UNSAFE_CODE OFF}
{$ENDIF}
 
interface
 
uses
 
Windows;
 
const
 
RomBiosDumpBase = $000E0000;
 
RomBiosDumpEnd  = $000FFFFF;
 
RomBiosDumpSize = RomBiosDumpEnd - RomBiosDumpBase + 1;
 
type
 
PRomBiosDump = ^TRomBiosDump;
 
TRomBiosDump = array [RomBiosDumpBase..RomBiosDumpEnd] of Byte;
 
type
 
TRomDumpMethod = (rdmAutomatic,  // Autodetect OS type and use proper method
    rdmGeneric
,    // Use 16-bit EXE program to dump the BIOS
    rdmMemory
,     // Dump from process's address space (Win9x)
    rdmPhysical    
// Dump from physical memory object (WinNT)
   
);
 
function DumpRomBios(out Dump: TRomBiosDump;
 
Method: TRomDumpMethod = rdmAutomatic; Timeout: DWORD = 5000): Boolean;
function DumpRomBiosEx(RomBase: Pointer; RomSize: Cardinal; out Dump;
 
Method: TRomDumpMethod = rdmAutomatic; Timeout: DWORD = 5000): Boolean;
 
procedure
ReadRomDumpBuffer(const Dump: TRomBiosDump; Addr: Pointer;
 
var Buffer; Size: Cardinal);
procedure
ReadRomDumpBufferEx(const Dump; Base, Addr: Pointer;
 
var Buffer; Size: Cardinal);
 
function GetRomDumpAddr(const Dump: TRomBiosDump; Addr: Pointer): Pointer;
function GetRomDumpAddrEx(const Dump; Base, Addr: Pointer): Pointer;
 
implementation
 
////////////////////////////////////////////////////////////////////////////////
//
//  DumpRomBios16 (rdmGeneric)
//
//    Creates an 16-bit EXE program in TEMP and runs it redirected to an file.
//
//    WARNING: One day 16-bit code will not run on future Windows.
//    WARNING: You are dumping the BIOS inside the MS-DOS 'emulator'.
//
 
function _RomDumpCode(RomBase: Pointer; RomSize: Cardinal;
 
out Code: Pointer; out Size: Cardinal): Boolean;
const
 
BlockSize = $1000;
type                                    
// ; RomDump (dumps mem to STDOUT)
 
PRomDumpCode = ^TRomDumpCode;          // ; BlockSize MUST be multiple of 10h.
 
TRomDumpCode = packed record           //
    _header
: TImageDosHeader;            //
    _notice
: array[0..$4F] of AnsiChar;  // @@note: db      'RomDump 2.0', ...
    init
: packed record                  // @@init:
      _mov_44
: array[0..2] of Byte;      //         mov     ax, 4400h
      _mov_bx
: array[0..2] of Byte;      //         mov     bx, 0001h
      _dos_21
: array[0..1] of Byte;      //         int     21h
      _jcf_18
: array[0..1] of Byte;      //         jc      @@code
      _and_dx
: array[0..3] of Byte;      //         and     dx, 0082h
      _cmp_dx
: array[0..3] of Byte;      //         cmp     dx, 0082h
      _jne_0E
: array[0..1] of Byte;      //         jne     @@code
      _psh_cs
: Byte;                     //         push    cs
      _pop_ds
: Byte;                     //         push    ds
      _mov_dx
: array[0..2] of Byte;      //         mov     dx, offset @@note
      _mov_09
: array[0..1] of Byte;      //         mov     ah, 09h
      _int_21
: array[0..1] of Byte;      //         int     21h
      _mov_4C
: array[0..2] of Byte;      //         mov     ax, 4C01h
      _int_20
: array[0..1] of Byte;      //         int     21h
   
end;                                 //
    code
: packed record                  // @@code:
      _mov_cx
: Byte;
     
BlockCount: Word;   //         mov     cx, <BlockCount>
      _mov_dx
: Byte;
     
DatSegment: Word;   //         mov     dx, <DatSegment>
      _jcx_1C
: array[0..1] of Byte;      //         jcxz    @@rest
   
end;                                 //
    loop
: packed record                  // @@loop:
      _psh_cx
: Byte;                     //         push    cx
      _psh_dx
: Byte;                     //         push    dx
      _mov_ds
: array[0..1] of Byte;      //         mov     ds, dx
      _mov_dx
: Byte;
     
DatOffset: Word;    //         mov     dx, <DatOffset>
      _mov_cx
: array[0..2] of Byte;      //         mov     cx, <BlockSize>
      _mov_bx
: array[0..2] of Byte;      //         mov     bx, 0001h
      _mov_ax
: array[0..2] of Byte;      //         mov     ax, 4000h
      _int_21
: array[0..1] of Byte;      //         int     21h
      _pop_dx
: Byte;                     //         pop     dx
      _pop_cx
: Byte;                     //         pop     cx
      _jcf_1C
: array[0..1] of Byte;      //         jc      @@exit
      _add_dx
: array[0..3] of Byte;      //         add     dx, <BlockSize/10h>
      _lop_E4
: array[0..1] of Byte;      //         loop    @@loop
   
end;                                 //
    rest
: packed record                  // @@rest:
      _mov_ds
: array[0..1] of Byte;      //         mov     ds, dx
      _mov_dx
: Byte;
     
DatOffset: Word;    //         mov     dx, <DatOffset>
      _mov_cx
: Byte;
     
LenghtMod: Word;    //         mov     cx, <LenghtMod>
      _mov_bx
: array[0..2] of Byte;      //         mov     bx, 0001h
      _mov_ax
: array[0..2] of Byte;      //         mov     ax, 4000h
      _jcx_06
: array[0..1] of Byte;      //         jcxz    @@exit
      _int_21
: array[0..1] of Byte;      //         int     21h
      _jcf_02
: array[0..1] of Byte;      //         jc      @@exit
      _mov_al
: array[0..1] of Byte;      //         mov     al, 00h
   
end;                                 //
   
Exit: packed record                  // @@exit:
      _mov_ah
: array[0..1] of Byte;      //         mov     ah, 4Ch
      _int_21
: array[0..1] of Byte;      //         int     21h
   
end;                                 //
 
end;
const
 
RomDumpCodeSize = SizeOf(TRomDumpCode) - SizeOf(TImageDosHeader);
 
RomDumpCode: TRomDumpCode = (_header: (e_magic: IMAGE_DOS_SIGNATURE;
    e_cblp
: Word(RomDumpCodeSize) and $1FF;
    e_cp
: Word((RomDumpCodeSize - 1) shr 9) + 1;
    e_crlc
: $0000;
    e_cparhdr
: SizeOf(TImageDosHeader) shr 4;
    e_minalloc
: $0000;
    e_maxalloc
: $FFFF;
    e_ss
: $0000;
    e_sp
: $1000;
    e_csum
: $0000;
    e_ip
: SizeOf(RomDumpCode._notice);
    e_cs
: $0000;
    e_lfarlc
: SizeOf(TImageDosHeader);
    e_ovno
: $0000;
    e_res
: ($0000, $0000, $0000, $0000);
    e_oemid
: $0000;
    e_oeminfo
: $0000;
    e_res2
: ($0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000,
    $0000
, $0000);
    _lfanew
: $00000000
   
);
    _notice
: #13#10 +
   
'RomDump 2.0'#13#10 +
   
'Copyright (c) 2003 Nico Bendlin'#13#10 +
   
#13#10 +
   
'Usage: RomDump > filename'#13#10 +
   
#13#10'$';
    init
: (_mov_44: ($B8, $00, $44);
    _mov_bx
: ($BB, $01, $00);
    _dos_21
: ($CD, $21);
    _jcf_18
: ($72, $18);
    _and_dx
: ($81, $E2, $82, $00);
    _cmp_dx
: ($81, $FA, $82, $00);
    _jne_0E
: ($75, $0E);
    _psh_cs
: $0E;
    _pop_ds
: $1F;
    _mov_dx
: ($BA, $00, $00);
    _mov_09
: ($B4, $09);
    _int_21
: ($CD, $21);
    _mov_4C
: ($B8, $01, $4C);
    _int_20
: ($CD, $21);
   
);
    code
: (_mov_cx: $B9; BlockCount: $0010;
    _mov_dx
: $BA; DatSegment: $F000;
    _jcx_1C
: ($E3, $1C)
   
);
    loop
: (_psh_cx: $51;
    _psh_dx
: $52;
    _mov_ds
: ($8E, $DA);
    _mov_dx
: $BA; DatOffset: $0000;
    _mov_cx
: ($B9, Lo(BlockSize), Hi(BlockSize));
    _mov_bx
: ($BB, $01, $00);
    _mov_ax
: ($B8, $00, $40);
    _int_21
: ($CD, $21);
    _pop_dx
: $5A;
    _pop_cx
: $59;
    _jcf_1C
: ($72, $1C);
    _add_dx
: ($81, $C2, Lo(BlockSize shr 4), Hi(BlockSize shr 4));
    _lop_E4
: ($E2, $E4)
   
);
    rest
: (_mov_ds: ($8E, $DA);
    _mov_dx
: $BA; DatOffset: $0000;
    _mov_cx
: $B9; LenghtMod: $0000;
    _mov_bx
: ($BB, $01, $00);
    _mov_ax
: ($B8, $00, $40);
    _jcx_06
: ($E3, $06);
    _int_21
: ($CD, $21);
    _jcf_02
: ($72, $02);
    _mov_al
: ($B0, $00)
   
);
   
Exit: (_mov_ah: ($B4, $4C);
    _int_21
: ($CD, $21)
   
)
   
);
begin
 
Result := False;
 
if (RomSize > 0) and (RomSize <= $100000) and
   
(Cardinal(RomBase) < $100000) and
   
(Cardinal(RomBase) + RomSize <= $100000) then
 
begin
   
Size := SizeOf(TRomDumpCode);
   
Code := Pointer(LocalAlloc(LPTR, Size));
   
if Code <> nil then
     
try
       
PRomDumpCode(Code)^ := RomDumpCode;
       
with PRomDumpCode(Code)^ do
       
begin
          code
.BlockCount := Word(RomSize div BlockSize);
          code
.DatSegment := Word(Cardinal(RomBase) shr 4);
          loop
.DatOffset  := Word(Cardinal(RomBase)) and $000F;
          rest
.DatOffset  := loop.DatOffset;
          rest
.LenghtMod  := Word(RomSize mod BlockSize);
       
end;
       
Result := True;
     
except
       
LocalFree(HLOCAL(Code));
       
Code := nil;
       
Size := 0;
     
end;
 
end;
end;
 
function _SaveRomDumpCodeToFile(RomBase: Pointer; RomSize: Cardinal;
 
const FileName: string): Boolean;
var
 
Code: Pointer;
 
Size: Cardinal;
 
Hand: THandle;
 
Num: DWORD;
begin
 
Result := False;
 
if _RomDumpCode(RomBase, RomSize, Code, Size) then
   
try
     
Hand := CreateFile(PChar(FileName), GENERIC_WRITE, FILE_SHARE_READ, nil,
        CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL, 0);
     
if Hand <> INVALID_HANDLE_VALUE then
       
try
         
Result := WriteFile(Hand, Code^, Size, Num, nil) and (Num = Size);
         
if not Result then
           
DeleteFile(PChar(FileName));
       
finally
         
CloseHandle(Hand);
       
end;
   
finally
     
LocalFree(HLOCAL(Code));
   
end;
end;
 
function _ExecuteRomDumpCode(const Code, Dump: string; Timeout: DWORD): Boolean;
var
 
ComSpec: string;
 
StartInfo: TStartupInfo;
 
ProcInfo: TProcessInformation;
 
ErrorMode: Cardinal;
begin
 
Result := False;
 
SetLength(ComSpec, MAX_PATH + 1);
 
SetLength(ComSpec,
   
GetEnvironmentVariable('ComSpec', PChar(@ComSpec[1]), MAX_PATH));
 
if Length(ComSpec) <= 0 then
   
Exit;
 
FillChar(StartInfo, SizeOf(TStartupInfo), 0);
 
StartInfo.cb := SizeOf(TStartupInfo);
 
StartInfo.dwFlags := STARTF_USESHOWWINDOW;
 
StartInfo.wShowWindow := SW_HIDE;
 
ErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOGPFAULTERRORBOX or
    SEM_NOALIGNMENTFAULTEXCEPT
or SEM_NOOPENFILEERRORBOX);
 
try
   
if CreateProcess(nil, PChar(ComSpec + ' /C ' + Code + ' > ' + Dump),
     
nil, nil, False, HIGH_PRIORITY_CLASS, nil, nil, StartInfo, ProcInfo) then
     
try
       
Result :=
         
(WaitForSingleObject(ProcInfo.hProcess, Timeout) <> WAIT_TIMEOUT);
       
if not Result then
         
TerminateProcess(ProcInfo.hProcess, STATUS_TIMEOUT);
     
finally
       
CloseHandle(ProcInfo.hThread);
       
CloseHandle(ProcInfo.hProcess);
     
end;
 
finally
   
SetErrorMode(ErrorMode);
 
end;
end;
 
function DumpRomBios16(RomBase: Pointer; RomSize: Cardinal; var Dump;
 
Timeout: DWORD): Boolean;
var
 
Tmp: array [0..MAX_PATH] of Char;
 
Dmp: array [0..MAX_PATH] of Char;
 
Exe: array [0..MAX_PATH] of Char;
 
Hnd: THandle;
 
Num: DWORD;
begin
 
Result := False;
 
if GetTempPath(MAX_PATH, Tmp) > 0 then
   
GetShortPathName(Tmp, Tmp, MAX_PATH)
 
else
    lstrcpy
(Tmp, '.');
 
if GetTempFileName(Tmp, 'rom', 0, Dmp) > 0 then
   
try
      lstrcpy
(Exe, Dmp);
      lstrcat
(Exe, '.exe');  // Win9x requires .EXE extention
     
if _SaveRomDumpCodeToFile(RomBase, RomSize, Exe) then
       
try
         
if _ExecuteRomDumpCode(Exe, Dmp, Timeout) then
         
begin
           
Hnd := CreateFile(Dmp, GENERIC_READ, FILE_SHARE_READ or
              FILE_SHARE_WRITE
, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
           
if Hnd <> INVALID_HANDLE_VALUE then
             
try
               
Result := ReadFile(Hnd, Dump, RomSize, Num, nil) and (Num = RomSize);
             
finally
               
CloseHandle(Hnd);
             
end;
         
end;
       
finally
         
DeleteFile(Exe);
       
end;
   
finally
     
DeleteFile(Dmp);
   
end;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
//  DumpRomBios9x (rdmMemory)
//
//    Win9x maps the BIOS into every process - therefore it's directly accessed.
//
 
function DumpRomBios9x(RomBase: Pointer; RomSize: Cardinal; var Dump): Boolean;
begin
 
Result := False;
 
try
   
Move(RomBase^, Dump, RomSize);
   
Result := True;
 
except
   
// ignore exeptions
 
end
end;
 
////////////////////////////////////////////////////////////////////////////////
//
//  DumpRomBiosNt (rdmPhysical)
//
//    On WinNT the BIOS is accessable through section '\Device\PhysicalMemory'.
//    This object can only be opened by members of local 'Adminstrators' group.
//    ZwOpenSection and RtlNtStatusToDosError are documented in newer MSDN/DDK.
//
 
type
  NTSTATUS
= Integer;
 
 
PUnicodeString = ^TUnicodeString;
 
TUnicodeString = packed record
   
Length: Word;
   
MaximumLength: Word;
   
Buffer: PWideChar;
 
end;
 
 
PObjectAttributes = ^TObjectAttributes;
 
TObjectAttributes = record
   
Length: ULONG;
   
RootDirectory: THandle;
   
ObjectName: PUnicodeString;
   
Attributes: ULONG;
   
SecurityDescriptor: PSecurityDescriptor;
   
SecurityQualityOfService: PSecurityQualityOfService;
 
end;
 
 
TFNZwOpenSection = function(out Section: THandle; Access: ACCESS_MASK;
   
Attributes: PObjectAttributes): NTSTATUS;
  stdcall
;
 
TFNRtlNtStatusToDosError = function(Status: NTSTATUS): DWORD;
  stdcall
;
 
const
 
PhysMemDevName = '\Device\PhysicalMemory';
 
PhysMemName: TUnicodeString = (Length: Length(PhysMemDevName) * SizeOf(WideChar);
   
MaximumLength: Length(PhysMemDevName) * SizeOf(WideChar) + SizeOf(WideChar);
   
Buffer: PhysMemDevName;
   
);
 
PhysMemMask: ACCESS_MASK = SECTION_MAP_READ;
 
PhysMemAttr: TObjectAttributes = (Length: SizeOf(TObjectAttributes);
   
RootDirectory: 0;
   
ObjectName: @PhysMemName;
   
Attributes: $00000040;  // OBJ_CASE_INSENSITIVE
   
SecurityDescriptor: nil;
   
SecurityQualityOfService: nil;
   
);
 
var
 
ZwOpenSection: TFNZwOpenSection;
 
RtlNtStatusToDosError: TFNRtlNtStatusToDosError;
 
function DumpRomBiosNt(RomBase: Pointer; RomSize: Cardinal; var Dump): Boolean;
var
 
HMod: HMODULE;
 
Stat: NTSTATUS;
 
Sect: THandle;
 
View: Pointer;
begin
 
Result := False;
 
HMod   := GetModuleHandle('ntdll.dll');
 
if HMod = 0 then
   
SetLastError(ERROR_CALL_NOT_IMPLEMENTED)
 
else
 
begin
   
if not Assigned(ZwOpenSection) then
     
ZwOpenSection := GetProcAddress(HMod, 'ZwOpenSection');
   
if not Assigned(RtlNtStatusToDosError) then
     
RtlNtStatusToDosError := GetProcAddress(HMod, 'RtlNtStatusToDosError');
   
if not Assigned(ZwOpenSection) or not Assigned(RtlNtStatusToDosError) then
     
SetLastError(ERROR_CALL_NOT_IMPLEMENTED)
   
else
   
begin
     
Stat := ZwOpenSection(Sect, PhysMemMask, @PhysMemAttr);
     
if Stat >= 0 then
       
try
         
View := MapViewOfFile(Sect, PhysMemMask, 0, Cardinal(RomBase), RomSize);
         
if View <> nil then
           
try
             
Move(View^, Dump, RomSize);
             
Result := True;
           
finally
             
UnmapViewOfFile(View);
           
end;
       
finally
         
CloseHandle(Sect);
       
end
     
else
       
SetLastError(RtlNtStatusToDosError(Stat));
   
end;
 
end;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
//  DumpRomBios(Ex)
//
//    Public functions to call OS-dependent implementations.
//
 
function DumpRomBios(out Dump: TRomBiosDump;
 
Method: TRomDumpMethod = rdmAutomatic; Timeout: DWORD = 5000): Boolean;
begin
 
Result := DumpRomBiosEx(Pointer(RomBiosDumpBase), RomBiosDumpSize, Dump,
   
Method, Timeout);
end;
 
function DumpRomBiosEx(RomBase: Pointer; RomSize: Cardinal; out Dump;
 
Method: TRomDumpMethod = rdmAutomatic; Timeout: DWORD = 5000): Boolean;
begin
 
Result := False;
 
case Method of
    rdmAutomatic
:
     
if (GetVersion() and $80000000) <> 0 then
       
Result := DumpRomBios9x(RomBase, RomSize, Dump)
     
else
       
begin
         
Result := DumpRomBiosNt(RomBase, RomSize, Dump);
         
if not Result then
            DumpRomBios16
(RomBase, RomSize, Dump, DWORD(Timeout));
       
end;
      rdmGeneric
:
     
Result := DumpRomBios16(RomBase, RomSize, Dump, DWORD(Timeout));
    rdmMemory
:
     
Result := DumpRomBios9x(RomBase, RomSize, Dump);
    rdmPhysical
:
     
Result := DumpRomBiosNt(RomBase, RomSize, Dump);
   
else
     
SetLastError(ERROR_INVALID_PARAMETER);
 
end;
end;
 
////////////////////////////////////////////////////////////////////////////////
//
//  ReadRomDumpBuffer(Ex) / GetRomDumpAddr(Ex)
//
//    Utilities to simplify the access to dumps.
//
 
procedure
ReadRomDumpBuffer(const Dump: TRomBiosDump; Addr: Pointer;
 
var Buffer; Size: Cardinal);
begin
 
Move(Dump[Cardinal(Addr)], Buffer, Size);
end;
 
procedure
ReadRomDumpBufferEx(const Dump; Base, Addr: Pointer;
 
var Buffer; Size: Cardinal);
begin
 
Move(Pointer(Cardinal(@Dump) + Cardinal(Addr) - Cardinal(Base))^,
   
Buffer, Size);
end;
 
function GetRomDumpAddr(const Dump: TRomBiosDump; Addr: Pointer): Pointer;
begin
 
Result := @Dump[Cardinal(Addr)];
end;
 
function GetRomDumpAddrEx(const Dump; Base, Addr: Pointer): Pointer;
begin
 
Result := Pointer(Cardinal(@Dump) + Cardinal(Addr) - Cardinal(Base));
end;
 
end.

Взято с сайта https://www.swissdelphicenter.ch/en/tipsindex.php