Использование native kernel32 функций для получения проекции физической памяти

Использование native kernel32 функций для получения проекции физической памяти

Использование native kernel32 функций для получения проекции физической памяти
© 2006 Альберт Мамедов (MagDelphi)
В процессе написания программного обеспечения в ряде случаев возникает необходимость получения данных из физических ячеек памяти. Документации Delphi по данному вопросу, я найти не смог, поэтому хочу восполнить данный пробел.
Платформа WinNT(XP) не допускает возможность непосредственного доступа к памяти средствами Win32API. В этом случае программист должен или написать свой драйвер доступа к физической памяти или использовать native kernel32 функции ядра.
Рассмотрим второй вариант использующий объект "проекция файла" (file-mapping object), представляющем собой блок памяти(раздел) доступный двум и более процессам для совместного использования.
Совместное использование данных с помощью объекта "раздел" происходит следующим образом: Задав атрибуты с помощью функции

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.
Привожу несложный пример.

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 и пишем такой код.

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 Вашей материнской платы.
Используя данные функции Вы легко получаете возможность просмотра всего объёма физической памяти, за исключением системных адресов операционной системы.

Copyright© 2006 Альберт Мамедов (MagDelphi) Специально для Delphi Plus

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...