3

有没有办法(只读)访问任意内存位置而不会遇到访问冲突?我认为每个进程都有自己的虚拟地址空间,并且它可以读取所有可用的内存位置......似乎并非如此,因为如果我执行类似的操作,我的程序就会挂起

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

我仍在尝试编写我的低级递归大小函数并尝试检测数据成员是否是对象引用。

谢谢!

4

6 回答 6

5

您只能通过指针访问您自己的进程的内存,即使那样它也只是那些已为您的进程映射的部分。有调试器钩子可以让你访问其他进程的内存;但他们很难做到正确。

所以如果你真的想遍历你的进程内存,你可以在这里找到你需要的函数:http: //msdn.microsoft.com/en-us/library/ms878​​234.aspx

Windows中的AFAIR也将内核的一部分映射到您的进程内存空间(这就是您的进程没有所有4G可用的原因)。

于 2009-05-04T14:50:30.260 回答
4

您的应用程序挂起?那么你的应用程序有问题。通常,会有一个简单的 AV。AV 导致错误消息。就这些。

顺便说一句,你不应该害怕它 - 只是处理它。

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

想到此规则的唯一例外是,如果您正在编写某种异常处理程序并想要检测是否存在有效对象。在这种情况下,您可能不想在异常处理程序中生成异常;)

如果这是您的情况 - 然后尝试使用此代码(这是一个示例):

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;

但通常你应该更喜欢第一种方法。

于 2009-05-04T14:51:38.913 回答
3

如果您想安全地尝试读取任何内存地址而不大惊小怪,并在您尝试读取的内存不可访问时获得一个很好的错误代码而不是异常,那么您要使用的函数在 WinAPI 中:ReadProcessMemory

于 2009-05-05T09:48:18.183 回答
2

内存可能不会在所有地址上映射。并且较低的 4kb 左右总是受到保护 afaik。

但是,如果是针对 VM,如果您控制内存管理器,则可以建立一个列表,其中包含应用程序映射的所有内存范围。

于 2009-05-04T14:48:45.753 回答
1

在旧 Windows、95、98、Me 中,您可以在函数中执行一些内联​​ asm 并读/写一些任意内存位置或硬件端口...

函数 ReadPortByte :字节;var Base : 单词;开始 Base := FAddress; asm mov DX, Base in AL, DX mov 结果, AL end; 结尾;

您仍然可以通过使用设备驱动程序来做到这一点,但除非驱动程序为 Vista 及更高版本正确编译,否则 Vista 可能会给您带来一些问题。

有几个免费的,值得尝试。

约翰

于 2009-05-04T15:47:59.823 回答
1

除非有一些我不知道的魔法方式,否则我很确定你不能这样做。Windows 使用受保护的内存,这意味着您无法访问尚未专门分配给您的任何内容。

有 DMA,但它是为驱动程序级软件保留的。

于 2009-05-04T14:32:27.870 回答