Szukanie array of bytes w innym procesie

0

Witam.

Co w tym kodzie jest nie tak?:

const
  Target: array[0..4] of byte = ($6E, $69, $63, $6F); 
var
  Mbi: TMemoryBasicInformation;
  Handle: THandle;
  buff: array of byte;
  hWin, ProcID, BuffSize: Cardinal;
  Addr: DWORD_PTR;
  BytesRead: NativeUInt;
  i: integer;
begin
  hWin := FindWindow(nil, 'TestSft');
  if hWin > 0 then
    GetWindowThreadProcessID(hWin, @ProcId);
  if ProcId > 0 then
  begin
    Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, ProcId);
    if Handle <> 0 then
    begin
      while (VirtualQueryEx(Handle, Ptr(Addr), Mbi, SizeOf(Mbi)) <> 0) do
      begin
        SetLength(buff, BuffSize);
        if ReadProcessMemory(Handle, Mbi.BaseAddress, Buff, Mbi.RegionSize, BytesRead) then
        begin
          for i := 0 to Length(Buff) do
          if CompareMem(@Buff[i], @Target[1], Length(Target)) then
          begin
            ShowMessage('Found');
          end;
        end;
        if Addr + BuffSize < Addr then
          break;
        Addr := Addr + BuffSize;
      end;
      SetLength(buff, 0);
      CloseHandle(Handle);
    end;
  end;
end;

Odpowiedzią programu na kliknięcie w button jest "Out of memory".
Proszę o pomoc. Dziękuję.

0

4 bajtami nie namierzysz tablicy, bo będzie ich z 1000 w całej aplikacji.

koło 20-30 bajtów na takie szukanie starczy :)

1

Nie inicjalizujesz BuffSize.

0

W takim razie jest tak:

procedure TForm1.Button3Click(Sender: TObject);
const
  Target: array[0..4] of byte = ($6E, $69, $63, $6F); 
  BufSize = 1024*4;
var
  Mbi: TMemoryBasicInformation;
  Handle: THandle;
  buff: array of byte;
  hWin, ProcID, BuffSize: Cardinal;
  Addr: DWORD_PTR;
  BytesRead: NativeUInt;
  i: integer;
begin
BuffSize:= 1024*4 + SizeOf(Target);
  hWin := FindWindow(nil, 'TestSft');
  if hWin > 0 then
    GetWindowThreadProcessID(hWin, @ProcId);
  if ProcId > 0 then
  begin
    Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, ProcId);
    if Handle <> 0 then
    begin
      while (VirtualQueryEx(Handle, Ptr(Addr), Mbi, SizeOf(Mbi)) <> 0) do
      begin
        SetLength(buff, BuffSize);
        if ReadProcessMemory(Handle, Mbi.BaseAddress, Buff, Mbi.RegionSize, BytesRead) then
        begin
          for i := 0 to Length(Buff) do
          if CompareMem(@Buff[i], @Target[1], Length(Target)) then
          begin
            ShowMessage('Found');
          end;
        end;
        if Addr + BuffSize < Addr then
          break;
        Addr := Addr + BuffSize;
      end;
      SetLength(buff, 0);
      CloseHandle(Handle);
    end;
  end;
end;

Po użyciu buguje mi cały program. Albo coś zrobiłem źle, albo za dużo arrays jest w tym zewnętrznym programie do sprawdzenia.

0

Co to znaczy „buguje” i w którym miejscu?

Ile wynosi Mbi.RegionSize i po co w takim razie ustawiasz rozmiar bufora na jakieś dziwne 1024*4 + SizeOf(Target)?

1

Tak w ciemno tylko patrząc na kod bez użycia debuggera, który zapewne jest Ci obcy zmień:

SetLength(buff, BuffSize);

na:

SetLength(buff, Mbi.RegionSize);

tu też trochę lipa:

          for i := 0 to Length(Buff) do
          if CompareMem(@Buff[i], @Target[1], Length(Target)) then
          begin
            ShowMessage('Found');
          end;

