views:

465

answers:

6

Is there a way to (read-only) access any arbitrary memory location without running into an access violation? I thought that each process has its own virtual adress space and that it can read all available memory locations...seems not to be the case, since my program hangs if I do something like

var
  IntPtr : PInteger;
  AnInteger : Integer;
...
IntPtr := $100;
AnInteger := IntPtr^;

I'm still trying to write my low-level recursive size-of function and try to detect if a data member is an object reference or not.

Thanks!

+1  A: 

Unless there is some Magic way that I'm unaware of, I'm pretty sure you can't do this. Windows uses protected memory, which means that you can't access anything that hasn't been specifically allocated to you.

There is DMA, but it's reserved for driver-level software.

Tim Sullivan
DMA has nothing to do with this, it's for transferring data between peripherals and memory without straining the CPU.
efficientjelly
+2  A: 

Memory might not be mapped at all adresses. And the lower 4kb or so are always protected afaik.

However if it is for VMs, if you control the memory manager, you can build up a list with all memory ranges that your application mapped.

Marco van de Voort
+4  A: 

You can only access your own process' memory via pointers, and even then it's only those parts that have been mapped for your process. There are debugger hooks that will give you access to other processes memory; but they're tricky to get right.

So if you really want to iterate through your process memory, you can probably find the functions that you need here: http://msdn.microsoft.com/en-us/library/ms878234.aspx

AFAIR in windows also part of kernel is mapped to your processes memory space (which is the reason to not have all of 4G available for your process).

Pasi Savolainen
+4  A: 

Your application hangs? There is something wrong with your application then. Usually, there will be a simple AV. An AV leads to error message. That is all.

BTW, you should not be scared of it - just handle it.

function IsValidObject(const AObj: Pointer { or TObject} ): Boolean;
begin
  try
    ...
    // place your checking code there
    Result := ...;
  except
    on EAccessViolation do
      Result := False;
  end;
end;

The only exception to this rule that comes to mind is if you're writing some sort of exception handler and want to detect if there is a valid object. In that case you probably do not want to generate an exception in handler of exception ;)

If this is your case - then try to use this code (this is an example):

function GetReadableSize(const AAddress: Pointer; const ASize: Cardinal): Cardinal;
const
  ReadAttributes = [PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE];
var
  MemInfo: TMemoryBasicInformation;
  Tmp: Cardinal;
begin
  Result := 0;
  if (VirtualQuery(AAddress, MemInfo, SizeOf(MemInfo)) = SizeOf(MemInfo)) and
     (MemInfo.State = MEM_COMMIT) and (MemInfo.Protect in ReadAttributes) then
  begin
    Result := (MemInfo.RegionSize - (Cardinal(AAddress) - Cardinal(MemInfo.BaseAddress)));
    if Result < ASize then
    begin
      repeat
        Tmp := GetReadableSize(Pointer(DWord(MemInfo.BaseAddress) + MemInfo.RegionSize), (ASize - Result));
        if (Tmp > 0) then
          Inc(Result, Tmp)
        else
          Result := 0;
      until (Result >= ASize) or (Tmp = 0);
    end;
  end;
end;

function IsValidBlockAddr(const AAddress: Pointer; const ASize: Cardinal): Boolean;
begin
  Result := (GetReadableSize(AAddress, ASize) >= ASize);
end;

But usually you should prefer first approach.

Alexander
I need some time to have a closer look at your second code sample, but one note: I don't get an access violation (you're right), but the operation dereferencing the pointer takes forever. It's like when I dereference a nil pointer...
Smasher
I think that you are seeing something else :( The hang at IntPtr^ looks VERY strange.Do you use any exception hooks? May be your stack was corrupted?
Alexander
+1  A: 

In old Windows, 95, 98, Me you could do some inline asm in your function and read/write some arbitrary memory location or hardware port...

function ReadPortByte : Byte; var Base : Word; begin Base := FAddress; asm mov DX, Base in AL, DX mov Result, AL end; end;

You can still do this by using a device driver, but Vista may cause you some problems unless the driver is compiled properly for Vista and above.

There are several free ones out there and worth experimenting with.

John

+2  A: 

If you want to safely try reading any memory address with no fuss, and get a nice error-code rather than an exception when the memory you're trying to read is inaccessible, the function you want to use is in the WinAPI: ReadProcessMemory.