Autor Beitrag
Tobi482
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: Mo 15.05.06 17:25 
Hi Leute,

ich möchte auf den Speicherbereich eines Prozesses zugreifen. Durch externen Zugriff mit der Debug-API (WriteProcessMemory, ReadProcessMemory) ist dies nicht möglich, da sofortige Beschädigungen des Codes der Fall ist (schwer zu beschreiben, es geht einfach nicht). Von innerher sollte dies jedoch möglich sein.

Das Ziel:
Ich muss einen Speicherbereich auslesen an der eine gesuchte Informations steht

Die Idee:
Ich nehmen einen Pointe, der auf ein 1 MB großes Byte Array typisierten ist und schiebe diesen durch den Prozessspeicher. Ich stelle mir einen klassifizierten Pointer immer als Maske vor, die auf den RAM gelegt wird und frei verschoben werden kann. Ich möchte diese Maske also vom ersten Byte bis zum letzten (-maskenlänge) des Prozessspeichers schieben und den Inhalt kontroliieren (Achtung Übergangstellen).

Damit diese Idee verfolgt werden kann, müssen einige Annahmen gemacht werden.

1. Prozesse liegen im RAM in fragmentieren Zustand vor
2. Prozesse sehen sich intern als zusammenhängendes Stück Speicher (ohne Fragmentation)

Meines Wissen stimme die beiden Annahmen.

