Frage zum Ollydbg

Hallo Leute,

meine Frage kurz und Knapp: Wofür ist der rot markierte Bereich im Screenshot da?

Screenshot.png


the_uxreal
 
Das sind die Opcodes [1] für die jeweiligen daneben stehenden übersetzen Assembler-Befehle. Bedeutet ergo: Wenn du die Executable in einem Hex-Editor öffnest und an diese Stelle gehst, würdest du genau diese Werte sehen.

[1] http://de.wikipedia.org/wiki/Opcode
 
Hallo +++ATH0,

wie genau kann ich mir die Opcodes im Hex-Editor anschauen? Wo finde ich weitere Informationen im Umgang mit Opcodes? Ansonsten vielen Dank für die Information!

the_uxreal
 
Du musst zuerst die VA in den eigentlichen Offset in der Datei umrechnen:
Imagebase subtrahieren, schauen in welcher Section diese Adresse dann liegt, und dann mittels dem Beginn der Section in der Datei auf den Offset schließen. Alternativ kannst du auch in OllyDbg diese Stelle in einer Art Hex-Editor anzeigen lassen, wo dir auch die reale Adresse in der Datei angezeigt wird.
Wenn du dann an dieser Adresse im Hexeditor nachschaust, wirst du die angesprochenen Opcodes finden. Wenn du diese direkt verändern willst, musst du die Syntax in den Intel-Handbüchern nachlesen und die Zahlenwerte entsprechend ändern. Bequemer geht das allerdings per OllyDbg, da du dort den Code in Assembly eingeben kannst.(also z.B. xor eax,eax statt 33c0)
 
Als Ergänzung: die Umrechnung erledigt man i.R mit einem PE-Editor (z.B LordPE ->FLC Button).Alternativ kann man in Olly die gewünschte Zeile markieren und "Rechtsklick->Copy to exectable->Selection" machen. Dann erscheint der von Lesco erwähnte Hex-Editor mitsamt der "realen" Adresse.
Da Opcodes die Instruktionskennzeichnungen für CPU sind, wird das manuelle kodieren nicht ganz so einfach. Dafür gibts aber auch öfters nette Tabellen oder stark reduzierte Listen mit Opcodes (sowas wie "asm opcodes for crackerers" ) z.b Nasm Handbuch oder bei MASM unter Help/OPCODES.HLP

http://www.assembler.my100megs.com/asm3.htm
http://www.scribd.com/doc/429560/Reverse-Coding
meistens wird man aber eher "ASM-Instruction" zu "Opcode" Tabellen vorfinden:
http://jsimlo.sk/docs/cpu/index.php/jnz.html
http://jsimlo.sk/docs/cpu/index.php/#a

Wenn man mal versucht, die Opcodes wirklich manuell zusammenzusetzen, merkt man auch, wie viel Altmüll die Intel-Archiketur noch mit sich rumschleppt ;)

PS: in älteren Cracking-Tutorials (in denen noch W32Dasm benutzt wird ;) ) gibt es auch öfters kleine Tabellen. I.R geht das aber nie über JMP-Anweisungen (JMP=EB,JNE=75,JE=74 usw.) hinaus.
 
Hallo ihr Beiden,

so ganz habe ich nicht verstanden, wie man den Offset berechnet. In dem Screenshot des ersten Beitrags gibt es eine JNZ-Anweisung, wo sich zwei Opcodes befinden: 75 und 2B. Die Zahl 75 kann ich aus der OPCODES.HLP entnehmen:
75 cb JNZ rel8 Jump short if not zero (ZF=0)
Doch wo kommt die Zahl 2B her? Wo kann ich die beiden Zahlen finden bzw. wo "entspringen" sie?

the_uxreal
 
Da steht ja ein "cb" dahinter.
Ich denke mal das heisst hier constant byte.

Bedeutet im Falle von JNZ. Springe (0x2B) 43 Byte nach vorne. Die Adressrechnung beginnt nach der JNZ Instruktion.

Also die Adresse zu der gesprungen wird, wenn das Zero-Flag nicht gesetzt wurde ergibt sich so:

Code:
0x0041157D + 0x02 (Größe der JNZ Instruktion) + 0x2B = 0x004115AA

Eine Maschineninstruktion setzt sich in vielen Fällen also nicht nur aus den Bytes für den Opcode zusammen, sondern besteht oft aus mehreren Teilen, die abhängig von den Opcodes vorhanden sind oder nicht.

