Reputation: 23
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
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