WENN NICHT BITTE SOFORT EINSCHREITEN DANN GEHT DIE IDEE NICHT !!! WICHTIG !!!

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
type
  region = packed array[0..10000000of byte;
  pregion = ^region;

procedure TForm1.FormCreate(Sender: TObject);
var
     data      : string;
     p         : pregion;
     i,j       : integer;
begin
      data := 'test_information_inforamtion_inforamtion';

      memo1.Clear;

      for i := 0 to prozessleange do
      begin
          p := Pointer(i);
          if   (p^[0] = ord('t')) and
               (p^[1] = ord('e')) and
               (p^[2] = ord('s')) and
               (p^[3] = ord('t')) then
          begin
               for j := 0 to 20 do
               begin
                    memo1.Lines.Text := memo1.Lines.Text + chr(p^[j]);
               end;
          end;
      end;
end;


Der obrige Code sollte dies übernehmen. Nun zu meiner Frage.

Fragen:

1. Warum funktioniert der Code nicht? Exception: AccessViolation
2. "p := Pointer(i);" erwartet eine interne Speicheradresse oder eine globale?

PS: VirtualQueryEx (API zum suchen den nächsten Prozessfragmentes darf nicht benutzt werden)

Mit freundlichen Grüßen
Tobi
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Mo 15.05.06 18:13 
mit IsBadReadPtr kannst du prüfen ob du auf den Speicher zugreifen kannst, mit VirtulProtect kannst du halt auch schaun ob der Speicher existiert (wenn du VirtualQuery nicht benutzen willst)

Willst duweder IsBadReadPtr noch VirtualQuery noch VirtualProtect benutzen, mach ein TryExcept um das auslesen drum.


Und um dich wohl ganz zu demotivieren: so kannst du nur Speicher deines EIGENEN Programms auslesen. Mit anderen Programmem geht es nicht.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: Mo 15.05.06 18:19 
jaja ich will ja auch nur mein eigenes Programm kontrollieren.

Wird denn nun ein Pointer global oder lokal referenziert?

Was ist mit der Speicheradresse an denen isBadPtr auf treu steht?
Das darf ja bei einer lokalren Adressierung nicht auftrerten.

Gruß Tobi
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Mo 15.05.06 18:47 
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
program search;

uses
  windows,
  SysUtils;

{$APPTYPE CONSOLE}

procedure SearchX(const s: String);
var
  i: DWord;
  j: DWord;
  xLen: Integer;
  k: Integer;
begin
  i := 0;
  xLen := Length(s);
  while i < $7FF00000 do
  begin
    try
    //if (not isBadReadPtr(Pointer(i),xLen)) then
    //begin
      k := 0;
      for j := 1 to xLen do
        if Byte(s[j]) = PByte(i+j-1)^ then
          Inc(k);
      if (k = xLen) then
      begin
        Writeln(IntToHex(i,8),': ',PChar(i));
        Inc(i,xLen);
      end else
        Inc(i,1);
    //end else
    except
      i := (i and $FFFFF000)+ $1000;
    end;
  end;
end;

begin
  SearchX('ntdll');
  Writeln('finished');
  ReadLn;
end.

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: Di 16.05.06 10:36 
Hi,

erstmal Danke für deine Antwort und den Beispiel Code.

Aber meine Fragen sind jetzt nur noch vertieft wurden.

FRAGEN:

1. Warum kann man an der internen Speicheradresse 0 nicht lesen?
Falls es irgendwas mit der kritischen Grenze 0 zu 1 zu tun hat, geht auch
bei 1 kein Lesevorgang.

Das würde bedeuten, dass Prozesse sich selbst nicht als ganzes Stück sehen!

2. Wie ist denn der Aufbau eines PRozesses im RAM?

3. Ist damit der ungültige Pointer auf 0 zu erklären?

4. Was ist das für eine Zahl 7FF00000 = 2147483648 = 2^31 und warum
ist sie eine Grenze?

5. i := (i and $FFFFF000)+ $1000; das gleich hier?
Kannst du mir diese Zeile erklären?

6. Warum eine Erhöhung von $1000 = 4096?

7. Wie kommt man auf die Zahlen aus 4. und 5. Zahlen?

Mit freundlichen Grüßen
Tobi
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 16.05.06 10:59 
user profile iconTobi482 hat folgendes geschrieben:
Hi,

erstmal Danke für deine Antwort und den Beispiel Code.

Aber meine Fragen sind jetzt nur noch vertieft wurden.

FRAGEN:

1. Warum kann man an der internen Speicheradresse 0 nicht lesen?
Falls es irgendwas mit der kritischen Grenze 0 zu 1 zu tun hat, geht auch
bei 1 kein Lesevorgang.

Weil das 4 kb-Segment an Adresse 00000000h per VirtualProtect als GuardPage zur Erkennung von AcessViolations reserviert ist.

user profile iconTobi482 hat folgendes geschrieben:
Das würde bedeuten, dass Prozesse sich selbst nicht als ganzes Stück sehen!

Wie meinst Du "nicht als ganzes Stück"??? Meinst Du, dass nicht der gesamte 2GB Adressraum abgerufen werden kann?

Innerhalb des 4GB-Adressraums eines jeden Prozesses werden vom Betriebssystem immer gewisse Teilbereiches (Pages, Vielfaches von 4kb) zugewiesen und mit Zugriffsflags gesetzt. Diese können für jeden Bereich abgefragt, geändert und ggf. angepasst werden.

user profile iconTobi482 hat folgendes geschrieben:
2. Wie ist denn der Aufbau eines PRozesses im RAM?

Sehr viele kleine Speicherblöcke mit Vielfachen von 4kb Größe, wobei Daten und Code im gleichen Adressraum liegen, aber (meist) in getrennten Blöcken. Jedes Modul umfasst jeweils einen Speicherblock mit seiner größe nd wird dort als normaler Datenblock mit GENERIC_EXECUTE-Recht (zusätzlich zu READ) gehandhabt.

user profile iconTobi482 hat folgendes geschrieben:
3. Ist damit der ungültige Pointer auf 0 zu erklären?

Siehe MSDN, dort steht das zu VirtualProtect genauer erklärt *g*

user profile iconTobi482 hat folgendes geschrieben:
4. Was ist das für eine Zahl 7FF00000 = 2147483648 = 2^31 und warum
ist sie eine Grenze?

Speicherbereiche oberhalb dieser Grenze sind für System-DLLs (ntdll, kernel32, advapi, ...) reserviert, sowie MMFs und andere Speicher-Mappings. Grob gesagt: Das ist für das System reservierter Speicher ...

user profile iconTobi482 hat folgendes geschrieben:
5. i := (i and $FFFFF000)+ $1000; das gleich hier?
Kannst du mir diese Zeile erklären?

$1000 = 4096 = 4kb. I wird einfach um 4KB an die Grenze des nächsten Segments geschoben...

user profile iconTobi482 hat folgendes geschrieben:
6. Warum eine Erhöhung von $1000 = 4096?

Speicher-Seiten-Größe unter Windows ...

user profile iconTobi482 hat folgendes geschrieben:
7. Wie kommt man auf die Zahlen aus 4. und 5. Zahlen?

Mit freundlichen Grüßen
Tobi

Das hat Microsoft noch aus DOS-Zeiten übernommen ...

MfG,
BenBE.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: Di 16.05.06 11:25 
KLASSE :-D

hier sind ja richtige Profis am Werk :-D NOCHMAL EIN GANZ GROßES DANKE

Also ich versuche das jetzt nochmal zusammen zu fassen, wenn ich das jetzt richtig verstanden habe.

Ein Prozess wird gestartet.Danach reserveiert Windows einen kleinen Teil an Speicher und beginnt dorthin das Programm zu laden. Dabei werden immer Speicherzellen (Pages) von á 4096 Bytes genutzt. Ist das Programm größer als eine Speicherzelle wird eine weitere 4096 große Page angelegt. Manche Speicherzelle sind zugreifbar andere nicht (verschiedenste Gründe). In den nichtzugreifbaren Speicherblöcken sind nur "Hilfsdaten" und kein wirklicher Programminhalt.

Wenn ich nun also einen Pointer von einem byte array(4096) auf 0 setzte kontroliere ich die erste Page. Nun kann es sein das diese zugreifbar ist oder nicht. Ist sie nicht zugreif wäre eh nichts interessantes drin "Hilfsdaten, Reservierter Speicher für ..." also kann ich berühigt zum nächsten 4096-Block springen. Ist ein Block zugreifbar wird er durchsucht und gegebenenfalls etwas notiert, falls die gesuchte Information auftritt. Jeder Prozess hat von Windows eine MAximale Größe von 4 GB davon sind 2 GB für das eigentliche Programm und die weiteren 2 GB für zusätzlich geladene DLL's etc.
Meine Suche müsste also von der lokalen Speicheradresse 0 bis zur Hälft des gesamtverfügbaren Speichers gehen. Die weiteren 2 GB gehören zwar noch zum Prozess, enthalten aber keine Prozessdaten, sondern nur hinzugeladenen z.B. Bibliotheken.

Bitte korrigier mich falls etwas nicht stimmt.

Mit freundlichen Grüßen
Tobi
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 16.05.06 11:36 
In den unteren 2GB liegen sehr wohl auch DLLs und dorthin werden auch andere DLLs geladen. Einzig die DLLs, die oberhalb der 2GB-Grenze geladen werden ist auf einige sehr begrenzte Ausnahmen festgelegt. Dazu muss man aber das genaue Vorgehen zwischen Win9x und WinNT kennen.

Wenn ein Block nicht zugreifbar ist, heißt das nicht, dass er nicht zugewiesen ist. Es heißt nur, dass das Lesen des Blockes verhindert wird. Und selbst wenn ein Block lesbar ist, kann es über sog. Guard-Pages immer noch zu Exceptions kommen (Guarding Page Exceptions, #GP), die man u.a. zum Debuggen nutzen kann.

Will man aber an den Speicherberechtigungen nix extra drehen, kann man alle Pages ohne Read-Berechtigung einfach ignorieren.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: Di 16.05.06 11:45 
Du kannst dir gar nicht vorstellen wie du mir gerade geholfen hast^^
Kann gar nicht genug Danke sagen.

So noch eine letzte Frage :-D

Also ich suche eine statische Structure die eine feste größe hat. Diese structure hat eine Art Unquie-Header. Also ich erkenne sie sofort, wenn sie in einer Page auftaucht.

Kann es nun passieren, dass eine Kopie dieser STructure in irgendeinem function Stack auftaucht und dieser Stack in einer nichtzugreifbaren Page liegt?

Oder sind die nicht zugreifbaren Pages immer nur spezielle Verknüpfungen zu kritischen Verweisen,Bereichen die speziell geesichert werden müssen oder kann auch ganz normaler Code darin liegen?

Mit freundlichen Grüßen
Tobi
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 16.05.06 12:12 
Im Normalfall gibt es außer der Page an Offset 0 keine weiteren Guard-Pages im 2GB Adress-Raum. D.h. wenn man nicht gerade selber Source schreibt, der seine Daten per Guard-Page oder Entzug der Leseberechtigung schützt, sind alle Daten und Codeblöcke immer auch zugreifbar.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Tobi482 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 135



BeitragVerfasst: Di 16.05.06 12:15 
Super Danke nochmal für deine Mühen !!!

Und wieder ein zufriedner Kunde :-D

Hiermit schließe ich diese Frage ab.

Nochmals Danke an alle Beteildigente für eure Hilfe

Gruß Tobi