[Ollydbg] Register Inhalt

Hallo HaBo Gemeinde, ich versuche gerade mich im reversing schlau zu machen ... Binär, Hexadezimal und Entrypoint sind mir bekannt, Api Funktionsaufrufe vermag ich auch noch zu erkennen und soweit ich verstanden habe, muß ich die Register als Array betrachten und der Inhalt läßt sich in Ollydbg mit einem dump manchmal ansehen . Nun frage ich mich aber was eigentlich in den Registern einer neu geladenen exe drinne steht ?

calc.exe: (Windows Taschen Rechner)

34y6dwul.png


Dazu habe ich diverse exen in Ollydbg geladen
und beobachtet habe ich, das:

EAX anfangs immer leer zu sein scheint
ECX Register variiert bei anderen Dateien
EDX ist anfangs ntdll.KiFastSystemCallRet immer
EBX variiert auch bei anderen Dateien

wobei ESP, EBP, ESI, EDI immer den gleichen Inhalt aufweisen, sobald ich etwas in Ollydbg geladen habe?
 
Zuletzt bearbeitet:
Und bei mir (win7) sind ESI,EDI = 0, EDX = EIP = Entry Point und EAX zeigt auf kernel32.BaseThreadInitThunk ;)
Unter XP entspricht es den geposteten Werten.

Eine Exe wird von dem Windows-PE-Loader geladen (Lesen vom Datenträger, reservieren des Speichers, mappen der Section, Ausfüllen der Importtabelle, ggf. Initialisieren der TLS Einträge, Abarbeiten der Relocations).

Auch wenn man bei bestimmten Winversionen ein Muster/Regeln ableiten kann, so sind die Werte (außer EBP/ESP und EIP) afaik nirgendwo wirklich festgelegt und dürften "Überbleibsel" aus der Loader-Code Ausführung sein.
 
So ich habe das jetzt mal durchgetüfftelt und alle Register bis auf ESP mit Ollydbg auf Null gesetzt und mit F9 Run anschließend die calc.exe ohne Absturz zum laufen gebracht (EBP scheint in diesem wohl Fall keine Rolle hier zu spielen)

wd2jxrcc.png



das heißt wohl, dass auf der Stack-Pointer Adresse 0007FFC4 der 32Bit Wert 6F77817C wichtig ist (Zeiger), weil ohne diesem will die calc.exe nicht mehr laufen.


^^ klick ^^


Interpretiert wird der Wert als relativ virtuelle Adresse 7C81776F und dort steht ...

Code:
7C81776F    50                       PUSH    EAX
7C817770    E8 8349FFFF     CALL     ExitThread
laut MSDN beendet es die Nachrichtenschleife eines Threads. Nun mit Ollydbg auf CALL ExitThread doppelt drauf geklickt, erfahre ich, dass ich zur RVA 7C80C0F8 weitergeleitet werde und es folgen dutzende weitere unter Proczduren. Diese werden vermutlich abgearbeitet, wobei jeden Call die Rücksprungadresse auf ESP beibehalten wird, soweit ich das jetzt verstanden habe hoffentlich ...

Also wenn ich eine Datei in Olly lade kann ich davon ausgehen das nur belangloses Zeug in den Registern steht, Überbleibsel aus dem PE loader wie du sagtest, welche je nach Windows sSystem varriieren. Und das EBP hier bei der calc.exe nicht beibehalten werden mußte, liegt glaube ich an der Aufrufkonvention oder ?
 
So ich habe das jetzt mal durchgetüfftelt und alle Register bis auf ESP mit Ollydbg auf Null gesetzt und mit F9 Run anschließend die calc.exe ohne Absturz zum laufen gebracht (EBP scheint in diesem wohl Fall keine Rolle hier zu spielen)
Jep, mein Fehler. Durch den üblichen Stackframeaufbau
Code:
push ebp
mov ebp,esp
sub esp, XYZ
bzw. "ENTER XYZ,0" ist der Code ganz unabhängig von dem vorherigen EBP Wert.
das heißt wohl, dass auf der Stack-Pointer Adresse 0007FFC4 der 32Bit Wert 6F77817C wichtig ist (Zeiger), weil ohne diesem will die calc.exe nicht mehr laufen.
Ja, ohne Stack wird es schon etwas schwerer ;). Wobei hier wohl eher ein access violation auftritt, da 0 Speicher "reserviert" ist
www.cs.sjtu.edu.cn/~kzhu/cs490/9/9_MemMan.pdf hat gesagt.:
0x0 – 0xFFFF64 KBNo-access region to catch incorrect pointer ref
Interessant kann es auch sein, in Olly die Debugoptionen den Eintrag "Make first pause" auf "System breakpoint" statt auf "Entrypoint" zu setzen.

