Memory nach Addresse durchsuchen?

05/12/2013 18:55 Zapeth#1
Hi ich habe einen Hook der zu Programmstart Änderungen an ein paar Addressen macht (danach aber nichts mehr).
Derweil funktioniert das ganz gut, nur halt eben für die eine Version des Programmes (statische Addressen).

Da ich den Hook aber auch für andere Versionen kompatibel machen will stellt sich mir nun die Frage wie ich möglichst effizient diese Addressen herausfinden kann ohne statische Addressen zu benutzen, sowie eine sichere Addresse für eine code cave.

Eine erste mögliche Idee wäre, dass ich einfach von der Base Address beginnend vorwärts suche und dabei jede Wert bei der jeweiligen Addresse mit den von mir gesuchen Werten vergleiche bis jeder Wert übereinstimmt.
Hier drängt sich mir aber noch die Frage auf, wie ich herausfinden kann wieviel Speicher das executable module einnimmt damit ich die Suche eingrenzen kann.

Freue mich über konstruktive Antworten :)
05/12/2013 19:25 Jeoni#2
Am Anfang eines jeden Moduls befindet sich der [Only registered and activated users can see links. Click Here To Register...]. Durch das Feld e_lfanew kommst du auf den [Only registered and activated users can see links. Click Here To Register...]. In diesem steht das Feld OptionalHeader.SizeOfImage. Dieses gibt die gesamte Modulgröße an. Wenn du weißt, dass sich deine gesuchte Adresse garantiert nicht in der Code-Section befindet, oder du genau weißt, in welcher Section sich deine Adresse befindet, dann kannst du die [Only registered and activated users can see links. Click Here To Register...] durchgehen, die direkt an den NtHeader anschließen. In diesen findet du nützliche Informationen zu jeder Section des Moduls (Startadresse, Größe, Charakteristika, also ob es Code enthält etc). Vermutlich kannst du deine Adresse ja auf eine Section einschränken, dann musste nur noch diese durchsuchen.
Wenn umliegende Adressen deiner gesuchten Adresse bestimmte statische Werte haben, kannst du es auch mit einem Patternscan probieren.
Allerdings sollte es für jede dynamische Adresse irgendwie Zeiger geben, weil der Origignal-Code ja auch irgendwie an diese Adresse rankommen muss (er wird ja nicht jedesmal auf gut Glück suchen, wenn er z.B. das Leben eines Spielers verändern will). Die wohl eleganteste Variante wäre, diese Pointer zu finden (können auch über verschiedene Ebenen gehen, muss kein Direktpointer sein) und sie in deinem Code zu implementieren, um dein Ziel zu erreichen.
Ich hoffe, dass das geholfen hat ;)
Mit freundlichen Grüßen
Jeoni

P.S.: Bei Fragen, kannst du mir gerne eine PN schreiben.
05/12/2013 20:22 Zapeth#3
Quote:
Originally Posted by Jeoni View Post
Vermutlich kannst du deine Adresse ja auf eine Section einschränken, dann musste nur noch diese durchsuchen.
Wenn umliegende Adressen deiner gesuchten Adresse bestimmte statische Werte haben, kannst du es auch mit einem Patternscan probieren.
Und diese Suche soll ich dann so gestalten wie ich es bereits erwähnt habe?
Und kann ich das genauso für meine Code Cave machen? Im Prinzip suche ich dort ja nur nach einer Addresse mit lauter Nullen aber gibts da auch eine Section wo ich danach suchen muss (damit ich nicht irgendwo was reinschreibe wo später was vom Programm reingeschrieben wird :p )

Quote:
Originally Posted by Jeoni View Post
Allerdings sollte es für jede dynamische Adresse irgendwie Zeiger geben, weil der Origignal-Code ja auch irgendwie an diese Adresse rankommen muss (er wird ja nicht jedesmal auf gut Glück suchen, wenn er z.B. das Leben eines Spielers verändern will). Die wohl eleganteste Variante wäre, diese Pointer zu finden (können auch über verschiedene Ebenen gehen, muss kein Direktpointer sein) und sie in deinem Code zu implementieren, um dein Ziel zu erreichen.
Die Werte an den Addressen sind nicht dynamisch aber die Offsets unterscheiden sich halt bei den Versionen, deshalb muss ich danach suchen.

