user3092064
user3092064

Reputation: 23

Delphi get processes memory range

I want to get all procceses memory in delphi, but it does not work. The program enters in a infinite loop and it always displays "00000000 - 00000000". I want the program to output the base address and the region zise. Here is the code:

program dtest;
{$APPTYPE CONSOLE}


uses
  Windows,
  TLHelp32,
  SysUtils;

var
Snap: dword;
sysinfo : TSystemInfo;
Process: TPROCESSENTRY32;
Handle: THandle;
Mbi: TMemoryBasicInformation;
Addr: DWORD;
begin
   GetSystemInfo(sysinfo);
   Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   if Snap <> INVALID_HANDLE_VALUE then
   begin
   Process.dwSize := SizeOf(TPROCESSENTRY32);
   if Process32First(Snap, Process) then
   repeat
      Handle:=OpenProcess(PROCESS_VM_READ,false,Process.th32ProcessID);
      if Handle <> 0 then
      begin
         writeln(Process.szExeFile);
         Addr := DWORD(sysinfo.lpMinimumApplicationAddress);
         while (Addr < $80000000) do
         begin
             VirtualQueryEx(Handle, Ptr(Addr), Mbi, SizeOf(Mbi));
             write(inttohex(Integer(Mbi.BaseAddress), 8));
             write(Output,' - ');
             writeln(inttohex(Integer(Mbi.RegionSize), 8));
             Addr := Addr + Mbi.RegionSize;
         end;
         CloseHandle(Handle)
      end
   until not Process32Next(Snap, Process);
   CloseHandle(Snap);
   end;
   Sleep(9999);
end
.

Upvotes: 0

Views: 1092

Answers (1)

David Heffernan
David Heffernan

Reputation: 612934

Your first call to VirtualQueryEx where you pass nil fails. You are not performing error checking. The documentation states that VirtualQueryEx returns 0 when it fails. That is what is happening.

In this scenario, the Win32 error code retrieved from a call to GetLastError is ERROR_ACCESS_DENIED. Hardly surprising.

Now, when this happens, the values in Mbi are ill-defined. As it happens, RegionSize is 0 and so you enter an infinite loop.

There's no point incrementing Addr by anything less than the size of a single page. So I suggest that when VirtualQueryEx fails you do just that.

Now, the other major problem is that you are not reading the documentation carefully enough. It tells you that the process handle must include PROCESS_QUERY_INFORMATION. You have not supplied that flag. Clearly you will need to do so.

And you also need to watch out for pages that have a region size that implies they go beyond the end of the address space. I'm no expert but I think that these mark the top of the address space. When you encounter these you'll need to break out of the loop.

Finally, I would like to point out that all of this can readily be found be simply running the program under the debugger. You have an infinite loop. So study the program under the debugger and work out why the loop does not terminate. It will pay dividends for you to learn how to use the debugger tool. Oh, and reading the documentation, and always checking for errors when calling Win32 API functions is also essential!

This version of your program is better, but I've not even remotely debugged it. You'll need to polish it up:

{$APPTYPE CONSOLE}

uses
  Windows,
  TLHelp32,
  SysUtils;

var
  Snap, err: dword;
  sysinfo: TSystemInfo;
  Process: TPROCESSENTRY32;
  Handle: THandle;
  Mbi: TMemoryBasicInformation;
  Addr: dword;

begin
  GetSystemInfo(sysinfo); // no error checking here either!
  Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Snap <> INVALID_HANDLE_VALUE then
  begin
    Process.dwSize := SizeOf(TPROCESSENTRY32);
    if Process32First(Snap, Process) then
    begin
      repeat
        Handle := OpenProcess(PROCESS_QUERY_INFORMATION, false,
          Process.th32ProcessID);
        if Handle <> 0 then
        begin
          writeln(Process.szExeFile);
          Addr := dword(sysinfo.lpMinimumApplicationAddress);
          while (Addr < $80000000) do
          begin
            if VirtualQueryEx(Handle, Ptr(Addr), Mbi, SizeOf(Mbi)) = 0 then
            begin
              err := GetLastError;
              inc(Addr, sysinfo.dwPageSize);
              continue;
            end;
            write(inttohex(Integer(Mbi.BaseAddress), 8));
            write(Output, ' - ');
            writeln(inttohex(Integer(Mbi.RegionSize), 8));
            if Addr + Mbi.RegionSize < Addr then
              break;
            Addr := Addr + Mbi.RegionSize;
          end;
          CloseHandle(Handle)
        end
      until not Process32Next(Snap, Process);
      CloseHandle(Snap);
    end;
  end;
  Readln;
end.

Upvotes: 3

Related Questions