В процессе написания программного обеспечения в ряде случаев возникает необходимость получения данных из физических ячеек памяти. Документации Delphi по данному вопросу, я найти не смог, поэтому хочу восполнить данный пробел.
Платформа WinNT(XP) не допускает возможность непосредственного доступа к памяти средствами Win32API. В этом случае программист должен или написать свой драйвер доступа к физической памяти или использовать native kernel32
функции ядра.
Рассмотрим второй вариант использующий объект "проекция файла" (file-mapping object),
представляющем собой блок памяти(раздел) доступный двум и более процессам для совместного использования.
Совместное использование данных с помощью объекта "раздел" происходит следующим образом: Задав атрибуты с помощью функции
которая фактически заполняет структуру NtObjectAttributes
Используем объект 'DevicePhysicalMemory'
и преобразовав его в тип TNtUnicodeString;
RtlInitAnsiString(@AnsiPhysicalMemory,
'DevicePhysicalMemory');
RtlAnsiStringToUnicodeString(@UniPhysicalMemory,
@AnsiPhysicalMemory, true);
InitializeObjectAttributes(@NtObjectAttributes,
@UniPhysicalMemory, OBJ_KERNEL_HANDLE, 0, nil); Получаем дескриптор секции вызывая функцию ядра
NtOpenSection(SectionHandle,
SECTION_MAP_READ, @NtObjectAttributes); Этим самым мы открываем объект 'DevicePhysicalMemory'
для чтения отображенного участка физической памяти в процессе пользователя. Отображение осуществляем с помощью функции 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, 'DevicePhysicalMemory'); 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 Вашей материнской платы.
Используя данные функции Вы легко получаете возможность просмотра всего объёма физической памяти, за исключением системных адресов операционной системы.
Статья обсуждает использование natives функций kernel32 в Delphi для получения проекции физической памяти. Автор предлагает пример кода, демонстрирующий, как открыть секцию физической памяти, отобразить ее в адресном пространстве процесса и прочитать данные из нее.
Статья начинается с объяснения, что прямой доступ к физической памяти не возможен под Windows NT (XP) из-за ограничений безопасности. Вместо этого автор рекомендует использовать объект "проекционный файл", который представляет собой блок памяти, который может быть общим для нескольких процессов.
Пример кода, предоставленный в статье, включает функции открытия и отображения физической памяти, а также пример приложения на основе формы, позволяющего пользователям прочитать данные из физической памяти. Приложение использует компонент StringGrid для отображения прочитанных данных в табличном формате.
Некоторые важные точки из статьи:
Автор использует функцию NtOpenSection для открытия секции физической памяти.
Функция NtMapViewOfSection используется для отображения секции физической памяти в адресном пространстве процесса.
Функции RtlAnsiStringToUnicodeString и RtlInitAnsiString используются для конвертации между строками ANSI и Unicode.
Функция InitializeObjectAttributes используется для инициализации структуры атрибутов объекта.
Приложение использует компонент TStringGrid для отображения прочитанных данных в табличном формате.
В целом, статья предоставляет полный пример использования natives функций kernel32 в Delphi для доступа к физической памяти. Однако важно отметить, что доступ к физической памяти может быть сложным и потенциально опасным операцией, и необходимо проявлять осторожность при работе с ней.
получение данных из физических ячеек памяти с помощью объекта "проекция файла" и функций ядра Windows.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.