Przeszukiwanie pamięci pod kątem łańcuchów

0

witam, juz od jakiegos czasu próboje przeszukać pamieć w poszukiwaniu stringów, lecz działam własciwie na opak, nie wiem czy działam w odpowiednim zakresie, i tutaj pojawia sie problem odczytania adresu rozpoczynającego program i kończącego, coś szukałem na zagranicznym forum ale nic konkretnego, byłbym wdzięczny

0

nie znam się na tym, ale Cheat Engine raczej jest napisany w Delphi i z tego co pamiętam kod źródłowy autorzy udostępniają na swojej stronie. Choć przeglądając ten kod, będzie masaaaaaa kodu więc nie wiem, czy znajdziesz to co chcesz.

0

no własnie z tamtąd używam funkcje przeszukiwania pamięci, tylko nie wiem jak pobrac zakres w jakim sie poruszać.

0

Problem polega na tym że używam funkcji

 FindStringInMemory(APID, $000000, $7FFFFFFF, 'test123', False, AnOnFindProc);

Tylko ze przy tej konfiguracji zakresu adresów, po prostu nie znajduje, nie wiem jaki zakres ustawic, jak pobrac zakres w którym operuje program, raz coś zmieniałem metodą prób i błędów w zakresie i wyszukiwanie stringów kończyło sie pomyślnie. A jeszcze jedno, jak bardzo ta funkcja obciąża system, potrzebuje skanować co około 100ms, stringi są dynamiczne i musze dynamicznie je wyszukiwać. Mam nadzieje że ktoś zna odpowiedz, Pozdrawiam Snacker

0

3 parametr $7FFFFFFF zamień 7 na F, to zwiększy obszar skanowania do całej pamięci, pytasz jak szybko to się będzie tworzyć... a jak myślisz ile zajmie przeoranie 2GB adresów? (7FFFFFFF wpisz sobie w kalkulator i podziel przez [3*1024]) szczerze to nie wieże żeby ci to zajęło mniej niż 100ms, aczkolwiek jeżeli adres jest alokowany dynamicznie tylko na początku pracy programu to nie powinno być problemu żeby go znaleźć raz i zapisać sobie pointer i z niego korzystać... Jeżeli jest alokowany dynamicznie warunkowo np jest to w grze i co misje kampanii adres się zmienia to możesz skanować sobie jakiś mniejszy obszar od ostatniego pointera, rozumiesz to?

0

Tak, rozumiem, a dzielac FFFFFFFF przez 1024^3 dostaje 0 wiec chyba cos nie tak z windowsowym kalkulatore ( FFFFFFFF/106CF3B64000) = 0
a idac dalej podmiana 7FFFFFFF na FFFFFFFF nic nie daje, dałem interval timera na 1s aby miał więcej czasu, ale w ogóle nie znajduje teraz tych stringów.
Mimo że są, nie wiem jak wydłupac te pointery zeby w zakresie sie obracac odpowiednim, bo te stringi pojawiają sie na bardzo krótko i znikają.

0

Małe sprostowanie interval to jest przerwa między wykonywaniem się czynności więc jak ustawisz 1000 to będzie się to wykonywać 1 sekunda + kod z procedury (jak procedura będzie trwać 1h to będziesz miał odstępy 1h i 1s między początkiem wywołania procedury). Nieco bardziej obciążające RAM i CPU będzie wrzucić skanowanie do pętli coś jak

var Enable:Boolean;
procedure ...
begin
 while Enable do begin
  FindStringInMemory(APID, $000000, $7FFFFFFF, 'test123', False, AnOnFindProc);
  Sleep(1);
 end;
end;

Ważne jest by wiedzieć mniej-więcej co jaki okres twój string jest realokowany i ja daleko od jakiego adresu, wtedy możesz zoptymalizować kod.
Jeszcze jedno bardzo ale to bardzo ważne czy proces jakiego przeszukujesz jest 32 czy 64 bitowy?