Interpretiert wird der Wert als relativ virtuelle Adresse 7C81776F und dort steht ...

Code:
7C81776F    50                       PUSH    EAX
7C817770    E8 8349FFFF     CALL     ExitThread
laut MSDN beendet es die Nachrichtenschleife eines Threads. Nun mit Ollydbg auf CALL ExitThread doppelt drauf geklickt, erfahre ich, dass ich zur RVA 7C80C0F8 weitergeleitet werde und es folgen dutzende weitere unter Proczduren. Diese werden vermutlich abgearbeitet, wobei jeden Call die Rücksprungadresse auf ESP beibehalten wird, soweit ich das jetzt verstanden habe hoffentlich ...
Ein Prozess ist nur ein "Kontainer" für Threads ;). Der "Hauptthread" wird erstellt (initialisiert usw) und startet später mit dem Code der Executable. Prinzipiell kann man statt "ExitProcess" am Ende der Anwendung auch einfach "ret" ausführen. Die Codeausführung kehrt zurück zum "Threadlauncher" Block, der auch ein komplettes Beenden des Threads bzw. des Prozesses beinaltet.

Also wenn ich eine Datei in Olly lade kann ich davon ausgehen das nur belangloses Zeug in den Registern steht, Überbleibsel aus dem PE loader wie du sagtest, welche je nach Windows sSystem varriieren. Und das EBP hier bei der calc.exe nicht beibehalten werden mußte, liegt glaube ich an der Aufrufkonvention oder ?
Jep. Interessante APIs könnten die "LdrpXYZfoo" aus der ntdll sein. Windows 2000 Loader: What Goes On Inside Windows 2000: Solving the Mysteries of the Loader
Prinzipiell kann man davon ausgehen, dass innerhalb einer NT Familie (z.B 5.0 bis 5.2 aka win2k - XP SP2/Server2003, 6.1 aka Win7/Server 2008 R2 usw. ) nicht so viel geändert wird. Wenn man genug Testmaschinen hat, kann man "interne" Funktionen/Eigenheiten durchaus nutzen. Der User hat dann halt ein Problem bei dem Update (z.B hier: http://www.hackerboard.de/windows-xp/46550-ntdll-dll-breakpoint.html#post347059 * oder an diverste Star/Sonstwas-Force geschützten Spiele und Software denk, die nur deshalb nicht mehr laufen :rolleyes: *).
 
Vielen Dank für deine Antwort erst einmal
und entschuldige bitte die etwas spätere Antwort jetzt :)

Also die Kodesequenz kommt mir sehr bekannt vor...
da einige Dateien so am Anfang des Entrypoints initialisiert werden.

Code:
PUSH    EBP
MOV     EBP, ESP
SUB     ESP, XY
Und tatsächlich, das ersezten mit diesem Kode

Code:
ENTER     XYZ, 0
tut es auch :thumb_up: .

Aber wie kann ich die passende Eingabegröße dazu bitte ermitteln ?


weil mir ist aufgefallen, wenn der Wert dort falsch ist -
springt Olly bei der Kodeausführung in sonst wo hohe Adressbereiche hin. Bei mir war das jetzt die Stelle 0x7C810C6D gewesen...

hsxb9v66.png


, welche ich aber in deiner verlinkten Tabelle nicht vorfinden konnte?


Bei Ollydbg 1.10 konnte ich nur die Debugoption "Use hardwarebreakpoints to step or trace code" finden.
War dennoch sehr interessant, zumal Olly beim ersten <Run> auf jener Stelle

Code:
01012583   .  83C4 24       ADD     ESP, 24
stehen geblieben ist, ich hoffe das meintest du oder?


Nun hatte ich eben versucht den Verweis von Exitthread auf nen ret in meiner calc umzuleiten, das Programm hat sich dann aber aufgehängt. Mit kernel.exitprocess hatte es aber geklappt :thumb_up:

Ja und danke für den weiteren Stoff aber ich will fürs erste lieber nur mit den dll wrappern kommunizieren, ist glaub ich einfacher, soweit ich das verstanden habe.
 
Zuletzt bearbeitet:
Code:
ENTER     XYZ, 0
tut es auch :thumb_up: .

Aber wie kann ich die passende Eingabegröße dazu bitte ermitteln ?
Üblicherweise ist es der Wert bei "ADD ESP, -XYZ" oder SUB ESP, XYZ am Anfang der Prozedur. Oder was meinst du mit Eingabegröße?

weil mir ist aufgefallen, wenn der Wert dort falsch ist -
springt Olly bei der Kodeausführung in sonst wo hohe Adressbereiche hin. Bei mir war das jetzt die Stelle 0x7C810C6D gewesen...