Wenn in der Maschineninstruktion bestimmte Register angewählt werden sollen, dann wird das mit dem MOD-R/M Byte entschieden, das direkt nach dem Opcode folgt.
MOD R/M ist sozusagen, dass Modifikationsbyte für Register und Memory(Adressen).
Da bekommt man dann allerlei Kombinationen hin, wie "[EAX+4], EBX", "[EAX+EBX], EDX" usw.
Wenn man dann die Adresse noch skalieren will mit einem Faktor (wahlweile 2,4 oder 8 ) und/oder noch dazu eine Basisadresse für die Rechnung hinzufügen will, dann kommt noch das SIB-Byte ins Spiel (Scale, Index, Base). Ob das SIB-Byte vorhanden ist oder nicht, wird mit in das MOD-R/M Byte hineinkodiert.

Sehen wir uns mal ein kompliziertes Beispiel an und schlagen mal nach, wie das zustande kommt.
Wie wäre es mit:

Code:
MOV DWORD PTR DS:[ECX*4+EAX+20000000], EBX

Nicht schlecht oder? Die wenigsten hätten gedacht, dass man soviel mit der Adressrechnung rumspielen kann. ;)

Sehen wir uns die Bytefolge dieser Instruktion an.

Code:
MOV DWORD PTR DS:[ECX*4+EAX+0x20000000],EBX

A   B   C   D
89 9C 88 00000020

A

Opcode von unserer Instruktion. Schauen wir mal nach, was 0x89 bedeutet [1].
Wir finden heraus:

Code:
MOV Ev,Gv

Jetzt schauen wir hier [2] nach, wofür das Ev und Gv steht.
Das E im ersten Operanden steht dafür, dass wohl das folgende MOD-R/M Byte entscheidet, was der erste Operand sein wird.
Das schauen wir uns gleich an.
Das G für den 2. Operanden steht für ein beliebiges Register. Die Auswahl des Registers geschieht nach einem bestimmten Feld im MOD-R/M Byte. (da passt viel rein xD)
Das kleine v steht für mögliche Operanden-Größen. Hier jeweils ein DWORD groß.

B+D

0x9C ist nun unser MOD-R/M Byte. Hier müsste das wichtigste drinstehen.
Wir schauen hier [3] nach.
Für 0x9C steht da:
[sib+sdword] für unseren linken Operanden, und EBX für unseren rechten Operanden.

Soviel steht schonmal hier fest:
Code:
MOV [sib+sdword], EBX

Nun müssen wir die Lücken füllen. sib bedeutet, dass wohl als nächstes das Scale/Index/Base-Byte kommt. Und zusätzlich wird zu dieser Adresse noch ein DWORD addiert. Also folgt nach dem SIB-Byte noch eine 32 Bit Konstante. (unser D von oben)
Bauen wir die doch schoneinmal ein.
Dann haben wir:
Code:
MOV [sib+0x20000000], EBX

Man muss bedenken, dass wir die Werte in Little-Endian Reihenfolge sehen.
Wenn wir also die Bytes von D (00 00 00 20) einzeln von rechts nach links lesen, haben wir 20 00 00 00 -> 0x20000000.

C

Schauen wir uns nun das SIB-Byte 0x88 an. [4]
Da finden wir heraus, dass wieder zwei Dinge hineinkodiert werden.
Einmal ein Scaled Index. In unserem Falle: [ECX*4+base]
Und eine Basis: EAX
Fügen wir zusammen und haben [ECX*4+EAX]

Setzen dies an Stelle von sib ein und haben endlich unsere gesamte Instruktion:
Code:
MOV [ECX*4+EAX+0x20000000], EBX


[1] http://www.sandpile.org/ia32/opc_1.htm
[2] http://www.sandpile.org/ia32/opc_enc.htm
[3] http://www.sandpile.org/ia32/opc_rm32.htm
[3] http://www.sandpile.org/ia32/opc_sib.htm
 
Hallo +++ATH0,

trotz von deinem sehr ausführlichen Beitrag bleiben ein paar Fragen von meiner Seite offen.
  • In dem ersten Codebeispiel ist geschrieben, dass die JNZ-Anweisung 2 Bytes groß ist. Woher weiß man das bzw. wo gibt es einen Nachweis dafür?
  • Zudem gibt es bei der JNZ-Anweisung ein Opcode, das 43 Bytes nach vorne springt. Ist es möglich sich das in einem Hex-Editor anzuschauen oder das irgendwie nachzuvollziehen?

