Witam,
od paru dni męczę się próbując wykombinować sposób, aby przeszukać pamięć procesu w celu odnalezienia pewnych wartości - głównie string.
Przeszukałem masę stron dotyczących
VirtualQueryEx
oraz ReadProcessMemory
, lecz na żadnej z tych stron nie znalazłem oczekiwanego rezultatu.
Widziałem, że kiedyś Olesio się interesował DUMP-em pamięci procesu do pliku i nawet podał sposób wyszukiwania który jest w miarę ok, lecz tyczy się on tylko niewielkiej ilości zakresu przeszukiwania pamięci. Mnie interesuje obszar od
```delphi
$400000
do
$7FFFFFFF
.
Obecnie kod wygląda tak:
```delphi
function ReadBufferFromMemory(Ad, Size: integer; var MB: TMemBlock): Cardinal;
var
Cnt : Cardinal;
begin
ReadProcessMemory(hPRocess, Pointer(Ad), @MB[0], Size, Cnt);
ReadBufferFromMemory := Cnt;
end;
var
St : TBytes6;
StCount : word;
BytesRead : Cardinal;
Sad, Ead, Ad : Cardinal;
X, Y, Z : Cardinal;
Found : Boolean;
MemBlock : TMemBlock;
MemStr : TMemoryStream;
Temp : array[1..1024] of Byte;
i, j: integer;
adress: integer;
const
WindowClass = 'Nazwa klasy okna';
begin
{ St[0] := $74;
St[1] := $6F;
St[2] := $6D;
St[3] := $61;
St[4] := $73;
St[5] := $7A;
St[6] := $2E;
St[7] := $6F;
St[8] := $70;
St[9] := $79;
St[10] := $64; }
st[0]:=$90; //in asm this means: nop
st[1]:=$90;
st[2]:=$90;
st[3]:=$90;
st[4]:=$90;
st[5]:=$90;
StCount := 6;
Sad := ($00400000);
Ead := ($7FFFFFFF);
Ad := Sad;
Found := False;
MemStr := TMemoryStream.Create;
WindowH := FindWindow(WindowClass, nil);
GetWindowThreadProcessId(WindowH, @ProcessId);
if WindowH = 0 then
begin
ShowMessage('Nie uruchomiono procesu o klasie okna: ' + WindowClass);
Exit;
end;
hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessId);
I := 0;
for adress := Sad to Ead -1 do
begin
repeat
ReadProcessMemory(hProcess, Ptr(adress + i + 1000), @Temp, SizeOf(Temp), BytesRead);
// RichLog.Lines.Append(IntToHex(Sad + i, 8));
MemStr.Write(Temp, SizeOf(Temp));
I := I + BytesRead;
until BytesRead = 0;
MemStr.SaveToFile('E:\Viking\Debug\Win32\dump\memstr.txt');
RichLog.Lines.Append(IntToHex(adress + i, 8));
end;
{ repeat
BytesRead := ReadBufferFromMemory(Ad, BUFFMAX, MemBlock);
if BytesRead = 0 then
Break;
RichLog.Lines.Append(IntToHex(Integer(ad), 8));
if BytesRead = BUFFMAX then
BytesRead := BytesRead - StCount;
for X := 0 to BytesRead - 1 do
begin
Found := True;
for Y := 0 to StCount - 1 do
if MemBlock[X + Y] <> St[Y] then
begin
Found := False;
Break;
end;
if Found then
begin
Z := Ad + X + Y - StCount;
RichLog.Lines.Append(IntToHex(Z, 8));
//ShowMessage('Ciąg bajtów znaleziono pod adresem: ' + IntToHex(Z, 6));
Break;
end;
end;
Ad := Ad + BytesRead;
MemStr.write(MemBlock, SizeOf(MemBlock));
until (Ad >= Ead); }
MemStr.SaveToFile('E:\Viking\Debug\Win32\dump\memstr.txt');
MemStr.Free;
ShowMessage('Koniec szukania.');
end;
Jest tu straszny bałagan ale to dlatego, że ciągle próbuję uzyskać jakiś lepszy efekt - niestety jak dotychczas bez powodzenia.
Od razu napiszę, że przeszukiwanie (w powyższym kodzie) pętlą
for
trwa wieki jeśli mam przeszukiwać cały obszar pamięci. Czy istnieje jakiś szybszy sposób? Przykładowo Cheat Engine robi to idealnie w krótkim czasie.
Jaki należy przyjąć schemat działania - zdumpować pamięć do pliku i w pliku szukać danej wartości, czy na bieżąco w kodzie analizować przychodzące dane... już nie mam sił do tego, jakieś konkretne kodowe podpowiedzi byłyby mile widziane.
Podaję również inne przykłady, może przybliżą Wam o co chodzi.
procedure ScanMem(start, ende: dword);
var
dwRead : DWORD;
iBuffer : integer;
adress : Integer;
begin
frmmain.lbl3.caption := 'start ' + Inttostr(start);
frmmain.lbl5.caption := 'ende ' + Inttostr(ende);
Application.ProcessMessages;
dwRead := 0;
iBuffer := 44112;
for adress := start to ende - 1 do
begin
ReadProcessMemory(memory.IDProcess, ptr(adress), @iBuffer, SizeOf(Integer), dwRead);
if iBuffer = 44112 then
frmMain.RichLog.Lines.Append(inttostr(start));
end;
end;
procedure GetMemMinMax;
var
mbi : TMemoryBasicInformation;
adress ,
start ,
ende : Cardinal;
begin
adress := $400000;
while adress < $7FFFFFFF do
begin
VirtualQueryEx(memory.IDProcess, ptr(adress), mbi, SizeOf(TMemoryBasicInformation));
if (mbi.State = MEM_COMMIT)
and (not (mbi.Protect = PAGE_GUARD)
or (mbi.Protect = PAGE_NOACCESS)) then
begin
start := DWORD(mbi.BaseAddress);
ende := DWORD(mbi.BaseAddress) + mbi.RegionSize;
ScanMem(start,ende); // als hex?
end;
adress := adress + mbi.RegionSize;
end;
// showmessage(ergebnis);
end;
Powyższy przykład wygląda fajnie, lecz nie robi tego co powinien.
var
APtr: Pointer;
Buffer: TMemoryBasicInformation;
Index: Integer;
MemoryStream: TMemoryStream;
FileStream: TFileStream;
hProcess: THandle;
BytesRead: DWord;
adress: dword;
start, ende: cardinal;
begin
APtr := nil;
Index := 0;
hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, memory.PID);
adress := $400000;
while adress < $7FFFFFFFF do
begin
VirtualQueryEx(hProcess, Ptr(adress), Buffer, SizeOf(TMemoryBasicInformation));
Inc(Index);
if (Buffer.State = MEM_COMMIT) and (not (Buffer.Protect = PAGE_GUARD)
or (Buffer.Protect = PAGE_NOACCESS)) and (Buffer.Protect = PAGE_READWRITE) then
begin
start := dword(Buffer.BaseAddress);
ende := dword(Buffer.BaseAddress) + Buffer.RegionSize;
MemoryStream := TMemoryStream.Create;
MemoryStream.Size := Buffer.RegionSize;
for adress := start to ende -1 do
begin
//for adress := start to ende -1 do
//begin
ReadProcessMemory(hProcess, Buffer.BaseAddress, @Buffer, 1000, BytesRead);
//if Buffer = 44112 then
frmMain.RichLog.Lines.Append(IntToHex(Integer(Buffer.BaseAddress), 8));
//end;
//frmMain.RichLog.Lines.Append(IntToHex(Integer(start), 8));
end;
FileStream := TFileStream.Create('E:\Viking\Debug\Win32\dump\memory_' + IntToHex(Integer(Buffer.BaseAddress), 8) + '_' + IntToHex(DWord(Buffer.BaseAddress) + Buffer.RegionSize, 8) + '.txt', fmCreate);
FileStream.CopyFrom(MemoryStream, 0);
FileStream.Free;
MemoryStream.Free;
end;
adress := adress + Buffer.RegionSize;
DWord(APtr) := DWord(APtr) + Buffer.RegionSize;
end;
ShowMessage(IntToStr(Index));
end;