0
procedure TForm1.Timer3Timer(Sender: TObject);
begin
  FindStringInMemory(APID, $1000000, $7000000, 'tekst123', False, AnOnFindProc);
  FindStringInMemory(APID, $1000000, $7000000, 'tekst345', False, AnOnFindProc2);
end;

Według obliczen ten zakres jest przeszukiwany w niecałe 100ms na jedno zapytanie, Timer działa na intervalu 200ms , no i raz sie udało wyszukać jedną z wartości, ale kolejne odpalenie aplikacji i już nie znalazło, nie rozumiem.

0

Proces 32bit, trochę zawęziłem obszar poszukiwań gdyż raz jak znalałem tą wartośc to była $1xxxxxx lub $2xxxxxx a druga $6xxxxxx więc spekuluje ze zakres odpowiedni ( czas spadł z 1s do 100ms wiec troche szybciej)

0

dobra takie szukanie po omacku jest bezsensu, wie ktoś jak pobrac aktualny obszar jaki używa program w pamięci, zakres adresów, tak sie nie da robic nic, przedchwilą mialem juz jedna wartosc teraz w ogóle jej nie widac.

0

Nie da się określić, domyślnie (i w większości przypadków) kompilowane są z dostępem do całego obszaru RAMu, a skoro jest alokowany dynamicznie to może być wszędzie, chociaż można spróbować w winapi jest takie coś do pobierania stosu http://msdn.microsoft.com/en-us/library/windows/desktop/aa366711%28v=vs.85%29.aspx sobie możesz określić adres bazowy i rozmiar stosu i tylko tę część przeszukiwać może zadziała...

0

chyba znalazłem rozwiązanie , tylko mam takie pytanie z podstaw bardziej, polecenie sleep( ) usypia proces czy wstawia przerwe czy tak jak Basicu waitms?

Rozwiązaniem jest zawieszenie procesu, owszem zawieszam go, i wtedy dostaje dwie zwrotne wartości bezproblemowo, program wisi, zamykam go procesem. Ale gdy dodaje opcje przywrócenia programu do życia. Nie otrzymuje wartości zwrotnej w postaci adresow do tych stringów. Próbowałem dać mu troche czasu, 2-5sek lecz bez zmian.

0

Usypia wątek na (n) [ms]
Pod Windows jest wywoływana procedure Sleep z kernel32.dll w stdcall dokładny opis masz tu http://msdn.microsoft.com/en-us/library/windows/desktop/ms686298%28v=vs.85%29.aspx [eng], tak w kilku słowach to stopuje "wrzucanie" instrukcji do cache CPU na rzecz innych wątków do pÓÓÓÓki ticket nie przekroczy określonego cyklu czasu CPU.

0

Ok, udało sie, finalnie znalazłem pointer który wywołuje te stringi, gdy zostaje wywołany, stopuje proces i podmieniam, Pozdrawiam i dziękuje za pomoc.

0

Na przyszłość polecam pogooglować. Na forum Cheat Engine jest przykładowy kod w jednym z wątków. A do całości określania rozmiarów dla domyślnego modułu pod danym PID'em polecam poniższy kod. Zwróci on Tobie identyczne informacje, jakie podaje na przykład LordPE dla danego procesu na głownej liście u góry swojego okna. Oczywiście wartość zmiennej DestPid możesz sobie zmienić. Jak wyszukiwać Pid'y na podstawie nazwy i inne operacje są pokazane na mnóstwie stron do wygooglowania, również pisane pod Delphi.

//...
uses
  Windows, PSApi;

procedure CvtInt;
asm
        OR      CL,CL
        JNZ     @CvtLoop
@C1:    OR      EAX,EAX
        JNS     @C2
        NEG     EAX
        CALL    @C2
        MOV     AL,'-'
        INC     ECX
        DEC     ESI
        MOV     [ESI],AL
        RET
@C2:    MOV     ECX,10

@CvtLoop:
        PUSH    EDX
        PUSH    ESI
@D1:    XOR     EDX,EDX
        DIV     ECX
        DEC     ESI
        ADD     DL,'0'
        CMP     DL,'0'+10
        JB      @D2
        ADD     DL,('A'-'0')-10
