Assembler, Mnemonics, Opcodes und Architekturen.
-
Zu 1)
Der Opcode ist einfach der vordere Teil eines Maschienenbefehls, der angibt um welche Operation es sich handelt. Ein Mnemonic ist einfach eine für den Menschen besser lesbare Darstellung des Opcodes. Da, wie du schon erkannt hast, das nicht immer 1:1 übersetzt wird, würde ich das nicht gleichsetzen.Zu 2)
Wie schon gesagt wurde, hat das Betriebssystem nichts mit der Codeausführung zu tun. Das BS läd das Programm in den Speicher und springt in den Code. Der Prozessor führt dann ausschließlich den Programmcode aus, bis aus dem Programm auf BS Funktionen zugegriffen wird, oder ein Interrupt auftritt. Bei unbekannten oder fehlerhaften Befehlen wird ebenfalls ein Interrupt (Je nach Architektur auch Exception genannt) ausgelöst und dementsprechend die Kontrolle an das BS übergeben, das dann in der Regel das Programm beendet. Damit hat der Prozessor dann aber wenig zu tun. Es gibt durchaus auch Exceptions die vom BS behandelt werden können und nicht zum beenden des Programms führen.Zu 3)
Es kommt da auch sehr stark darauf an wie groß die Standardbibliothek ist, und wieviel davon statisch mitgelinkt wird. Interpretierte und VM Sprachen sind da aber Sonderfälle, da bei denen die Standardbibliothek im Interpreter/VM stecken und nicht im "Programm".Zu 4)
http://www.lowlevel.eu/wiki/PE oder für mehr Details die offizielle Spec http://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx
-
Der aus dem Westen ... schrieb:
1. Frage: Dieser Maschinencode ist binär, ich weiß. Wenn ich das Ganze aber mit einem Texteditor betrachte, der die Werte als Maschinenbefehle ansieht, zeigt dieser mir auch Mnemonics an, Labels, die genauer beschreiben, was der Befehl tut. Obwohl diese Mnemonics ein bisschen mit Assembler zu tun haben (in Assembler-Dialekten werden allerdinds manchmal Anweisungen geschrieben, die so im Maschinencode nicht auftauchen) nennt man sie offiziel (glaube ich zumindest, deshalb frage ich) Opcodes, weil es ja kein Assembler mehr ist, sondern richtige Maschinensprache, richtig?
? nicht ganz klar. Aber Opcode ist einfach der Maschinencode, Assembler arbeiten dagegen mit Assemblerdirektiven, Macros und den ->Mnemonics, die wiederum nichts anderes sind, als eine wörtliche Entsprechung des Maschinenbefehls:
Opcode: 01d8 bzw. 0000 0001 1101 1000 bzw. Schaltergedöns
Mnemonic: add ax,bx
Frage: mit welchem Befehl kann man die beiden Register dx und cx zusammenzählen? a)obcode b)mnemonic2.
Der aus dem Westen ... schrieb:
Wie diese Opcodes interpretiert werden, ist Sache des Prozessors und des Betriebssystems (?). Was passiert, wenn das OS auf einen Befehl trifft, den er nicht kennt, standardmäßig?
siehe Tobiking2 und z.B.
http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte6kxc.htm3. siehe oben
Es werden in der Regel Bibliotheken für alles mögliche mitgeschleppt, und mehr Speicherzugriffbefehle und Stackbearbeitung als Register vs Register benutzt und wie man dem Code auch immer ansieht, jede Menge Redundanz usw.
Ganz lesenswert dazu:
http://www.mikrocontroller.net/articles/ASM_vs_C4.
Der aus dem Westen ... schrieb:
Und was machen diese "MZ"?
siehe u.a.:
http://de.wikipedia.org/wiki/Mark_Zbikowski
Hauptsächlich unterscheidt diese Signatur Exe von Com Programmen. Für Exe Programme übernimmt Dos die Reallokation, bei .com Programmen muss das von Hand gemacht werden.
Siehe auch noch hier:
http://www.lowlevel.eu/wiki/MZ_EXE5.
Der aus dem Westen ... schrieb:
(nur Windows) Im Header muss eigentlich auch stehen, für welche Architektur das Programm kompiliert wurde. Ich vermute, dass, wenn die entsprechende Information gesetzt wurde und das Programm auf einer x64-Plattform läuft, automatisch die Bibliotheken für den WOW64-Emulator geladen werden, oder?
Auch wieder nicht ganz klar. Der Windows kernel enthält viele Emulatoren, ist ein reines Multiemutalent. Für unterschiedliche Plattformen muss aber auch unterschiedlich compiliert werden. Bisher war es meist so, dass native Programme normalerweise nicht davon ausgehen, auf einer anderen Plattform ausgeführt zu werden.
-
ad 2) - Ungültige Opcodes (bzw. allgemein Befehle)
Die meisten Prozessoren, haben dafür sog. "fault handler". Nicht nur "invalid instruction" ist so ein fault, sondern auch die allseits beliebte "access violation" bzw. "segmentation violation" oder "division by zero" funktionieren über diesen Mechanismus.
Erkennt die CPU also einen ungültigen Befehl, dann führt sie stattdessen den "fault handler" für "invalid instruction" aus.
Passiert dabei wieder etwas (ein weiterer "fault"), dann nennt man das "double fault", und es wird der "double fault handler" ausgeführt.
Sollte das dann immer noch nicht hinhauen, dann nennt man das "triple fault". Die meisten CPUs quittieren das damit, dass sie einfach anhalten, oder sich komplett resetten.Über diese "fault handler" Funktionen kann das Betriebssystem kontrollieren, was bei einem "fault" passieren soll. Es kann also z.B. das verursachende Programm kontrolliert abgebrochen werden, ohne dass gleich das ganze OS hopps geht. Windows erlaubt es einem Programm sogar sich da einzuklinken, so dass es bestimmte Dinge selbst regeln kann, ohne dass das Programm dadurch gleich abgebrochen wird.
ad 3) - Die grossen VB Programme
Der Grund warum solche Programme so gross werden, ist die dazugelinkte Runtime. Auch ein Visual C++ Programm kann schnell mal ein paar zig oder hundert Kilobyte haben, wenn man die Runtime statisch dazulinkt, und ein paar Runtime-Funktionen verwendet die viele andere mit reinziehen.ad 4) - Das .exe Format
Wenn du wissen willst wie eine Windows .exe aufgebaut ist, dann guck bei Wikipedia nach, Stichwort PE Format (Portable Executable). Linux verwendet soweit ich weiss das ELF Format.Und eine ".exe" "besitzt" ganz sicher keine Register, und wird auch nicht "in Register geladen". Wenn du wissen willst was ein Register ist, empfehle ich ebenso Wikipedia.
ad 5) - Die .exe Header
Ja, in der Header steht auch drin ob ein Programm 32 Bit oder 64 Bit Code enthält. Das OS sieht dies beim Laden, und erzeugt dann entsprechend einen 32 Bit oder einen 64 Bit Prozess. Bzw. ein 32 Bit Windows sieht dann, dass es mit dieser .exe nix anfangen kann, und meldet entsprechend dass das Programm unter dieser Windows Version nicht verwendet werden kann.Der aus dem Westen ... schrieb:
Sagen wir mal so, ich verwende Texteditore, die diesen Feature unterstützen - schon mal was von HIEW gehört?
HIEW ist kein Texteditor.
-
SeppJ schrieb:
Das heißt im Klartext, du hast das Programm deassembliert und wunderst dich nun, dass du Assembleranweisungen siehst?
Nein, habe ich aber auch nicht gesagt ...
Sieh mal, wenn ich mit einem Assembler-Dialekt Programmiere (masm, tasm, fasm), kann ich spezielle, sehr maschinennahe Operationen ausführen, die jedoch kein Teil des Befehlssatzes eine x86 sind (zum Beispiel). Wenn ich mein Programm disassembliere, kann ich diesen Maschinencode sehen, aber die Anweisungen meines Assemblerprogramms (also das, was in meiner *.asm-Datei steht) stehen dort nur bedingt drin.
cooky451 schrieb:
Das ist ein Debugger, und halt kein Texteditor. Ein Texteditor liest nur Text und da steht halt nichts von mov, add, jmp etc.
Deswegen war ich gerade etwas verwirrt.Deshalb hatte ich ja auch HIEW im Hinterkopf.
Tobiking2 schrieb:
Zu 1)
Der Opcode ist einfach der vordere Teil eines Maschienenbefehls, der angibt um welche Operation es sich handelt. Ein Mnemonic ist einfach eine für den Menschen besser lesbare Darstellung des Opcodes. Da, wie du schon erkannt hast, das nicht immer 1:1 übersetzt wird, würde ich das nicht gleichsetzen.Ja, gut, war ein bisschen missverständlich ausgedrückt. Ich weiß, dass bei diesen Befehlen oft auch Indizes für Register oder Speicheradressen verwendet werden, sozusagen als Parameter.
nachtfeuer schrieb:
Frage: mit welchem Befehl kann man die beiden Register dx und cx zusammenzählen? a)obcode b)mnemonic
Ist das ein Test?
Mnemonic dürfte:
mov ax,dx add ax,cx
sein, oder? Binär weiß ich jetzt leider nicht ...
nachtfeuer schrieb:
Auch wieder nicht ganz klar. Der Windows kernel enthält viele Emulatoren, ist ein reines Multiemutalent. Für unterschiedliche Plattformen muss aber auch unterschiedlich compiliert werden. Bisher war es meist so, dass native Programme normalerweise nicht davon ausgehen, auf einer anderen Plattform ausgeführt zu werden.
Ja, das weiß ich. Und auch, wenn die Header für das OS kompatibel sind, heißt das noch nicht, dass sie auch binärkonform ist. Soweit ich mich darin eingelesen habe, sind Windows-Exen absolut, was die Speicheradressen angeht (führt, wenn der virtuelle Adressraum, den die Exe beansprucht, noch nicht voll ist - aus diesem Grund besitzen die System-DLLs auch feste Basisadressen, die nicht so häufig benutzt werden - zu einem immensen Geschwindigkeitsvorteil, kann aber auch zu einem massiven Geschwindigkeitsverlust führen, wenn das OS die Adressen umwandeln muss, weil die Adressen bereits belegt sind), während Unix-Exen relative Speicheradressen verwenden.
hustbaer schrieb:
ad 3) - Die grossen VB Programme
Der Grund warum solche Programme so gross werden, ist die dazugelinkte Runtime. Auch ein Visual C++ Programm kann schnell mal ein paar zig oder hundert Kilobyte haben, wenn man die Runtime statisch dazulinkt, und ein paar Runtime-Funktionen verwendet die viele andere mit reinziehen.Verstehe.
hustbaer schrieb:
ad 4) - Das .exe Format
Wenn du wissen willst wie eine Windows .exe aufgebaut ist, dann guck bei Wikipedia nach, Stichwort PE Format (Portable Executable). Linux verwendet soweit ich weiss das ELF Format.Und eine ".exe" "besitzt" ganz sicher keine Register, und wird auch nicht "in Register geladen". Wenn du wissen willst was ein Register ist, empfehle ich ebenso Wikipedia.
Register? Ach du Scheiße, ich meinte Segmente.
Also .text, .data, .rdata und so. Soweit ich weiß, stammen die noch aus der Zeit der 20-Bit-CPUs, als man 1 MB an Speicher reservieren konnte und noch so bescheuerte Konzepte wie FAR- und NEAR-Zeiger.
Ein Register ist ein (eher flüchtiger) Speicher auf der CPU, in dem Werte sehr schnell gesichert und verarbeitet werden können, das weiß ich schon. Ein Segment hingegen enthält Teile der Exe - Code in .text, Daten in .data usw.
hustbaer schrieb:
HIEW ist kein Texteditor.
HIEW unterstützt drei Ansichten einer Datei - Textformat (verwendet dabei wohl die .OEM-Codierung des OS), Hex-Editor-Format und Disassemblierformat. Deshalb kann man es schon als einen Texteditor sehen - mit einigen texteditoruntypischen Features.
-
Nach der Logik könnte man auch Visual-Studio als Zeichenprogramm bezeichnen, weil man damit in Bitmaps rummalen kann. Wäre aber genauso sinnfrei.
"Ich hab da so ein Zeichenprogramm, mit dem kann man auch programmieren"
-
Der aus dem Westen ... schrieb:
Ist das ein Test?
Nein, das sollte nur helfen, den Unterschied einzuordnen. Für Low Level Geschichten ist das Windowsprogramm debug oder ein 32bit Clone davon sehr gut:
C:\Users\nachtfeuer>debug -a 19F4:0100 add cx,dx 19F4:0102 -r AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=19F4 ES=19F4 SS=19F4 CS=19F4 IP=0100 NV UP EI PL NZ NA PO NC 19F4:0100 01D1 ADD CX,DX -u 19F4:0100 01D1 ADD CX,DX 19F4:0102 0000 ADD [BX+SI],AL 19F4:0104 0000 ADD [BX+SI],AL 19F4:0106 0000 ADD [BX+SI],AL 19F4:0108 0000 ADD [BX+SI],AL 19F4:010A 0000 ADD [BX+SI],AL 19F4:010C 0000 ADD [BX+SI],AL 19F4:010E 0000 ADD [BX+SI],AL 19F4:0110 0000 ADD [BX+SI],AL 19F4:0112 0000 ADD [BX+SI],AL 19F4:0114 0000 ADD [BX+SI],AL 19F4:0116 0000 ADD [BX+SI],AL 19F4:0118 0000 ADD [BX+SI],AL 19F4:011A 0000 ADD [BX+SI],AL 19F4:011C 3400 XOR AL,00 19F4:011E E319 JCXZ 0139 -
-
Was spricht denn gegen den Ollydbg?^^
-
nachtfeuer schrieb:
Nein, das sollte nur helfen, den Unterschied einzuordnen.
Maschinencode (so wie ihn mir der Hex-Editor HIEW ausgibt):
8B FF 55 8B EC E8 79 1F FF FF
Mnemonics:
mov edi,edi push ebp mov epb,esp
Wobei mir nicht klar ist, warum man edi nach edi kopieren muss. Sollte mich aber nicht wundern, schließlich handelt es sich hier um den Code der API-Funktion
RegOpenKey
, und wir wissen ja, was Microsoft so alles anstellt ...
-
Der aus dem Westen ... schrieb:
Wobei mir nicht klar ist, warum man edi nach edi kopieren muss. Sollte mich aber nicht wundern, schließlich handelt es sich hier um den Code der API-Funktion
RegOpenKey
, und wir wissen ja, was Microsoft so alles anstellt ...Das hat schon seinen Sinn:
http://msdn.microsoft.com/en-us/library/ms173507.aspx
http://technet.microsoft.com/en-us/library/cc787843(v=WS.10).aspx
-
das ist aber bei bei dieser Adresse hier etwas besser erklärt:
http://blogs.msdn.com/b/ishai/archive/2004/06/24/165143.aspx
-
Wenn ich das also recht verstanden habe, werden diese zwei Byte dafür verwendet, einen Platzhalter für einen kurzen Jumpbefehl zu bilden (nur zwei Bytes), der hinterher auf einen größerem Jumpbefehl verweist. Dies hat den Vorteil, dass man so noch ein Abbild der Funktion, die man patchen will, irgendwo im Speicher hat, sodass es nicht notwendig ist, Anwendungen, die diese Funktionen nutzen, anzuhalten - wenn mein Programm also bspw.
RegOpenKey
verwendet, gerade aber ein Update der Reg-Dll läuft, werden alle Funktionaufrufe zu einer "virtuellen" Funktion umgeleitet, während die "reelle" Funktion umgeschrieben wird.Korrekt?