Autor |
Beitrag |
Tobi482
      
Beiträge: 135
|
Verfasst: 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 !!!
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..10000000] of 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
      
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: 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 
      
Beiträge: 135
|
Verfasst: 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
      
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: Mo 15.05.06 18:47
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 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); 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 
      
Beiträge: 135
|
Verfasst: 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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 16.05.06 10:59
Tobi482 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.
Tobi482 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.
Tobi482 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.
Tobi482 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*
Tobi482 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 ...
Tobi482 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...
Tobi482 hat folgendes geschrieben: | 6. Warum eine Erhöhung von $1000 = 4096? |
Speicher-Seiten-Größe unter Windows ...
Tobi482 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 
      
Beiträge: 135
|
Verfasst: Di 16.05.06 11:25
KLASSE
hier sind ja richtige Profis am Werk  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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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 
      
Beiträge: 135
|
Verfasst: 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
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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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 
      
Beiträge: 135
|
Verfasst: Di 16.05.06 12:15
Super Danke nochmal für deine Mühen !!!
Und wieder ein zufriedner Kunde
Hiermit schließe ich diese Frage ab.
Nochmals Danke an alle Beteildigente für eure Hilfe
Gruß Tobi
|
|
|