the_uxreal
 
In dem ersten Codebeispiel ist geschrieben, dass die JNZ-Anweisung 2 Bytes groß ist. Woher weiß man das bzw. wo gibt es einen Nachweis dafür?
naja, abgesehen von der opcode.hlp
75 cb JNZ rel8 Jump short if not zero (ZF=0)
im Intelmanual:
http://www.intel.com/design/PentiumII/manuals/243191.htm
75 cb JNZ rel8 Jump short if not zero (ZF=0)

cb, cw, cd, cp?A 1-byte (cb), 2-byte (cw), 4-byte (cd), or 6-byte (cp) value following the
opcode that is used to specify a code offset and possibly a new value for the code segment
register.
dh 75 steht für JNZ und das Byte danach für die Distanz.

Zudem gibt es bei der JNZ-Anweisung ein Opcode, das 43 Bytes nach vorne springt. Ist es möglich sich das in einem Hex-Editor anzuschauen oder das irgendwie nachzuvollziehen?
Ähm, das die Anweisung ist in Deinem Screenshot markiert ;)
Code:
41157D   75 2B
heißt: Aktuelle_Adresse(41157D)+Größe_der_Instruction(2)=(41157F) +2B = Zieladresse: 4115AA
 
Original von the_uxreal
Hallo +++ATH0,

trotz von deinem sehr ausführlichen Beitrag bleiben ein paar Fragen von meiner Seite offen.
  • In dem ersten Codebeispiel ist geschrieben, dass die JNZ-Anweisung 2 Bytes groß ist. Woher weiß man das bzw. wo gibt es einen Nachweis dafür?
  • Zudem gibt es bei der JNZ-Anweisung ein Opcode, das 43 Bytes nach vorne springt. Ist es möglich sich das in einem Hex-Editor anzuschauen oder das irgendwie nachzuvollziehen?

the_uxreal

CDW hat es ja jetzt nochmal für das Intel-Manual gezeigt.
Aber was spricht denn dagegen, die gleiche vorgehensweise wie ich sie oben beschrieben habe, nochmal für 0x75 durchzugehen? (sozusagen als kleine Hausaufgabe *g*)

Hier in der Tabelle [1] finden wir für 0x75 dann:
JNZ Jb

Schauen wir hier [2] nach wozu das J und das b ist:
J steht für einen Offset, relativ vom EIP Register.
Und das kleine b steht für ein Byte.

Dem Opcode (0x75) folgt demnach ein 1 Byte großer relativer Offset (0x2B) vom EIP aus. Macht insgesamt für die Instruktion 2 Byte.

So kannst du eigentlich den Aufbau und die Größe jeder Instruktion genaustens nachvollziehen.


[1] http://www.sandpile.org/ia32/opc_1.htm
[2] http://www.sandpile.org/ia32/opc_enc.htm
 
Hallo Leute,

vielen Dank für eure Hilfe, jedoch habe ich noch einige weitere Fragen.
  • Wie kann man sich im OllyDbg sich die Segmentregister(cs, ds, ss, es, fs, gs) anschauen?
  • Was bedeuten die weiteren Buchstaben(C, P, A, Z, S, T, D, O) unter den Registern rechts im OllyDbg?

the_uxreal
 
Original von the_uxreal
Wie kann man sich im OllyDbg sich die Segmentregister(cs, ds, ss, es, fs, gs) anschauen?

Ähmm. :D
flags69fr.jpg


Wird dir aber nicht viel helfen bzw. bringen. Alle Segment-Register (ausser FS,GS) zeigen auf die lineare Adresse 0. Logisch. Denn wir haben bei virtueller Adressierung theoretisch den gesamten 4GB Speicherraum (mit einigen Abstrichen) zur Verfügung.
Das FS-Register zeigt auf den TEB (Thread Environment Block).
Wahrscheinlich der Einfachheit halber. ;)

Original von the_uxreal
Was bedeuten die weiteren Buchstaben(C, P, A, Z, S, T, D, O) unter den Registern rechts im OllyDbg?

http://en.wikipedia.org/wiki/FLAGS_register_(computing)

Das müsste dir aber schon aufgefallen sein. Zum Beispiel bei JZ und JNZ Sprüngen. Bei diesen Instruktionen zum Beispiel hängt es vom [Z]ero-Flag ab, ob gesprungen wird.
 
Zurück
Oben