, welche ich aber in deiner verlinkten Tabelle nicht vorfinden konnte?
zum einen: 0x1000 < 0x7C 81 0C 6D < 0x7F FF FF FF, - also innnerhalb des private address spaces ;)
zum anderen muss es überhaupt kein gültiger Speicherbereich sein, da bei einem falschen Stackaufbau irgendwelche Daten als Sprungadressen interpretiert werden können (z.B weil die Rücksprungadresse überschrieben wird).


Bei Ollydbg 1.10 konnte ich nur die Debugoption "Use hardwarebreakpoints to step or trace code" finden.
Ich meine diese Option:
2-ollydbg-events-entry-point(1).png



Nun hatte ich eben versucht den Verweis von Exitthread auf nen ret in meiner calc umzuleiten, das Programm hat sich dann aber aufgehängt. Mit kernel.exitprocess hatte es aber geklappt :thumb_up:
Ich meinte eher die Programmlogik beim Schreiben der Software ;). Oder den "Exitprocess" im Programm selbst. ExitThread wird i.d.R eher für programmeigene Threads benutzt - da macht ein RET nicht so viel Sinn, da die Threads dann i.d.R. asynchron erzeugt werden und es gar nicht gedacht ist, aus dem Thread wieder zum "Erzeuger" Code zurückzukehren.
 
Üblicherweise ist es der Wert bei "ADD ESP, -XYZ" oder SUB ESP, XYZ am Anfang der Prozedur. Oder was meinst du mit Eingabegröße?
Ja den Wert XY meine ich, weil ich nicht weiß, woraus dieser sich nun ergibt?

zum einen: 0x1000 < 0x7C 81 0C 6D < 0x7F FF FF FF, - also innnerhalb des private address spaces ;)
zum anderen muss es überhaupt kein gültiger Speicherbereich sein, da bei einem falschen Stackaufbau irgendwelche Daten als Sprungadressen interpretiert werden können (z.B weil die Rücksprungadresse überschrieben wird).
so ich bin zwar weit weggesprungen aber dennoch im privaten Adressbereich geblieben, demnach gehört - die blaue Abbildung auch noch dazu. Und es gibt gültige, sowie nicht gültige Speicherbereiche, wobei letzteres nicht sein muß. Leider aber, weiß ich jetzt nicht wieso das so ist ?l

Nachtrag: habs das hier gefunden

g7a33syt.png

wobei das mit dem Kernel muß glaube ich nicht stimmen, da diese sich je nach Windows System etwas unterscheiden soweit ich weiß...

Übrigens die Obtion habe ich in Olly erfolgreich einstellen können. Und siehe da, ich bin noch innerhalb des privaten Adressbereich gelandet.

Code:
7C91120F    C3              RETN
 
Zuletzt bearbeitet:
Ja den Wert XY meine ich, weil ich nicht weiß, woraus dieser sich nun ergibt?
Aus dem Speicherbedarf, den der Compiler ermittelt hat. Wenn man nachträglich im Debugger/Disassembler push ebp; mov ebp, esp; sub esp,XY in ENTER XY,0 umschreibt, sollte man nur dieser Wert nehmen, ohne den Stackframe "kaputt"zu machen.
das ENTER Mnemonic habe ich im übrigen nur der Vollständigkeit halber erwähnt - üblich ist die "PUSH EBP usw" Sequenz.
Möglich ist aber auch keine davon, sondern direkte Nutzung von (irgendwo: sub esp, sizeof(vartype)) und dann [ESP-XY] (mit XY= je nach Position im Code unterschiedlicher Wert für dieselbe Variable), da der Compiler in vielen Fällen ganz gut auch Buch führen kann über PUSH/POP/CALLs und den nötigen Wert zur Compilezeit ausrechnen. Da werden spätere, manuelle Änderungen im Disassembler "etwas" aufwändig ;)

Und es gibt gültige, sowie nicht gültige Speicherbereiche, wobei letzteres nicht sein muß. Leider aber, weiß ich jetzt nicht wieso das so ist ?l
Weil kein "realer" Speicher angefordert wurde. Virtueller Speicher (Virtuelle Speicherverwaltung) bzw. virtueller Adressbereich ist ja eine "Krücke" für den Prozess bzw. den Programmierer.
Dass ein 32-Bit Prozess 2-3GB adressieren kann, heißt ja nicht, dass direkt bei der Ausführung soviel belegt wird (auch wenn man bei manchen Programmen den Eindruck nicht los wird :rolleyes: ). Erst wenn man Speicher anfordert, wird einem virtuellen Bereich (aka Page) ein realer RAM/Swap-Block zugeordnet.

