Архив блога 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?", "Как передать и вернуть массив записей?", "Как передать в DLL форму?".

Чтобы вам не тратить половину жизни на разобраться - в этой статье я принесу всё на блюдечке.

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

Скачать проекты можно