@D2:    MOV     [ESI],DL
        OR      EAX,EAX
        JNE     @D1
        POP     ECX
        POP     EDX
        SUB     ECX,ESI
        SUB     EDX,ECX
        JBE     @D5
        ADD     ECX,EDX
        MOV     AL,'0'
        SUB     ESI,EDX
        JMP     @z
@zloop: MOV     [ESI+EDX],AL
@z:     DEC     EDX
        JNZ     @zloop
        MOV     [ESI],AL
@D5:
end;

function IntToHex(Value : integer; Digits : integer) : string;
asm
        CMP     EDX, 32
        JBE     @A1
        XOR     EDX, EDX
@A1:    PUSH    ESI
        MOV     ESI, ESP
        SUB     ESP, 32
        PUSH    ECX
        MOV     ECX, 16
        CALL    CvtInt
        MOV     EDX, ESI
        POP     EAX
        CALL    System.@LStrFromPCharLen
        ADD     ESP, 32
        POP     ESI
end;

function ExtractFileName(FileName : string) : string;
var
  I : integer;
begin
  ExtractFileName := FileName;
  for I := Length(FileName) downto 1 do
  begin
    if (FileName[I] = '\') then
    begin
      ExtractFileName := Copy(FileName, I + 1, MaxInt);
      Break;
    end;
  end;
end;

function AnsiCompareText(const S1, S2 : string) : Integer;
begin
  Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1),
    Length(S1), PChar(S2), Length(S2)) - 2;
end;

function GetModuleBaseAddress(ProcessId : Cardinal; MName : string; var ImageBase, ImageSize : DWORD) : boolean;
var
  PHandle : THandle;
  CbNeeded, I : Cardinal;
  ModuleInfo : TModuleInfo;
  Modules : array of HMODULE;
  ModuleName : array[0..MAX_PATH - 1] of Char;
begin
  ImageBase := 0;
  ImageSize := 0;
  Result := False;
  SetLength(Modules, 1024);
  PHandle := OpenProcess(PROCESS_QUERY_INFORMATION + PROCESS_VM_READ, False, ProcessId);
  if (PHandle <> 0) then
  begin
    EnumProcessModules(PHandle, @Modules[0], 1024 * SizeOf(HMODULE), CbNeeded);
    SetLength(Modules, CbNeeded div SizeOf(HMODULE));
    for i := 0 to Length(Modules) - 1 do
    begin
      GetModuleBaseName(PHandle, Modules[I], ModuleName, SizeOf(ModuleName));
      if AnsiCompareText(MName, ModuleName) = 0 then
      begin
        GetModuleInformation(PHandle, Modules[i], @ModuleInfo, SizeOf(ModuleInfo));
        Result := True;
        ImageBase := DWORD(ModuleInfo.lpBaseOfDll);
        ImageSize := DWORD(ModuleInfo.SizeOfImage);
        CloseHandle(PHandle);
        Break;
      end;
    end;
  end;
end;

function GetMainModuleNameFromPid(PidToCheck : DWORD) : string;
var
  FullProcPath : PChar;
  ProcessHandle : THandle;
begin
  Result := '';
  ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, PidToCheck);
  if ProcessHandle > 0 then
  begin
    GetMem(FullProcPath, MAX_PATH);
    GetModuleFileNameEx(ProcessHandle, 0, FullProcPath, MAX_PATH);
    Result := ExtractFileName(FullPRocPath);
  end;
end;

var
  DestPid, ImgBase, ImgSize : DWORD;
begin
  DEstPid := $9C0;
  if GetModuleBaseAddress(DestPid, GetMainModuleNameFromPid(DestPid), ImgBase, ImgSize) then
  begin
    Writeln(IntToHex(ImgBase, 1) + ' / ' + IntToHex(ImgSize, 1));
    Readln;
  end;
end.

Kod przygotowany pod kątem użycia w WinAPI i aplikacji konsolowej. Kod dodatkowych potrzebnych tutaj funkcji został "wypruty" ;) z kodu źródłowego modułu VCL dla Delphi 7.

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