Und danke, das hat schonmal sehr geholfen ;)
mfg Zapeth
05/12/2013 20:34 Jeoni#4
Zum Thema Code Caves: Warum allozierst du nicht Speicher mithilfe von malloc oder new? Den daraus resultierenden Speicher kannste in jedem Fall mit deinen Sachen beschreiben (ggf noch mit VirtualAlloc Execute-Rechte geben), ohne dass die Funktionalität des Programms leidet, weil du wichtige Codes oder Daten überschreibst.
Zu den Adressen: Ok, also es geht nur um Versionsunterschiede? Hier könnte man entweder einen Patternscan machen (mit einem eindeutigen Pattern) oder tatsächlich jede Adresse abprüfen. Bei letzterer Methode allerdings musst du aufpassen: Wenn du nach dem Wert 100 suchst, gibt es evtl mehrere, also musst du ein paar Funde überspringen (muss natürlich eine statische Anzahl an Funden sein) oder eben weitere statische Werte in der nähe Suchen und die abprüfen. Also zum Beispiel, wenn der nächste integer 50 sein soll eben auch <Adresse>+4 nach 50 prüfen (was ja quasi schon ein Patternscan ist). In jedem Fall ist aber nicht garantiert, dass du deine Adresse in jeder Version findest. Pattern können sich verändern und die Anzahl der 'übersprungenen' Ergebnisse auch.
Hoffe, dass ist hilfreich, auch wenn dieser Post in meinen eigenen Augen irgendwie etwas verwirrt aussieht :D
Mit freundlichen Grüßen
Jeoni
05/12/2013 21:31 Zapeth#5
Quote:
Originally Posted by Jeoni View Post
Zum Thema Code Caves: Warum allozierst du nicht Speicher mithilfe von malloc oder new? Den daraus resultierenden Speicher kannste in jedem Fall mit deinen Sachen beschreiben (ggf noch mit VirtualAlloc Execute-Rechte geben), ohne dass die Funktionalität des Programms leidet, weil du wichtige Codes oder Daten überschreibst.
Stimmt, daran habe ich gar nicht gedacht :p
Aber wenn ich einen JMP zu einer Addresse in meinem hook machen will, wird der Befehl nicht mehr Speicher verbrauchen als wie wenn ich zu einer Addresse innerhalb des Speichers der .exe springe? Oder verbrauchen die einheitlich viel Speicher (solange es keine short jmp's sind)?

Und nachdem die Werte die ich suche größtenteils sowieso nur einmal in den entsprechenden Sections zu finden sind, schätze ich mal, dass die Eindeutigkeit kein großes Problem sein sollte ;)

mfg, Zapeth
05/12/2013 21:40 Jeoni#6
Soweit ich weiß, gibt es da keinen erhöhten Speicherverbrauch. Du kannst auch andere Methoden zum jumpen anwenden, die sind aber etwas größer.
Da gibt es
Code:
push <absolute Adresse deiner Code Cave>
ret
oder, wenn ein Register gerade unnütz ist (im Beispiel eax)
Code:
mov eax, <absolute Adresse deiner Code Cave>
jmp eax
Geht natürlich auch mit call statt jmp.
Direkte JMPs (also "jmp <Distanz>") sind in jedem Fall 5 Bytes lang: 1 Byte der "jmp" 4 Bytes die Distanz.
Bezieht sich alles auf 32Bit.
Hoffe, dass war das, was du suchtest ;)
Jeoni
05/12/2013 21:53 Zapeth#7
Quote:
Originally Posted by Jeoni View Post
Hoffe, dass war das, was du suchtest ;)
Jeoni
Soweit wars das, werde mich aber hier wieder melden falls unerwartete Probleme auftreten :p

Danke nochmal für die schnelle Hilfe ;)
mfg Zapeth
05/13/2013 10:01 Shadow992#8
Quote:
Originally Posted by Zapeth View Post
Soweit wars das, werde mich aber hier wieder melden falls unerwartete Probleme auftreten :p

Danke nochmal für die schnelle Hilfe ;)
mfg Zapeth
Sollte es zum Thema Code-Caves weitere Probleme geben, hilft dir vielleicht auch das:
[Only registered and activated users can see links. Click Here To Register...]

Das Ganze wird zwar implementiert als AutoIt-Code, davor versuche ich aber alles so allgemein wie möglich zu beschreiben, damit es auch in jeder anderen Sprache derart umsetzbar sein sollte.
05/18/2013 16:32 Zapeth#9
OK hier bin ich wieder mit neuen Fragen :D (hatte leider in letzter Zeit viel zu tun und bin erst kürzlich dazu gekommen mich wieder diesem Projekt von mir zu widmen)

