0

我有从外部进程注入的 DLL 调用的这段代码。它可以读取一些内存范围,但我有时会在这一行遇到分段错误DataBuffer := TCharPointer(Address + CharOffset)^;。那么有没有办法检查内存是否可读?

function GetCurrentData(Address: Pointer): PChar;
var
  DataBuffer: Char;
  CharArray: Array of Char;
  CharOffset: Integer;
  ReadBytes: longword;
begin
  CharOffset := 0;
  SetLength(CharArray, 0);
  repeat
    DataBuffer := TCharPointer(Address + CharOffset)^;
    CharOffset := CharOffset + 1;
    SetLength(CharArray, CharOffset);
    CharArray[CharOffset - 1] := DataBuffer;
  until (Ord(DataBuffer) = 0);
  Result := PChar(@CharArray[0]);
end;

我也试图捕捉异常,但由于某种原因这不起作用。主机程序仍然崩溃。

unit UnitEventBridgeExports;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Windows, ShellAPI, JwaTlHelp32, SimpleIPC;

type
  TCharPointer = ^Char;

const
  WOWEXE = 'TestProgramm.exe';

var
  IPCClient: TSimpleIPCClient;
  PID: DWord;
  Process: THandle;

procedure EventCalled;
procedure InitializeWoWEventBridge; stdcall;

implementation


function GetProcessIDByName(Exename: String): DWord;
var
  hProcSnap: THandle;
  pe32: TProcessEntry32;
begin
  Result := 0;
  hProcSnap := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
  if hProcSnap <> INVALID_HANDLE_VALUE then
  begin
    pe32.dwSize := SizeOf(ProcessEntry32);
    if Process32First(hProcSnap, pe32) = True then
    begin
      while Process32Next(hProcSnap, pe32) = True do
      begin
        if pos(Exename, pe32.szExeFile) <> 0 then
          Result := pe32.th32ProcessID;
      end;
    end;
    CloseHandle(hProcSnap);
  end;
end;


procedure InitializeEventBridge; stdcall;
begin
  IPCClient := TSimpleIPCClient.Create(nil);
  IPCClient.ServerID := 'EventBridgeServer';
  IPCClient.Active := True;
  IPCClient.SendStringMessage('init');
  PID := GetProcessIDByName(EXE);
  Process := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
end;


function GetCurrentData(Address: Pointer): PChar;
var
  DataBuffer: Char;
  CharArray: Array of Char;
  CharOffset: Integer;
  ReadBytes: longword;
  CharPointer: TCharPointer;
  BreakLoop: Boolean;
begin
  CharOffset := 0;
  SetLength(CharArray, 0);
  BreakLoop := False;
  repeat
    try
      CharPointer := TCharPointer(Address + CharOffset);
      DataBuffer := CharPointer^;
      CharOffset := CharOffset + 1;
      SetLength(CharArray, CharOffset);
      CharArray[CharOffset - 1] := DataBuffer;
    except
      BreakLoop := True;
    end;
  until (Ord(DataBuffer) = 0) or BreakLoop;
  Result := PChar(@CharArray[0]);
end;


procedure EventCalled;
var
  TmpAddress: Pointer;
  StringData: PChar;
begin
  {$ASMMODE intel}
  asm
    mov [TmpAddress], edi
  end;
  StringData := GetCurrentData(TmpAddress);
  IPCClient.SendStringMessage('update:' + StringData);
  //IPCClient.SendStringMessage('update');
end;

end.
4

2 回答 2

2

您的GetCurrentData()实现正在返回一个指向本地数组的指针,该数组在函数退出时超出范围,然后EventCalled()在它不再有效后尝试使用该指针。试试这个:

function GetCurrentData(Address: Pointer): AnsiString; 
var 
  Offset: Integer; 
begin 
  Result := '';
  Offset := 0; 
  repeat 
    try 
      if PByte(Longint(Address) + Offset)^ = #0 then Break;
      Inc(Offset); 
    except 
      Break; 
    end; 
  until False; 
  SetString(Result, PAnsiChar(Address), Offset); 
end; 

procedure EventCalled; 
var 
  TmpAddress: Pointer; 
  StringData: AnsiString; 
begin 
  {$ASMMODE intel} 
  asm 
    mov [TmpAddress], edi 
  end; 
  StringData := GetCurrentData(TmpAddress); 
  IPCClient.SendStringMessage('update:' + StringData); 
  //IPCClient.SendStringMessage('update'); 
end; 
于 2012-07-24T20:03:24.737 回答
1

IsBadReadPtrAPI 可以为您提供帮助。你给出地址和大小,你就可以恢复可读性。Raymond Chen建议不要使用它

除此之外,VirtualQuery应该为您提供有关地址的信息,以说明其可读性。

由于肯在下面的评论中重新警告了 的危险IsBadReadPtr,因此我提出了不要错过的答案。请务必阅读 Raymdond 博客的评论和链接。一定要看看:

于 2012-07-24T17:03:58.757 回答