bezpieczniej:

          for i := 0 to Length(Buff)  - Length(Target) do
          if CompareMem(@Buff[i], @Target[1], Length(Target)) then
          begin
            ShowMessage('Found');
          end;

Kiedy ten warunek będzie spełniony? BuffSize będzie ujemne? Po co to?

        if Addr + BuffSize < Addr then
          break;

Już raczej ewentualnie można by:

        if BytesRead = 0 then
          break;

A to:

Addr := Addr + BuffSize;

raczej zmień na:

Addr := Addr + BytesRead;
0
procedure TForm1.Button3Click(Sender: TObject);
const
  Target: array[0..4] of byte = ($6E, $69, $63, $6F); 
  BufSize = 1024*4;
var
  Mbi: TMemoryBasicInformation;
  Handle: THandle;
  buff: array of byte;
  hWin, ProcID, BuffSize: Cardinal;
  Addr: DWORD_PTR;
  BytesRead: NativeUInt;
  i: integer;
begin
BuffSize:= 1024*4 + SizeOf(Target);
  hWin := FindWindow(nil, 'TestSft');
  if hWin > 0 then
    GetWindowThreadProcessID(hWin, @ProcId);

  if ProcId > 0 then
  begin
    Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, ProcId);
    if Handle <> 0 then
    begin
      while (VirtualQueryEx(Handle, Ptr(Addr), Mbi, SizeOf(Mbi)) <> 0) do
      begin
        SetLength(buff, Mbi.RegionSize);
        if ReadProcessMemory(Handle, Mbi.BaseAddress, Buff, Mbi.RegionSize, BytesRead) then
        begin
         for i := 0 to Length(Buff)  - Length(Target) do
          if CompareMem(@Buff[i], @Target[1], Length(Target)) then
          begin
            ShowMessage('Found');
          end;
        if BytesRead = 0 then
          break;
        Addr := Addr + BytesRead;
      end;
      SetLength(buff, 0);
      CloseHandle(Handle);
    end;
  end;
end;
end;

Pisząc "buguje" miałem na myśli to że program się zawieszał i musiałem go wyłączyć. Teraz się nie zawiesza, ale w sumie nic się nie dzieje.

1

Jeszcze:

if CompareMem(@Buff[i], @Target[1], Length(Target)) then

na

if CompareMem(@Buff[i], @Target[0], Length(Target)) then

bo widzę że tablica Target indeksowana jest od 0

0
Inny Inaczej napisał(a):

Teraz się nie zawiesza, ale w sumie nic się nie dzieje.

Dzieje się, tylko nie ma wizualnych efektów działania. Sprawdź pod debuggerem, linia po linii. W ten sposób sprawdzisz przepływ sterowania i znajdziesz przyczynę w kilka minut.

0
kAzek napisał(a):

Jeszcze:

if CompareMem(@Buff[i], @Target[1], Length(Target)) then

na

if CompareMem(@Buff[i], @Target[0], Length(Target)) then

bo widzę że tablica Target indeksowana jest od 0 [/quote]

Nadal nic :/

2