Das Suchen funktioniert ganz gut bis jetzt (und schnell genug ist es auch) allerdings habe ich jetzt Verständnisprobleme mit der Code Cave.
So wie ich es verstanden habe kann ich ja ganz einfach neuen Speicher allozieren mit zb new und den Pointer auf diesen Speicher dann für meine Code Cave verwenden.
VirtualAllocEx (so wie in Shadow's tutorial) müsste ich ja nur verwenden, wenn ich von außerhalb des Prozesses auf den Speicher zugreife was ja hier nicht der Fall ist oder?
Und was für einen Datentyp soll ich hier verwenden oder ist das egal?

Und ich müsste ja dann diesen Pointer auch in ASM-Code umwandeln damit ich einen JMP dorthin machen kann.
Also derzeit mache ich es ja so mit meiner Code Cave als statische Addresse:
Code:
// jump befehl zur code cave
JMP 010034A0

// der zugehörige bytecode, der in den speicher geschrieben wird:
E9 F6123B00
Wie kann ich also jetzt zur Laufzeit den ASM code mit der richtigen Addresse in Bytecode umwandeln damit ich ihn in den Speicher schreiben kann?
05/18/2013 21:38 Padmak#10
Du hast keine Sprache angegeben, also C++

(len ist die Länge des Codes, der an deiner Adresse steht, mindestens 5, src ist die Adresse der Stelle die du hooken willst)
Code:
//erzeugt deine Code-Cave
uint8_t *jmp = (uint8_t*)malloc(len + 5);
//erzeugt ein Byte-Array auf den original-Code
uint8_t* byteSrc = reinterpret_cast<uint8_t*>(src);
//kopiert den originalen Code in deine Codecave
memcpy(jmp, src, len);
//Für unseren Jump zurück brauchen wir nur 5 Bytes, die letzten 5
jmp += len;
//Logisch, JMP-Byte
jmp[0] = 0xE9;
//Die Adresse der des Original-Codes wird in die Codecave geschrieben, zum Zurückspringen
*(uintptr_t *)(jmp + 1) = uintptr_t(byteSrc + len - jmp) - 5;
//Ursprungscode wird abgeändert auf JMP
byteSrc[0] = 0xE9;
//Die Adresse der Code-Cave wird an Originale Stelle geschrieben (deine Frage meint das hier)
*(uintptr_t *)(byteSrc + 1) = uintptr_t((uint8_t*)dst - byteSrc) - 5;
//Setzt den Rest im Ursprungscode auf 0x90, also NOP
for (uint32_t i = 5; i < len; i++)
{
	byteSrc[i] = 0x90;
}
Das ist vllt etwas heftig, sollte dir aber genauestens erklären, was abgeht bzw. abgehen sollte.
Achtung: ich habe sämtliche Zugriffsrechtsänderungen rausgenommen, natürlich muss src mit der Länge len auf PAGE_READWRITE gesetzt werden und dein Code, falls nicht direkt als ausführbar alloziert, natürlich auf PAGE_EXECUTE oder ähnliches

Ich hoffe, das hilft^^

Padmak
05/18/2013 22:05 Zapeth#11
Quote:
Originally Posted by Padmak View Post
Du hast keine Sprache angegeben, also C++
Sry, dachte dass es nach der bisherigen Diskussion schon offensichtlich war.

Quote:
Das ist vllt etwas heftig, sollte dir aber genauestens erklären, was abgeht bzw. abgehen sollte.
Danke, das hilft mir in der Tat. Es war zwar mehr als verlangt aber das schadet ja nie :p

gruß, Zapeth
05/18/2013 22:39 Padmak#12
War auch relativ offensichtlich, ich habs nur nochmal dazugeschrieben für andere, die vielleicht mal auf diesen Thread stoßen
Freut mich dass ich dir helfen konnte, wenn du damit weitergehende Probleme haben solltest, schreib mir einfach 'ne PM, dann versuch ich dir zu helfen :P

Padmak
05/19/2013 17:54 MrSm!th#13
Wenn man src die Execute-Berechtigung nimmt, endet das nicht schön.
05/19/2013 18:07 Padmak#14
Ich hab mal als Voraussetzung vorausgesetzt, dass er selbst merkt, dass der Code danach wieder auf exec zurückgesetzt werden muss.. war das zuviel verlangt?

Padmak