Содержание материала

В процессе написания программного обеспечения в ряде случаев возникает необходимость получения данных из физических ячеек памяти. Документации Delphi по данному вопросу, я найти не смог, поэтому хочу восполнить данный пробел.

Платформа WinNT(XP) не допускает возможность непосредственного доступа к памяти средствами Win32API. В этом случае программист должен или написать свой драйвер доступа к физической памяти или использовать native kernel32 функции ядра.

Рассмотрим второй вариант использующий объект "проекция файла" (file-mapping object), представляющем собой блок памяти(раздел) доступный двум и более процессам для совместного использования.

Совместное использование данных с помощью объекта "раздел" происходит следующим образом: Задав атрибуты с помощью функции

Code:

procedure InitializeObjectAttributes(InitializedAttributes : PNtObjectAttributes;

                                    pObjectName : PNtUnicodeString;

                                    const uAttributes : ULONG;

                                    const hRootDirectory : THandle;

                                    pSecurityDescriptor : PSECURITY_DESCRIPTOR);

begin

with InitializedAttributes^ do

begin

   Length := SizeOf(TNtObjectAttributes);

   ObjectName := pObjectName;

   Attributes := uAttributes;

   RootDirectory := hRootDirectory;

   SecurityDescriptor := pSecurityDescriptor;

   SecurityQualityOfService := nil;

end;

end;

 

 

которая фактически заполняет структуру NtObjectAttributes

Используем объект '\Device\PhysicalMemory' и преобразовав его в тип TNtUnicodeString;

RtlInitAnsiString(@AnsiPhysicalMemory, '\Device\PhysicalMemory');
RtlAnsiStringToUnicodeString(@UniPhysicalMemory, @AnsiPhysicalMemory, true);
InitializeObjectAttributes(@NtObjectAttributes, @UniPhysicalMemory, OBJ_KERNEL_HANDLE, 0, nil);

Получаем дескриптор секции вызывая функцию ядра
 

NtOpenSection(SectionHandle, SECTION_MAP_READ, @NtObjectAttributes);

Этим самым мы открываем объект '\Device\PhysicalMemory' для чтения отображенного участка физической памяти в процессе пользователя.

Отображение осуществляем с помощью функции NtMapViewOfSection возвращающей указатель на участок памяти процесса пользователя в который осуществляется отображение. Более подробную информацию можно найти в MicrosoftDDK.

Привожу несложный пример.


Code:

unit PhysMemWorks;

 

interface

 

uses windows;

 

type

 

NTSTATUS = LongInt;

PLARGE_INTEGER = ^LARGE_INTEGER;

TSectionInherit = (ViewNone,ViewShare,ViewUnmap);

SECTION_INHERIT = TSectionInherit;

 

PHYSICAL_ADDRESS = record

LowPart : DWORD ;

HighPart : DWORD;

end;

 

 

TNtAnsiString = packed record

Length : Word;

MaximumLength : Word;

Buffer : PChar;

end;

 

PNtAnsiString = ^TNtAnsiString;

ANSI_STRING = TNtAnsiString;

 

 

TNtUnicodeString = packed record

Length : Word;

MaximumLength : Word;

Buffer : PWideChar;

end;

 

UNICODE_STRING = TNtUnicodeString;

PNtUnicodeString = ^TNtUnicodeString;

 

 

TNtObjectAttributes = packed record

Length : ULONG;

RootDirectory : THandle;

ObjectName : PNtUnicodeString;

Attributes : ULONG;

SecurityDescriptor : Pointer;

SecurityQualityOfService : Pointer;

end;

 

OBJECT_ATTRIBUTES = TNtObjectAttributes;

PNtObjectAttributes = ^TNtObjectAttributes;

 

 

function OpenPhysicalMemory:dword;

 

function MapPhysicalMemory (hPhysMem:tHANDLE; pdwAddress:DWORD; pdwLength:DWORD; pdwBaseAddress:pDWORD):dword;

 

///////////

 

const DLL = 'ntdll.dll';

 

function RtlAnsiStringToUnicodeString( DestinationString : PNtUnicodeString; SourceString : PNtAnsiString;

AllocateDestinationString : Boolean ) : NTSTATUS; stdcall; external DLL name 'RtlAnsiStringToUnicodeString';

procedure RtlInitAnsiString( DestinationString : PNtAnsiString; SourceString : PChar ); stdcall; external DLL name 'RtlInitAnsiString';

 

function NtMapViewOfSection(SectionHandle : THandle;ProcessHandle : THandle; var BaseAddress : PDWORD;

ZeroBits : ULONG; CommitSize : ULONG; SectionOffset : PLARGE_INTEGER; ViewSize : DWORD;

InheritDisposition : SECTION_INHERIT;

AllocationType : ULONG; Protect : ULONG) : NTSTATUS; stdcall; external DLL name 'NtMapViewOfSection';

 

function NtUnmapViewOfSection(const ProcessHandle : THandle;

const BaseAddress : Pointer) : NTSTATUS; stdcall; external DLL name 'NtUnmapViewOfSection';

function NtOpenSection(out SectionHandle : THandle; const DesiredAccess : ACCESS_MASK;

ObjectAttributes : PNtObjectAttributes) : NTSTATUS; stdcall; external DLL name 'NtOpenSection';

 

implementation

 

const

OBJ_KERNEL_HANDLE = $0000200;

 

var

status: dword;

 

procedure InitializeObjectAttributes(InitializedAttributes : PNtObjectAttributes;

pObjectName : PNtUnicodeString; const uAttributes : ULONG; const hRootDirectory : THandle;

pSecurityDescriptor : PSECURITY_DESCRIPTOR);