Ech dopiero po odpaleni zauważyłem byki takie jak próby odczytu z pamięci do której nie mamy dostępu (można by próbować uzyskać dostęp funkcja VirtualProtect ale co gorsze CloseHandle odpowiedzialne za zamknięcie uchwytu procesu było po nie tym end więc zamykało go zbyt wcześnie. Masz działającą chyba poprawnie (na tyle na ile zdążyłem przetestować) funkcję. Zawiera ona proste logowanie do Memo dla testu to możesz usunąć te linie.

procedure TForm2.Button1Click(Sender: TObject);
const
  Target: array[0..3] of byte = ($6E, $69, $63, $6F);
var
  Mbi: TMemoryBasicInformation;
  Handle: THandle;
  buff: array of byte;
  hWin, ProcID, BuffSize: Cardinal;
  Addr: DWORD_PTR;
  BytesRead: NativeUInt;
  i: integer;
begin
  Addr:= $400000; //tak dla testu initcjalizacja adresu szukania
  Memo1.Lines.Clear;
  hWin := FindWindow(nil, 'TestSft');
  if hWin > 0 then
    GetWindowThreadProcessID(hWin, @ProcId);
  if ProcId > 0 then
  begin
    Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, ProcId);
    if Handle <> 0 then
    begin
      while (VirtualQueryEx(Handle, Ptr(Addr), Mbi, SizeOf(Mbi)) <> 0) do
      begin
        if ((Mbi.State = MEM_COMMIT) and (not (Mbi.Protect = PAGE_GUARD)
           or (Mbi.Protect = PAGE_NOACCESS)) and (Mbi.Protect = PAGE_READWRITE)) then
        begin
          Memo1.Lines.Add(Format('%0:.8x', [Int64(Mbi.BaseAddress)]));
          SetLength(buff, Mbi.RegionSize);
          if ReadProcessMemory(Handle, Mbi.BaseAddress, Buff, Mbi.RegionSize, BytesRead) then
          begin
            for i := 0 to BytesRead - Length(Target)  -1 do
            if CompareMem(@Buff[i], @Target[0], Length(Target)) then
            begin
              Memo1.Lines.Add(Format('Found at %0:.8x', [Int64(Mbi.BaseAddress) + i]));
              //ShowMessage('Found');
            end;
          end;
        end;
        Addr := Addr + Mbi.RegionSize;
      end;
    end;
    SetLength(buff, 0);
    CloseHandle(Handle);
  end;
end;
0

Kurde powiem że klasa :D Rewelacyjnie śmiga poza jedną rzeczą.

007B9000
007BE000
007C2000
0097E000
00988000
00BB2000
00BC0000
00C90000
00CD8000
00D50000
00D60000
00D70000
00E70000
00E80000
00E90000
00EA0000
0173C000
0174D000
01750000
0303F000
0304F000
03050000
03098000
030D8000
030EF000
03100000
03130000
0333F000
03C80000
03E80000
05F80000
05FEB000
07F80000
0800A000
0804C000
080B8000
080F8000
08138000
08140000
08198000
...
77079000
77127000
77182000
77224000
77242000
77365000

Dlaczego mi to dodaje tak dużo adresów do memo zamiast tylko te z napisem "found at"?

1

Bo chciałem aby logowało jakie obszary pamięci są sprawdzane (te do których jest dostęp). Aby logowało tylko gdzie znalazło trzeba usunąć:

Memo1.Lines.Add(Format('%0:.8x', [Int64(Mbi.BaseAddress)]));
0

Ok. Wystarczyło usunąć Memo1.Lines.Add(Format('%0:.8x', [Int64(Mbi.BaseAddress)]));

Dzięki za gotowca w sumie :)
Miłego wieczoru.

0
kAzek napisał(a):

bezpieczniej:

          for i := 0 to Length(Buff)  - Length(Target) do
          if CompareMem(@Buff[i], @Target[1], Length(Target)) then
          begin
            ShowMessage('Found');
          end;

I nadal jedziesz o 1 bajt za daleko. Length(Buff) - Length(Target)-1 być powinno. Rzadko się wykrzaczy, ale jednak jak wejdziesz na kolejną stronę pamięci będzie lipa.

0
Błękitny Krawiec napisał(a):

I nadal jedziesz o 1 bajt za daleko. Length(Buff) - Length(Target)-1 być powinno.

Racja

Błękitny Krawiec napisał(a):

Rzadko się wykrzaczy, ale jednak jak wejdziesz na kolejną stronę pamięci będzie lipa.

W ostatecznym kodzie było

for i := 0 to BytesRead - Length(Target) do

Co także jest źle (ciągle ten 1 bajt) ale w tym kodzie niemożliwe jest wjechać na kolejną stronę pamięci ze względu na działanie funkcji VirtualQueryEx i założenie że szukana ilość bajtów wynosi co najmniej 1. Niemniej dzięki za uwagę już poprawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1