PS: die DLLs sind i.d.R "shared"/"übervirtuell" - sie werden zwar im Prozessspeicher unter einer virt. Adresse eingeblendet, allerdings verweisen alle "Einblendungen" nur auf einen "realen" RAM-Block mit dem Inhalt. Das sorgt dafür, dass z.B die üblichen SystemDLLs wie Kernel32/ntdll/winsock usw. nicht gigabyteweise RAM Speicher belegen. Erst wenn man einen Schreibzugriff darauf tätigt, bekommt der Prozess eine eigene, private Kopie davon (daher klappen auch die Tricks mit dem Patchen/Hooken der Systemdlls z.B beim unpacking oder API-Monitoring)
 
Also der Stackframe ist sowas wie ne art Schmierzettel, wobei eigentlich alle Register Zwischenspeicher sind,soweit ich das verstanden habe.

Und das dort einfach nicht nur SUB ESP, XY oder Enter XY, 0 liegt vermutlich an den Compiler, zumal HTML Erstellungssoftware ja auch ziemlich viel Mühl produziert was nicht gebraucht wird, wie z.b. Move EDI, EDI aber zurück zum thema

Explorer.exe:



IDA:
5nypf5s8.png


IDA brachte mich auf die Idee das es sich um eine Struktur aus verschiedenen definierten Datentypen handelt.

http://msdn.microsoft.com/de-de/library/windows/desktop/ms686331(v=vs.85).aspx


Also denke ich jetzt, dass die Struktur mit dem Eingabeparametern 44h groß ist?
Anderseits sind es auch ca. 44h bis zum Funktionsaufruf wie aus einem anderen Beispiel hier zu entnehmen ist.

Beispiel2:
 
Zuletzt bearbeitet:
z.b. Move EDI, EDI aber zurück zum thema
Das Beispiel ist ungünstig ;). Afaik ist das zumindest in WinAPI Absicht für Hot-Patching:
sizeof(PUSH EBP; MOV EBP,ESP) == 3 Bytes. MOV EDI,EDI ist ein NOP in 2 Bytes Ausführung (dürfte von jeder halbwegs modernen CPU "übersprungen" werden). Zusammen sind es 5 Bytes => ausreichend für einen relativen CALL oder JMP
Why do Windows functions all begin with a pointless MOV EDI, EDI instruction? - The Old New Thing - Site Home - MSDN Blogs

Also denke ich jetzt, dass die Struktur mit dem Eingabeparametern 44h groß ist?
Jep. Das lässt sich per Hand abzählen oder über "sizeof(_STARTUPINFO)" im Compiler ermitteln/ausgeben. Wobei die Anzahl*Größe der lokalen Variablen bei modernen Compilern oft deutlich kleiner, als der tatsächlich reservierter Stackspeicher sind.

Anderseits sind es auch ca. 44h bis zum Funktionsaufruf wie aus einem anderen Beispiel hier zu entnehmen ist.
Zufall. Solange man nicht Shellcodes/Spezialroutinen betrachtet, sind Code und Stackspeicher getrennt (ferner wird die Codeausfürhung auf dem Stack mittlerweile unter allen modernen OS unterbunden: Data Execution Prevention - Wikipedia, the free encyclopedia)
 
Ah sehr interessant, so könnte man also die Kodeausführung umleiten und man kann also auf dem Stack nicht nur Sachen ablegen sondern auch ausführen lassen. Müßte man dazu jetzt den EIP für ändern ?
 
Beim "klassischen" Bufferoverflow wäre z.B das Überschreiben der Rücksprungadresse solch eine EIP Änderung.
Bsp:
Code:
void myfunc(char *str)
{
  char msg[100];
  strcpy(msg, str);
}
beim Aufruf der Funktion wird die Rücksprungadresse auf dem Stack abgelegt und bei ausreichend langem String durch strcpy überschrieben. Wenn die Funktion nun abgearbeitet wurde, kehrt RETN nicht zum Aufrufer zurück, sondern zu der neuen Adresse. Die kann auch durchaus auf dem Stack liegen. Ohne gezielte Randomisierung lässt (oder eher: ließ) sich relativ gut vorhersagen, wo z.B diese konkrete lokale Variable, die man durch den "eigenen" String überschrieben hat, nun auf dem Stack liegt. Dadurch konnte man also eigenen Code durch einen String lokal/remote (z.B Chat/Webserver usw) einschleusen.
War früher DIE Fehlerquelle schlechthin (zog nicht umsonst DEP/ASLR in OS sowie Stack-Cookies (und weitere Techniken) in Compilern nach sich ;) )
 
Nun gut CDW vielen Dank für deine Erklärungen noch einmal :) Ich probiere nun die crackmes auf dem board hier aus...
 
Zurück
Oben