begin

with InitializedAttributes^ do

begin

Length := SizeOf(TNtObjectAttributes);

ObjectName := pObjectName;

Attributes := uAttributes;

RootDirectory := hRootDirectory;

SecurityDescriptor := pSecurityDescriptor;

SecurityQualityOfService := nil;

end;

end;

 

 

function OpenPhysicalMemory:dword;

var

hPhysMem:dword;

UniPhysicalMemory : TNtUnicodeString;

AnsiPhysicalMemory :TNtAnsiString ;

oa :TNtObjectAttributes;

 

begin

RtlInitAnsiString(@AnsiPhysicalMemory, '\Device\PhysicalMemory');

status:= RtlAnsiStringToUnicodeString(@UniPhysicalMemory, @AnsiPhysicalMemory, true);

InitializeObjectAttributes(@oa, @UniPhysicalMemory, OBJ_KERNEL_HANDLE, 0, nil) ;

status:= NtOpenSection(hPhysMem, SECTION_MAP_READ, @oa);

if status <> 0 then result:= 0 else result:= hPhysMem;

end;

 

 

function MapPhysicalMemory (hPhysMem:tHANDLE; pdwAddress:DWORD; pdwLength:DWORD; pdwBaseAddress:pDWORD):dword;

var

SectionOffset: pLARGE_INTEGER;

begin

SectionOffset.HighPart := 0;

SectionOffset.LowPart:= pdwAddress;

NtMapViewOfSection(hPhysMem, 0, pdwBaseAddress, 0, 0, nil,0, ViewNone, 0, PAGE_READONLY);

result:=1;

end;

 

 

function UnmapPhysicalMemory (dwBaseAddress:DWORD):dword;

begin

NtUnmapViewOfSection(0, @dwBaseAddress);

result:=1;

end;

 

end.

 


 

Используя данный модуль получаем доступ к функциям ядра которые, в свою очередь, позволяют получить проекцию нужного участка памяти.

На форме разместим компонент StringGrid для представления информации в табличном виде, Button, Label и Edit и пишем такой код.

Code:

unit Read_Mem;

 

interface

 

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, Grids, ExtCtrls, PhysMemWorks;

 

type

TForm1 = class(TForm)

gridData: TStringGrid;

Label12: TLabel;

editAddr: TEdit;

btnRead: TButton;

Label2: TLabel;

procedure btnReadClick(Sender: TObject);

procedure FormCreate(Sender: TObject);

end;

 

var

 

Form1: TForm1;

 

implementation

 

{$R *.DFM}

{$R WindowsXP.res}

 

 

type

XData = array[1..16] of Byte;

YData = array[1..16] of XData;

TPhysPointer =^YData;

 

procedure TForm1.btnReadClick(Sender: TObject);

var

i, j: longint;

nAddr: int64;//

s1, s2: String;

b: Byte;

ch: Char;

arrayMemory :pbytearray;

PointMemory:pointer;

hmemory:dword;

xhex: integer;

yhex: integer;

ofsetHex: integer;

begin

with gridData do

begin

ColWidths[0] := Canvas.TextWidth(IntToHex(0, 9));

ColWidths[1] := Canvas.TextWidth(Cells[1, 0]);

end;

nAddr := StrToInt('$' + editAddr.Text);

label2.Caption:=inttostr(nAddr div 1024 )+ ' kб';

hmemory:=OpenPhysicalMemory;

PointMemory:=MapViewOfFile(hmemory, FILE_MAP_READ, 0, nAddr, $2000); //размер секции 8 кб

arrayMemory :=PointMemory;

xhex:= nAddr and $0f;

yhex:=(nAddr and $00f0) div 16;

ofsetHex:= ((nAddr and $0f00) div 16);

if yhex = 0 then yhex:=0;

if PointMemory <> nil then

begin

for i:=1 to 16 do

begin

gridData.Cells[0,i] := IntToHex(nAddr,8);

s1 := '';

s2 := '';

for j:=1 to 16 do

begin

b := arrayMemory^[((i+ofsetHex+yhex-1)*16)+(j+xhex-1)];

s1 := s1 + IntToHex(b, 2) + ' ';

if b >= $20 then ch := Char(b) else ch:='.';

s2 := s2 + ch;

end;

gridData.Cells[1,i] := s1;

gridData.Cells[2,i] := s2;

nAddr := nAddr + 16;

end;

 

with gridData do

begin

ColWidths[2] := Canvas.TextWidth(Cells[2, 1] + ' ');

end;

 

end else MessageDlg('Этот участок памяти' +^M+' недоступен!!!' , mtWarning, [mbOK], 0);

 

end;

 

procedure TForm1.FormCreate(Sender: TObject);

var

i: integer;

begin

with gridData do

begin

Cells[0,0]:=' ADDR';

Cells[1,0]:='';

for i := 0 to 15 do

Cells[1,0] := Cells[1,0] + IntToHex(i, 2) + ' ';

Cells[2,0]:=' ASCII';

end;

end;

end.

  

Готово! У нас есть приложение позволяющее просматривать физическую память. Наберите, например, в поле адреса 000FFF00 , нажмие "Read" и в ячейках начиная с FFFF5 прочитайте дату прошивки BIOS Вашей материнской платы.

Используя данные функции Вы легко получаете возможность просмотра всего объёма физической памяти, за исключением системных адресов операционной системы.

Альберт Мамедов (MagDelphi)

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить