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が役に立ちます。アドレスとサイズを指定すると、読みやすさが回復します。レイモンド・チェンは、それを決して使用しないことを提案しています。

それ以外に、VirtualQueryは、読みやすさを伝えるために、問題のアドレスに関する情報を提供する必要があります。

以下のコメントでケンは危険性について再警告したのでIsBadReadPtr、私はそれを通り過ぎないという答えに持っていきます。Raymdondのブログへのコメントとリンクを必ずお読みください。必ず参照してください:

于 2012-07-24T17:03:58.757 に答える