[Delphi] GetMem & ReadProcessMemory vraagje

Pagina: 1
Acties:
  • 127 views sinds 30-01-2008
  • Reageer

  • Stuff
  • Registratie: November 2000
  • Laatst online: 28-06-2010

Stuff

*ploink*

Topicstarter
Gegroet,

Ik ben bezig met het maken van een trainer in Delphi. Ik heb dit nog niet eerder gedaan en het leek mij een leuke oefening, maar nu loop ik toch echt vast.

Wat is de bedoeling: Ik wil een programma maken die het geheugen range van een ander programma kan doorzoeken en daarin eventueel waardes kan veranderen.

Ik ben zover dat ik een lijst krijg van draaiende processen (Win98 trouwens) en dat ik zo'n process kan selecteren. Ik heb de PID en alle andere nodige informatie om de Process te openen. het openen van een Process doe ik als volgt:

ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);
HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);

Nu wil ik met ReadProcessMemory het geheugen uitlezen, maar dit lukt mij niet. Wellicht kijk ik ergens overheen, of zit ik veels te moelijk te doen, maar hoe krijg ik het begin adres van zo'n process? (Voor ReadProcessMemory dus.. het gaat om de "BaseAddress").

Heeft iemand toevallig hier nog een tutorial van liggen of weet iemand een linkje waar er wat meer over uitgelegd word?

Elke suggestie is welkom. :)

Alvast bedankt voor de moeite. Maar ik ga nu lekker naar bed en kom daar voor 12:00 dus mooi niet uit. :o) (Het is weekend, ff lekker uitslapen).

http://www.vado.org -- Videogames are a conduit for the soul. They expand our lives, channel our imagination, test our skillz. Games exist as a channel for the boundless energy of people all over the world. -MegaTokyo


  • Stuff
  • Registratie: November 2000
  • Laatst online: 28-06-2010

Stuff

*ploink*

Topicstarter
Het antwoord heb ik inmiddels gevonden, danzij Madshi op Expert-Exchange.com. Voor de volledigheid post ik het antwoord hier ook nog even. :)

Basically each process has a full memory range from $00000000 - $FFFFFFFF (in win9x only $7FFFFFFF). The executable is usually (but not always) loaded at $400000, the modules are usually loaded at higher addresses. The application can allocate memory, which can be *anywhere* in that memory/address range. You can use VirtualQueryEx to ask which memory area is readable in the other process, then you can use ReadProcessMemory to read the readable parts of the other process. But be prepared: That will be some megabytes!

Regards, Madshi.

http://www.vado.org -- Videogames are a conduit for the soul. They expand our lives, channel our imagination, test our skillz. Games exist as a channel for the boundless energy of people all over the world. -MegaTokyo


Verwijderd

Omdat ik dit wel een interessant probleem vind, en omdat ik niet zoveel te doen had :) heb ik effe een voorbeeldje gemaakt:

Kleine beschrijving:

Dit programma past een constante waarde in het programma aan dmv API calls. Dit werkt btw niet op Windows NT geloof ik omdat ik gebruik maak van de Tool Help Library.

We maken dus gebruik van de Tool Help Library
code:
1
2
uses
  TLHelp32;

Ik gebruik de API's CreateToolhelp32Snapshot, Process32First, Process32Next, Module32First, Module32Next om een MODULEENTRY32 struct te vinden van een bepaalde executable. Hierin staan dan weer een process ID en een base adress van het process.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
function FindProcess(const AExeFile: string; var ProcessEntry: TProcessEntry32):
Boolean;
var
  SnapShotHnd: THandle;
begin
  Result := False;
  SnapShotHnd := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if SnapShotHnd <> INVALID_HANDLE_VALUE then
  try
    ProcessEntry.dwSize := SizeOf(TProcessEntry32);
    if Process32First(SnapShotHnd, ProcessEntry) then
    repeat
      Result := ProcessEntry.szExeFile = AExeFile;
      ProcessEntry.dwSize := SizeOf(TProcessEntry32);
    until Result or not Process32Next(SnapShotHnd, ProcessEntry);
  finally
    CloseHandle(SnapShotHnd);
  end;
end;

function FindModule(const AExeFile: string; var ModuleEntry: TModuleEntry32):
Boolean;
var
  SnapShotHnd: THandle;
  ProcessEntry: TProcessEntry32;
begin
  Result := False;
  if FindProcess(AExeFile, ProcessEntry) then
  begin
    SnapShotHnd := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
    ProcessEntry.th32ProcessID);
    if SnapShotHnd <> INVALID_HANDLE_VALUE then
    try
    ModuleEntry.dwSize := SizeOf(TModuleEntry32);
    if Module32First(SnapShotHnd, ModuleEntry) then
      repeat
        Result := ModuleEntry.th32ModuleID = ProcessEntry.th32ModuleID;
        ModuleEntry.dwSize := SizeOf(TModuleEntry32);
      until Result or not Module32Next(SnapShotHnd, ModuleEntry);
    finally
    CloseHandle(SnapShotHnd);
    end;
  end;
end;

Als we een handle naar een process hebben, en een base address van dat process hebben, kunnen we in dit stuk geheugen gaan zoeken:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
function FindStringInMemory(AProcessHandle: THandle; const ABaseAddress:
  PChar; const ASize: Integer; const S: string; var Address_S: PChar): Boolean;
var
  Buffer: array[0..200] of Char;
  NrRead: DWORD;
  TotalRead: Integer;
  DoubleCheckSize: Integer;

  function FindIt(const ASearchSize: Integer; var APos: Integer): Boolean;
  var
    Count: Integer;
  begin
    APos := 0;
    Count := 0;
    Result := False;
    while not Result and (APos < ASearchSize) do
    begin
    if Buffer[APos] = S[Count + 1] then
      Inc(Count)
    else
    begin
      APos := APos - Count;
      Count := 0;
    end;
    Result := Count = DoubleCheckSize + 1;
    if Result then
      Dec(APos, DoubleCheckSize)
    else
      Inc(APos);
    end;
  end;
var
  PosInBuffer: Integer;
begin
  FillChar(Buffer, SizeOf(Buffer), #0);
  DoubleCheckSize := Length(S) - 1;
  Result := False;
  TotalRead := 0;

  while not Result and (TotalRead < ASize) do
  begin
    if not ReadProcessMemory(AProcessHandle, ABaseAddress + TotalRead,
    PChar(@Buffer) + DoubleCheckSize, SizeOf(Buffer) - DoubleCheckSize, NrRead)
      then Exit;
    if NrRead = 0 then Exit;
    Result := FindIt(DoubleCheckSize + Integer(NrRead), PosInBuffer);
    if Result then
    Address_S := ABaseAddress + TotalRead + PosInBuffer - DoubleCheckSize
    else
    begin
    Move((PChar(@Buffer) + NrRead)^, Buffer, DoubleCheckSize);
    Inc(TotalRead, NrRead);
    end;
  end;
end;

En nog een procedure om een stukje geheugen te veranderen:
code:
1
2
3
4
5
6
7
8
procedure WriteStringInMemory(AProcessHandle: THandle; const AAddress:
  PChar; const S: string);
var
  NrWritten: DWORD;
begin
  WriteProcessMemory(AProcessHandle, AAddress, PChar(S), Length(S) + 1,
    NrWritten);
end;

Deze functie maakt gebruik van een mbv FindModule gevonden MODULEENTRY32 struct, om een stuk geheugen te veranderen.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function ModifyStringInModule(ModuleEntry: TModuleEntry32; const OldString,
  NewString: string): Boolean;
var
  ProcessHandle: THandle;
  OldStringAddress: PChar;
begin
  Result := False;
  ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False,
    ModuleEntry.th32ProcessID);
  if ProcessHandle <> INVALID_HANDLE_VALUE then
  try
    Result := FindStringInMemory(ProcessHandle, PChar(ModuleEntry.modBaseAddr),
    ModuleEntry.modBaseSize, OldString, OldStringAddress);
    if Result then
    WriteStringInMemory(ProcessHandle, OldStringAddress, NewString);
  finally
    CloseHandle(ProcessHandle);
  end;
end;

Deze constanten willen we veranderen:
code:
1
2
const
  CValue = 'Atjemenou';

Met een button click voeren we alle code uit:
code:
1
2
3
4
5
6
7
8
9
10
11
procedure TForm1.Button1Click(Sender: TObject);
var
  ModuleEntry: TModuleEntry32;
begin
  if FindModule(Application.ExeName, ModuleEntry) then
  begin
    ShowMessage(CValue);
    ModifyStringInModule(ModuleEntry, 'Atjemenou', 'abcdefghi');
    ShowMessage(CValue);
  end;
end;

En dat was die :)