Архив блога Delphi. Поиск в памяти процесса
Поиск в памяти процесса
// Поиск значения типа DWORD в указанном процессе
// [email protected]
program
search;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils;
var
ProcessID: DWord
;
ProcessHandle: THandle
;
Mbi: TMemoryBasicInformation;
Addr
: DWord
;
Value: DWord
;
I: Cardinal
;
Buf: PChar
;
BytesRead: DWord
;
begin
if
ParamCount
< 2
then
begin
WriteLn
("Usage: search.exe processid value"
)
;
Exit
;
end
;
ProcessID:= StrToInt
(ParamStr
(1
)
)
;
WriteLn
("Process id: "
+ IntToStr
(ProcessID)
)
;
Value:= StrToInt
(ParamStr
(2
)
)
;
WriteLn
("Value to search: "
+ IntToStr
(Value)
)
;
// Открываем процесс
ProcessHandle:= OpenProcess(PROCESS_QUERY_INFORMATION or
PROCESS_VM_READ or
PROCESS_VM_OPERATION, false
, ProcessID)
;
if
ProcessHandle <> 0
then
try
Addr
:= 0
;
// Перечисляем все регионы виртуальной памяти процесса
while
VirtualQueryEx(ProcessHandle, Pointer
(Addr
)
, Mbi, SizeOf
(Mbi)
)
<> 0
do
begin
// Uncomment чтобы увидеть список регионов, найденых в адресном пространстве
// WriteLn("region: " + IntToHex(Integer(Mbi.BaseAddress), 8) +
// " size: " + IntToStr(Mbi.RegionSize));
// Если региону выделена память, и регион не является "сторожевым" (как вершина стека),
// то читаем этот регион
if
(Mbi.State
= MEM_COMMIT)
and
not
((Mbi.Protect
and
PAGE_GUARD)
= PAGE_GUARD)
then
begin
// Это демонстрационная программа, поэтому здесь выделяется буфер под весь регион.
// Регион может быть достаточно большим, поэтому лучше читать его блоками для экономии
// памяти. Но здесь для простоты алгоритма вся оптимизация похерена.
GetMem
(Buf, Mbi.RegionSize
)
;
try
// Читаем весь регион в выделенный буфер
if
ReadProcessMemory(ProcessHandle, Mbi.BaseAddress
, Buf,
Mbi.RegionSize
, BytesRead)
then
begin
// Ищем значение типа DWORD в буфере
for
I:= 0
to
BytesRead - SizeOf
(Value)
do
begin
if
PDWord
(@Buf[
I]
)
^ = Value then
// Найдено, выводим
WriteLn
("Value "
+ IntToStr
(Value)
+ " found at "
+
IntToHex
(Integer
(Cardinal
(Mbi.BaseAddress
)
+ I)
, 8
)
)
;
end
;
end
else
WriteLn
("Failed to read process memory "
+ IntToStr
(GetLastError
)
)
;
finally
FreeMem
(Buf)
;
end
;
end
;
// Вычисляем адрес следуюшего региона
Addr
:= Addr
+ Mbi.RegionSize
;
end
;
finally
CloseHandle(ProcessHandle)
;
end
else
WriteLn
("Failed to open process"
)
;
end
.
А вот программа, в которой ведем поиск для примера:
program
someprog;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
SomeValue: Integer
;
begin
SomeValue:= 12345
;
WriteLn
("One variable of this program has a value "
+ IntToStr
(SomeValue)
)
;
WriteLn
("Press any key to exit"
)
;
ReadLn
;
end
.
Чтобы вам не тратить половину жизни на разобраться - в этой статье я принесу всё на блюдечке.
Темы этой статьи в разной степени уже не раз затрагивались в этом блоге, но в этой статье они собраны в кучу, приведены обоснования. Короче, ссылкой на эту статью можно кидаться в тех, кто разрабатывает DLL.
Важное примечание : статью нужно читать последовательно . Примеры кода приводятся только как примеры , на каждом шаге (пункте) статьи код примеров добавляется новыми подробностями. Например, в самом начале статьи нет обработки ошибок, указываются "классические" способы (типа, использования GetLastError , соглашения sdtcall и т.д.), которые по ходу статьи заменяются на более адекватные. Сделано так по той причине, чтобы "новые" ("необычные") конструкции не вызывали вопросов. Иначе при пришлось бы к каждому примеру вставлять примечание вида: "вот это обсуждается в том пункте ниже, а вот то - в этом вот". В любом случае в конце статьи есть ссылка на уже готовый код, написанный с учётом всего сказанного в статье. Можете просто его брать и использовать. А статья объясняет зачем и почему. Если вам не интересно "зачем и почему" - листайте в конец к заключению и ссылке на скачивание примера.
Отображение файла в память для совместного использования несколькими процессами.
Первый процесс создает файл Temp.txt, после чего проецирует его в память
//первый процесс
unit mainServ;
Uses
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnCreate: TButton;
Memo1: TMemo;
procedure btnCreateClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
Private
{ Private declarations }
public
{ Public declarations }
end;
const
bufSize=100;//размер буфера
Var
Form1: TForm1;
hFile,hMapedFile:HWND;
pMapFile:Pointer;
//Создание именованной, совместно используемой памяти
procedure TForm1.btnCreateClick(Sender: TObject);
var
outBuff:array of Char;
byteWrt:Cardinal;
begin
UnmapViewOfFile(pMapFile);
if hMapedFile<>INVALID_HANDLE_VALUE then
CloseHandle(hMapedFile);
if (hFile<>INVALID_HANDLE_VALUE) then
CloseHandle(hFile);
hFile:=CreateFile(PWideChar("Temp.txt"),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil,CREATE_ALWAYS or OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0);
If hFile=INVALID_HANDLE_VALUE then
begin
ShowMessage("Ошибка при создании файла "+SysErrorMessage(GetLastError));
Exit;
end;
StrPCopy(outBuff,Memo1.Lines.Text);
WriteFile(hFile,outBuff,bufSize*SizeOf(Char),byteWrt,nil);
HMapedFile:=CreateFileMapping(hFile, //INVALID_HANDLE_VALUE-использование файла подкачки
nil, // защита по умолчанию
PAGE_READWRITE, //доступ к чтению/записи
0, // макс. размер объекта
bufSize*SizeOf(Char), // размер буфера
MMFName); // имя отраженного в памяти объекта
begin
CloseHandle(hFile);
Exit;
end;
pMapFile:=MapViewOfFile(hMapedFile, //дескриптор "проецируемого" объекта
FILE_MAP_ALL_ACCESS, // разрешение чтения/записи
0,0,
if pMapFile=nil then
begin
CloseHandle(hMapedFile);
CloseHandle(hFile);
Exit;
end;
end;
Procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if not Assigned(pMapFile) then
UnmapViewOfFile(pMapFile);
if hMapedFile<>INVALID_HANDLE_VALUE then
CloseHandle(hMapedFile);
if (hFile<>INVALID_HANDLE_VALUE) then
CloseHandle(hFile);end;
Второй процесс может получить доступ к одним и тем же данным при помощи вызова функции OpenFileMapping с тем же самым именем, что и первый процесс. Он может затем использовать функцию MapViewOfFile, чтобы получить указатель на представление данных файла.
//второй процесс
Unit clientMain;
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
Type
TForm1 = class(TForm)
btnRead: TButton;
Memo1: TMemo;
procedure btnReadClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
MMFName: PWideChar = "DelphiFileMappedExample"; // имя объекта файлового отображения
bufSize=100;//размер буфера
Var
Form1: TForm1;
Procedure TForm1.btnReadClick(Sender: TObject);
var
hMapedFile:HWND;
pMapFile:Pointer;
Begin
hMapedFile:=OpenFileMapping(FILE_MAP_ALL_ACCESS, // доступ к чтению/записи
False, //имя не наследуется
MMFName);//имя "проецируемого " объекта
If hMapedFile=INVALID_HANDLE_VALUE then
begin
ShowMessage("Ошибка при проецировании файла в память "+SysErrorMessage(GetLastError));
Exit;
end;
PMapFile:=MapViewOfFile(hMapedFile,//дескриптор "проецируемого" объекта
FILE_MAP_ALL_ACCESS,// разрешение чтения/записи
0,0,
bufSize*SizeOf(Char));//размер буфера
If pMapFile=nil then
begin
ShowMessage("Ошибка при отображении файла "+SysErrorMessage(GetLastError));
CloseHandle(hMapedFile);
Exit;
end;
Memo1.Text:=PChar(pMapFile);
UnmapViewOfFile(pMapFile);
CloseHandle(hMapedFile);
end;
Когда процессу больше не нужен доступ к объекту "проекция файла в память", он должен вызвать функцию CloseHandle. Когда все дескрипторы закрыты, система может освободить секцию файла подкачки, используемого объектом.
Скачать проекты можно