hallo,
wenn ich hello world mit ndisasm öffne kommt:
0000000 E80F000000 Call 0x14
0000005 usw.
wie kommt man von e80f000000 zu CALL 0x14 und umgekehrt?
Gibt es da eine Tabelle?
hallo,
wenn ich hello world mit ndisasm öffne kommt:
0000000 E80F000000 Call 0x14
0000005 usw.
wie kommt man von e80f000000 zu CALL 0x14 und umgekehrt?
Gibt es da eine Tabelle?
Also angenommen du hast einen E8-Call auf deine Funktion. Dann hast du 5 Bytes. Das erste Byte bekommt den Opcode E8 für CALL. Die anderen vier Bytes sind jetzt die Anzahl Bytes relativ von der nächsten Instruktion auf die Funktionsadresse.
Um von A nach B zu kommen, rechnen wir: B - A
Einfaches Beispiel zum Verständnis: Von 5 nach 20 rechnen wir 20 - 5, relativer Offset: 15
Angenommen:
- A ist dort, wo unser Funktionsaufruf (einer der vielen CALLs auf deine Funktion) ist
- B ist die Funktion, die wir aufrufen wollen
Da wir relativ von der nächsten Instruktion rechnen müssen, heißt es, dass unser Start A noch 5 Bytes weiter muss: Relative Adresse = B - (A + 5)
Im Endeffekt programmierst du dann sowas wie:
int new_relative_address = address_of_function - (address_of_call + 5)
Mit diesem Hintergrundwissen können wir ja mal dein ndisasm-Output untersuchen:
Ok, jetzt setzen wir die konkreten Werte in die Formel ein:Code:0000000 E80F000000 Call 0x14 | | | | | |---> new_relative_address in little-endian = 0x0000000F | | | ---> Der E8-Opcode | |---> address_of_call
Womit wir dann ohne die Information von ndisasm (Call 0x14) die absolute Funktionsadresse berechnet haben.Code:Gegeben: address_of_call = 0x00 new_relative_address = 0x0f Einsetzen in: new_relative_address = address_of_function - (address_of_call + 5) Eingesetzt: 0x0f = address_of_function - (0x00 + 5) Umgestellt: 0x0f = address_of_function - 5 Umgestellt: 0x0f + 5 = address_of_function Umgestellt: address_of_function = 0x14
Du siehst, es gibt keine Tabelle, sondern eine kleine Formel.![]()
Über das neue Zeitalter der Gehirne eines Menschen!
echo 'main() { char z[] = "ping "; for(;printf(z);z[1]^=6); }' > a.c; gcc a.c -o a; ./a # 16.11.2011 02:51
Tabelle z. B. http://ref.x86asm.net/coder32.html
Referenz sind sind die dicken x86-Bücher von Intel. Die konnte man sich früher mal kostenlos schicken lassen; weiß nicht, ob es das noch gibt.
thx thx,
@gruena
ok, soweit ist es mir ja klar, aber was ist jetzt E8 Opcode ? Das kommt doch auch ein z.b.mov oder push sein? :-)
Oh, schön das dir soweit alles klar war.
Der Opcode E8 ist ein CALL, daran kann man nichts mehr rütteln. Andere Instruktionen haben wiederum ihre eigenen Opcodes und auch eine andere Anzahl Bytes die er in Anspruch nimmt. Der CALL ist 5 Bytes, andere können nur 1 Byte haben zum Beispiel.
Shakademus hat dir eine nette Referenz-Tabelle mitgeteilt. Strg+F und nach E8 suchen und den Anker-Link klicken.![]()
Über das neue Zeitalter der Gehirne eines Menschen!
echo 'main() { char z[] = "ping "; for(;printf(z);z[1]^=6); }' > a.c; gcc a.c -o a; ./a # 16.11.2011 02:51
oh da ist ja ein link, ok alles klar
Viele Instruktionen folgen ausserdem einem allgemeinen Format, normalerweise ein Op-Code, u.U. mit Laengenangabe (16/32 bit, bzw. 64 im Long Mode), und wenn ich es richtig in Erinnerung habe, dahinter ein r/m-byte (register/memory), das entweder Register angibt, oder eine bestimmte Art der Speicheradressierung (z.b. auch relativ zu einem Register), was gleichzeitig auch bewirkt, dass hinten nach noch weitere Bytes folgen, welche die Speicheradressen enthalten.
Die Registerwerte sind in den Instruktionen auch gleich codiert, somit kann man teilweise Maschinencode spontan im Kopf zusammendenken, wenn man ein paar Instruktionen auswendig kennt.
0x31 0xC9 ist beispielsweise ein "xorl %ecx,%ecx;", eine einfache Moeglichkeit, den Wert 0 in den Register ECX zu kriegen.
Im zweiten Byte sind die Register codiert - binaer 11001001, der wesentliche Teil sind die zwei '001'. Die allgemeinen Register EAX bis EDX sind einfach durchnummeriert, allerdings etwas unintuitiv: EAX=0, ECX=1, EDX=2, EBX=3.
Somit kannst du die Instruktion leicht aendern:
0x31 0xC0 = xorl %eax,%eax
Im Long-Mode heisst das ganze "xor %rax,%rax;", und arbeitet mit 64 bit, der Maschinencode ist aber immer noch der selbe. Das ist allerdings nicht allgemeingueltig, beispielsweise kommt bei manchen MOVs im Long Mode ein Byte hinzu.
Segmentation fault (core dumped)
Oder auch hier: http://www.sandpile.org/
Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)