Register for your free account! | Forgot your password?

Go Back   elitepvpers > Coders Den > General Coding > Coding Tutorials
You last visited: Today at 04:27

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[AutoIt & Assembler] Assembler lernen und in AutoIt benutzen

Discussion on [AutoIt & Assembler] Assembler lernen und in AutoIt benutzen within the Coding Tutorials forum part of the General Coding category.

Reply
 
Old   #1
 
elite*gold: 77
Join Date: May 2008
Posts: 5,131
Received Thanks: 5,225
[AutoIt & Assembler] Assembler lernen und in AutoIt benutzen

1. Vorwort
1.1. Vorraussetzungen für das Programmieren mit Assembler
1.2. Ein paar Fakten zu Assembler/Computern
1.3. Warum Assembler benutzen
2. Assembler Allgemein
2.1. Arbeitsweise von Assembler
2.2. Syntax und Semantik
2.3. Register
3. Erste Assembler Schritte
3.1. Mov
3.2. Add und Sub
3.3. Inc und Dec
3.4. Cmp und Jmp/Jne/Je/Jbe/Jge/Jle/...
3.5. Push/Pop
3.6. Variablen in ASM
3.7. Sonstige wichtige Befehle
4. Assembler-Codes
4.1. Berechnen der Fakultät einer ganzen Zahl
4.2. Potenzieren einer ganzen natürlichen Zahl mit ganzen Exponenten
5. AutoIt und Inline-Assembler
5.1. Erstes Programm mit Assembler und AutoIt
5.2. 2 Zahlen in ASM addieren
5.3. Einen kleinen Taschenrechner mit Parser schreiben
5.4. Eine einfache Verschlüsselungsroutine schreiben
6. AutoIt-Skripts in Assembler-Codes umschreiben
7. Quellen

-------------------------------------------------------------------------------------------------


1. Vorwort
1.1. Vorraussetzungen für das Programmieren mit Assembler

Eine Vorraussetzung wäre auf jeden Fall grob zu wissen wie ein Computer
funktioniert. Wer immer noch denkt, dass im Computer kleine Männchen
herum laufen, der kann sofort aufhören weiter zu lesen.
Assembler ist nur verständlich, wenn man auch weiß wie ein Computer funktioniert.
Wer nicht weiß was Variablen wirklich sind und wer keine Ahnung hat was
AutoIt mit dem Source-Code macht, der ist hier ebenfalls falsch.
Ich kann euch nicht empfehlen als Neuling auf dem Gebiet direkt mit Assembler
ein zu steigen.
Assembler ist zwar auch nicht schwerer als andere Sprachen, aber es dauert etwas länger bis man
sich eingearbeitet hat.

Nachdem wir uns jetzt endlich für bereit halten, brauchen wir noch ein paar
Programme/Skripts:



In dieser Rar-Datei liegt alles benötigte drinnen.
Am besten ist, wenn ihr die Skripts in euren AutoIt-Include Ordner verschiebt.


-------------------------------------------------------------------------------------------------


1. Vorwort
1.2. Ein paar Fakten zu Assembler/Computern

Keine Angst, ich werde euch nicht bombadieren mit Informationen rund um Assembler.
Ich möchte nur kurz ein paar Sachen erwähnen, die ich für interessant/wichtig halte.

1. Der erste Computer war nur über Verbinden von Datenleitungen programmierbar.
Die ersten Rechner waren richtige Monster wogen teilweise über 500kg und hatten
gerade einmal ein paar Herz Takt. Das heißt sie haben für die Addition von
2 Zahlen ungefähr 1/2 - 1 Sekunde gebraucht (Heutzutage geht das in ein paar nanosekunden).

2. Die erste richtige Programmiersprache wurde ca. 1952 erfunden und war Assembler.

3. Es folgten etliche weitere Sprachen in den nächsten Jahren unter anderem auch C (1971–1973).

4. AutoIt wurde 1999 als Skriptsprache von Jonathan Bennett für seine Arbeit entwickelt.


-------------------------------------------------------------------------------------------------


1. Vorwort
1.3. Warum Assembler benutzen

Assembler ist und bleibt die maschinennäheste Sprache, die es gibt.
Außerdem ist Assembler schlicht weg schneller als AutoIt.
Für Zeitkritische und hardwarenahe Funktionen ist Assembler also sehr gut geeignet.
In AutoIt wurde leider sehr viel abstrahiert. Dadurch ist man gewisser Maßen eingeschränkt.
Assembler hat aber auch einen Nachteil, man muss sich um alles selbst kümmern, außerdem vergeht
einem bei größeren Programmen meistens die Lust sich da wieder ein zu lesen.

Die Kombination von Hardwarenähe/Geschwindigkeit und Abstraktion/"Aufräumen" bringt
die Möglichkeit mit sich, je nach Situation, das Problem bestmöglich zu lösen.


-------------------------------------------------------------------------------------------------


2. Assembler Allgemein
2.1. Arbeitsweise von Assembler

Im Gegensatz zu AutoIt ist Assembler keine Interpretsprache.
Das heißt der Code, den wir in ASM (=Assembler) schreiben wird von einem Compiler
später so umgewandelt, dass unsere Befehle ohne Umwege vom Computer ausgeführt werden können.
Dementsprechend Fehleranfällig ist ASM aber auch, 2 eckige Klammern vergessen und unser Programm
crasht mit einer schönen Windows-Fehlermeldung.
Man sollte also besonders bei Assembler auf mögliche Probleme achten und sie möglichst schon
im Keim ersticken.

Assembler arbeitet die Befehle (ähnlich wie AutoIt) im normalfall von oben nach unten ab.
Wir werden später sehen, dass wir auch ganz unten anfangen können und uns dann hoch arbeiten können,
aber das macht selten Sinn und verwirrt nur unnötig.

Der Programmfluss ist also im Regelfall von Oben nach Unten, genau so wie bei AutoIt.


-------------------------------------------------------------------------------------------------


2. Assembler Allgemein
2.2. Syntax und Semantik

Die Syntax von ASM ist im Grunde immer die Gleiche:

Code:
ASM-Befehl Wert1[, Wert2, ...]
In ASM werden die Übergabeparameter im Gegensatz zu AutoIt nicht in Klammern geschrieben, sondern
einfach hinter den Befehl getrennt mit einem (oder mehreren) Leerzeichen.

In ASM kann maximal ein Befehl pro Zeile ausgeführt werden.
So würde dann ein Teil eines ASM-Codes aussehen:

Code:
ASM-Befehl Wert1[, Wert2, ...]
ASM-Befehl Wert1[, Wert2, ...]
ASM-Befehl Wert1[, Wert2, ...]
ASM-Befehl Wert1[, Wert2, ...]
...

-------------------------------------------------------------------------------------------------


2. Assembler Allgemein
2.3. Register

Nun sind wir schon bei den Registern angekommen, hat man erst einmal verstanden was die Register sind, macht ASM an sich auch keine Probleme mehr.

Register kann man als vordefinierte Variablen sehen.
Die meisten Register mit einem "e" am Anfang haben eine Größe von 32-Bit, das entspricht 32 0en bzw. 1en, damit lassen sich ganze
Zahlen bis 4.294.967.296 darstellen (in den meisten Fällen genug).
Es gibt nicht viele Register, aber jedes Register hat eine gewisse Bedeutung.

Vergleichen kann man das ganze mit @Error in AutoIt.
Man kann @Error nicht umbennen, aber man kann den Wert ändern durch SetError(...).
@Error kann für alles mögliche benutzt werden, wird aber meistens nur für Errors benutzt,
um Verwirrung vorzubeugen.

Die Register in ASM haben auch solche Eigeschaften, sie können nicht umbenannt werden, können aber
ihre Werte ändern.

Die Namen der Register sind wie folgt:

eax allgemein verwendbar, spezielle Bedeutung bei Rechenbefehlen
ebx allgemein verwendbar
ecx allgemein verwendbar, spezielle Bedeutung bei Schleifen
edx allgemein verwendbar
ebp Basepointer
esi Quelle (eng: source) für Stringoperationen
edi Ziel (eng: destination) für Stringoperationen
esp Stackpointer

Wem die oben aufgeführten Begriffe nichts sagen, der braucht sich nicht wundern, denn die meisten
dieser Register werden später in Beispielen benutzt und dort wird oft sehr schnell klar was das Register jetzt macht/wofür es genommen wird.

Ein Register besteht aber wiederum aus Registern.
Die ersten 16-Bit des Registers eax heißen z.b. ax.
Die ersten 8-Bit des Registers ax bestehen wiederum aus al und die 2. 8-Bit bestehen aus ah.

Es ist nicht wichtig zu wissen welches Register aus welchen Registern besteht, es ist nur
wichtig zu wissen, dass es soetwas gibt und dass jedes Register (meistens) aus weiteren Registern besteht.

Anmerkung:
Kommentare können in ASM mit einem ; (Strichpunkt) gemacht werden,
ähnlich wie in AutoIt.


-------------------------------------------------------------------------------------------------


3. Erste Assembler Schritte
3.1. Mov

Vorerst werden wir reinen Assemblercode versuchen zu verstehen und zu schreiben,
da es bei AutoIt und Inline-Assembler noch ein paar Kleinigkeiten zu beachten gibt.
Ich fange mit diesem Befehl an, weil er ein am Anfang für mich extrem schwer zu verstehendes
Phänomen zeigte.

Aber kurz bevor wir zum Befehl kommen, ein paar Informationen:

Wir wissen ja wie Assembler-Befehle aufgebaut sind:

Code:
ASM-Befehl Wert1[, Wert2, ...]
Es gibt da jetzt aber noch eine Kleinigkeit zu beachten, die vielleicht etwas komisch klingen mag.
Man kann nämlich auf den Wert der Register zugreifen oder auf die Adresse an der der Wert gespeichert wurde.
Wenn der Computer die Werte abspeichert, versieht er sie automatisch mit einer Nummer.
Diese Nummer ist unsere Adresse. Diese Adresse braucht der Computer, damit wir ihm sagen können:
"Wir wollen den Wert an der Stelle Nummer 10".

Würden wir den Computer nur sagen, dass wir einen Wert wollen, dann wüsste er nicht welchen Wert wir jetzt wollen.
In AutoIt wird uns die Arbeit der "Nummern" durch die Variablennamen abgenommen.
Der Interpret des AutoIt-Codes weiß dann genau, dass wir den Wert mit dem Namen "$Variable1" wollen.
Der Interpret nimmt uns also die Arbeit ab und macht uns das Leben leichter indem er statt Zahlen
Namen nimmt, die wir uns leichter merken können.

So könnte für AutoIt der Namen "$hallo" die Adresse/Nummer "5126" haben.

Aber zurück zu Assembler.
In Assembler müssen wir das selbst erledigen (zumindest bei Registern).
Da wir die Register nicht umbenennen können und die Namen der Register für den
Compiler fast irrelevant sind, müssen wir uns selbst um die Addressierung/Nummerierung kümmern.
Und uns selbst eine passende Speicherstelle suchen.

Das hat aber auch gewisse Vorteile, denn damit haben wir jetzt viel mehr Freiheit als früher,
scheint zwar auf den ersten Blick Blödsinn zu sein, aber im Laufe des Tutorials wird das hoffentlich
klar werden.

So, nachdem wir alles so ausführlich besprochen haben, sind wir bereit für unser erstes Assembler-Programm:

Code:
Mov eax, edi
Schaut doch gut aus und natürlich weiß jeder auf den ersten Blick was gemeint ist.

Zuerst bevor wir genauer auf das Beispiel eingehen, will ich kurz die Syntax des Mov-Befehls erklären.

Code:
Mov Destination, Source
Wobei Destination in unserem Fall eax und Source in unserem Fall edi ist.

Aber was passiert hier?
Eigentlich ist es relativ einfach.
Es wird einfach nur die Adresse von edi in eax kopiert.

Vor dem Ausführen des Codes sieht es folgendermaßen bei uns aus.
(Ich habe Startwerte genommen, die normalerweise falsch sind, aber dadurch
lässt sich das ganze wohl besser nachvollziehen).

RegisterAdresseWert
eax05
edi81

Danach sieht es so aus:

RegisterAdresseWert
eax81
edi81

Aber auch das geht:

Code:
Mov eax, [edi]

Vor dem Codeasuführen:

RegisterAdresseWert
eax050
edi832

Danach:

RegisterAdresseWert
eax320
edi832

Das kann man jetzt so weiter führen.


Jetzt schauen wir uns einmal etwas komplexeres an:

Code:
mov edi, 4
mov edx, edi
mov eax, edx
Wenn man mit Registern rechnet, so wird im Normalfall mit den Adressen gerechnet und nicht mit den Speicherwerten.
Deswegen benutzen wir hier auch Adressen zum Abspeichern der Werte.

Tabelle vor dem Code (Die Startwerte sind wieder nur ausgedacht und dienen der besseren Verständlichkeit):

RegisterAdresseWert
edi00
edx325
eax6412

Tabelle danach:

RegisterAdresseWert
edi40
edx40
eax40


-------------------------------------------------------------------------------------------------


3. Erste Assembler Schritte
3.2. Add und Sub

2 weitere wichtige Befehle sind Add und Sub.

Die Syntax sieht wie folgt aus:

Code:
Add Destination, Source
Code:
Sub Destination, Source
Add, addiert 2 Zahlen und speichert das Ergebniss in "Destination".
Sub subtrahiert 2 zahlen und speichert das Ergebniss in "Destination".

Recht viel mehr gibt es darüber nicht zu wissen, also schauen wir uns gleich ein kurzes Beispiel an:


Code:
Mov edi, 17
Add edi, 3
Davor:

RegisterAdresseWert
edi00

Danach:

RegisterAdresseWert
edi200

Ich denke das ist nicht schwer zu verstehen, deswegen gehen wir gleich zu etwas größerem über
(Btw. Die Groß- und Kleinschreibung von ASM-Befehlen ist total egal):

Code:
mov edi, 4
mov edx, 16
sub edi, edx
mov eax, edi
add eax, edi
Weil es für einen Anfänger doch etwas viel auf einmal sein kann, schauen wir uns die Werte der Register
nach jeder Zeile Code einmal an.

Ausgang:
RegisterAdresseWert
edi00
edx00
eax00

Nach diesen Zeilen Code,

Code:
mov edi, 4
mov edx, 16
sieht das so aus:

RegisterAdresseWert
edi40
edx160
eax00

Danach:

Code:
sub edi, edx
sieht es so aus:

RegisterAdresseWert
edi-120
edx160
eax00

Danach:

Code:
mov eax, edi
siehts so aus:

RegisterAdresseWert
edi-120
edx160
eax-120

und ganz zum Schluss sieht es so aus (nach "add eax, edi"):

RegisterAdresseWert
edi-120
edx160
eax-240


Das ganze in AutoIt-Code sähe ungefähr so aus:

PHP Code:
$edi=4
$edx
=16

$edi
=$edi $edx
$eax
=$edi
$eax
=$eax $edi 

-------------------------------------------------------------------------------------------------


3. Erste Assembler Schritte
3.3. Inc und Dec

Syntax:

Code:
Inc Destination
Inc erhöht Destination um 1.

Inc ist also fast gleich zu setzen mit

Code:
Add Destination, 1
Dementsprechend ist es auch mit Dec.

Code:
Dec Destination
ist gleich zu setzen mit:

Code:
Sub Destination,1
Wenn die beiden Befehle das selbe machen, warum braucht man dann inc/dec?
Die Antwort ist relativ einfach, Inc braucht 2 Taktzyklen weniger als Add.
Add braucht 3 Taktzyklen und Inc nur 1 Taktzyklus.

Dadurch kann man seinem Assembler Programm zusätzlich "Speed" verleihen.
Inc/Dec wird besonders gerne in Schleifen eingesetzt.
Ein Beispiel zu Inc/Dec kommt später.


-------------------------------------------------------------------------------------------------


3. Erste Assembler Schritte
3.4. Cmp und Jmp/Jne/Je/Jbe/Jge/Jle/...

Cmp ist Kurzschreibweise für Compare (=Vergleichen).
Mit dem Befehl cmp werden also 2 Werte verglichen.

Syntax:

Code:
cmp Source1, Source2
Auf ein Beispiel angewandt sieht es dann so aus:

Code:
mov eax, 1
cmp eax, 2
Nachdem "cmp eax, 2" ausgeführt wurde, werden das sog. Flag-Register je nach dem
welches Ergebniss "cmp" hat gesetzt. Die Funktionsweise von "cmp" ist relativ simpel.
Die beiden zahlen werden von einander abgezogen und anschließend wird geschaut welches
Ergebniss "cmp" erhält. Je nach Ergebniss werden andere Register des Flag-Registers geändert.
Es wird also die Eigenschaft der beiden zahlen im vergleich in einem extra register gespeichert, das
man später abfragen kann.

So bringt uns das aber relativ wenig, in Verbindung mit JNE/JE/JMP/... hingegen
wird der Befehl wichtiger.

Aber zuerst widmen wir uns dem Befehl "Jmp".
Dieser Befehl springt zu einer bestimmten Stelle im Skript.
Man kann entweder zum Jmp-Befehl sagen: "Spring an die 2. Stelle im Code" oder
man sagt dem Jmp-Befehl: "Spring an die Stelle, an der du eine Sprungmarke mit dem Namen "Hier_kann_alles_stehen" findest".

Sprungmarken (=Labels) zu erstellen ist einfach:

Code:
Sprungmarke1:
Das ist bereits eine Sprungmarke, wir könnten jetzt noch ein Jmp drunter setzen:

Code:
Sprungmarke1:
Jmp Sprungmarke1
Und schon hätten wir eine Enlosschleife, die nichts macht.
In AutoIt sähe es so aus:

PHP Code:
While 1

wend 
Der Befehl Jmp springt aber immer zur angegebenen Sprungmarke, egal was passiert.
Genau deswegen gibt es gewisse Abwandlungen vom Jmp-Befehl:

JE, JNE, JA, JAE, JL, JLE, ...

Wenn wir einen dieser Befehle benutzen, dann müssen wir zuvor erst vergleichen lassen.
Der JE-Befehl springt nämlich nur, wenn das Flag-Register den richtigen Wert für JE hat.
Es muss sich also sozusagen zuvor ein "OK" geholt werden und dieses "OK" steht im Flag-Register.

Jetzt kann man sich auch einmal die Tabelle anschauen, in der man sieht welcher JMP-Befehl wann erfüllt ist:

JMP-BefehlAusgeschriebenBedeutung
JEJump EqualSpringe nur, wenn beide zahlen gleich groß sind
JAJump AboveSpringe nur wenn Source1 größer ist als Source2
JAEJump Above or EqualSpringe nur wenn Source1 größer oder gleich Source2 ist
JLJump LesserSpringe nur wenn Source1 kleiner Source2 ist
JLEJump Lesser or EqualSpringe nur wenn Source1 kleiner oder gleich Source2 ist

Mit diesen Kentnissen können wir auch ein kleines ASM-Programm schreiben.

Code:
mov eax, 30
mov edi, 0
Sprungmarke1:
add eax, 10
inc edi
cmp eax, 100
jne Sprungmarke1
Unsere Tabelle sieht nach den ersten beiden Zeilen so aus:

RegisterAdresseWert
eax300
edi00

Jetzt wird Sprungmarke1 vorerst ignoriert (es wird einfach weiter gemacht mit Zeile 4 "add eax, 10").

Es wird jetzt also zur Adresse von eax 10 addiert und edi wird um eins erhöht.
Anschließend wird geprüft, ob eax gleich 100 ist. ("cmp eax, 100")
Wenn eax jetzt ungleich 100 ist, dann springt das Programm zu "Sprungmarke1" zurück. ("jne Sprungmarke1")

Und am Ende sieht unsere Tabelle so aus:
RegisterAdresseWert
eax1000
edi70


-------------------------------------------------------------------------------------------------


3. Erste Assembler Schritte
3.5. Push/Pop

Push und Pop sind die wohl, meiner Meinung nach, wichtigsten Befehle in Assembler.
Mit Push kann man Werte auf dem Stack abspeichern und mit Pop holt man sie wieder runter.

Das war Push/Pop ganz knapp zusammen gefasst, natürlich ist es, wie alles in ASM, etwas komplizierter.

Der Stack arbeitet nach dem First-In-Last-Out Prinzip.
Das heißt im Grunde nichts anderes als, dass das erste Element, das auf den Stack per Push gespeichert wurde
das letzte Element ist, das per Pop runtergenommen werden kann.

Der Stack (zu deutsch: Stapelspeicher) wird insbesondere zum Zwischenspeichern von Werten und zum
Übergeben von Parametern benutzt.

Ich denke momentan sagt uns das nicht viel, aber wir machen es uns an einem Beispiel klar:

Code:
mov eax, 10
push eax
mov eax, 3
pop eax
Wir werden uns jetzt Tabelle und Stack immer gleichzeitig anschauen.
Unsere Tabelle nach der ersten Zeile Code:

RegisterAdresseWert
eax100

Unser Stack:
Stack

Nach Push hat sich an der Tabelle nichts verändert, aber unser Stack hat sich verändert:

Stack
10

Nach dem Ausführen von Zeile 3 sieht der Stack immer noch gleich aus, aber unsere Tabelle
hat sich verändert:

RegisterAdresseWert
eax30

Stack
10

Wenn unser Code komplett ausgeführt wurde, dann sieht das wie folgt aus:

RegisterAdresseWert
eax100

Stack

Das Prinzip des Stacks kam bei diesem Beispiel nicht raus, aber die Arbeitsweise sollte jetzt nachvollziehbar sein.

Schauen wir uns das ganze mit mehr Werten auf dem Stack an:

Code:
mov eax, 10
push eax
mov eax, 3
push eax
mov eax, 8
push eax
pop edx
pop edi
pop eax
Nach den beiden ersten zeilen:

RegisterAdresseWert
eax100

Stack
10

Nach der nächsten Zeile ("mov eax,3"):

RegisterAdresseWert
eax30

Stack
10

In zeile 4:

RegisterAdresseWert
eax30

Stack
3
10

Hier sieht man, der Stack kann mehrere Werte speichern.
Die Anzahl der Werte ist theoretisch unbegrentzt, aber praktisch natürlich durch Speicherkapazität u.ä. begrentzt.

In Zeile 6 sieht es dann schon so aus:

RegisterAdresseWert
eax80

Stack
8
3
10

So ab jetzt wird es interessant:

Ich poste jetzt einfach die 2 Tabellen, wie sie nach jeder Zeile Code aussehen:

Zeile 7:

RegisterAdresseWert
eax80
edx80

Stack
3
10

Zeile 8:

RegisterAdresseWert
eax80
edx80
edi30

Stack
10

Zeile 9:

RegisterAdresseWert
eax100
edx80
edi30

Stack

Man sieht hier also sehr schön, Wenn man 3 Werte per Push auf den Stack befördert und sie anschließend wieder
mit Pop holt, wird der zu letzt auf den Stack gelegte Wert als erstes geholt und vom Stack gelöscht.

Dazu noch eine kleine Illustration von Wikipedia:
Quote:
Ein Stapelspeicher ist mit einem Stapel von Umzugskisten vergleichbar. Es kann immer eine neue Kiste oben auf den Stapel gepackt werden (entspricht push) oder eine Kiste von oben heruntergenommen werden (entspricht pop). Der Zugriff ist im Regelfall nur auf das oberste Element des Stapels möglich. Ein Hinzufügen oder Entfernen einer Kiste weiter unten im Stapel ist nicht möglich.

http://de.wikipedia.org/wiki/Stapelspeicher
Aber wozu braucht man das jetzt?
Die Anzahl an Register sind ja leider begrentzt und viele der Register haben einen extrem wichtigen Startwert,
den man unter gar keinen Umständen löschen sollte.
Wenn man dieses Register jetzt aber doch braucht (z.b. aus Mangel an Registern), dann kann man den Wert des Registers
vor der Rechnung abspeichern und danach wieder laden, somit geht nichts verloren und wir haben trotzdem ein Register mehr:

Code:
push edi
; Code 
; ...
pop edi
Bei Push und Pop gibt es nicht viel zu beachten, außer dass in jedem Code immer genau gleich viele
Pushs und Pops seien sollten.
Haben wir ein Pop zu viel stürzt unser Programm ab.
Haben wir ein Push zu viel, wird der Stack unnötig zu gemüllt und bleibt (zumindest vorrübergehend)
unbenutzbar.

Es ist also wichtig den Stack immer auf zu räumen, auch wenn man den gespeicherten Wert wider Erwartens
nicht braucht.


-------------------------------------------------------------------------------------------------


3. Erste Assembler Schritte
3.6. Variablen in ASM

Ich hatte mir überlegt, ob dieses Kapitel wirklich sinnvoll sei oder ob es nicht vielleicht zu sehr verwirrt.
Aber Ich denke, wenn Assembler-Grundlagen lernen, dann sollte man Variablen nicht vergessen.

Das "Problem" hierbei ist, dass man es nicht mehr groß umschreiben kann, wir müssen voll in die Materie eintauchen.
Aber wer es bis hier her geschafft hat, den wird der Rest auch nicht zu schwer fallen.

Also gut fangen wir an.
Variablen in ASM können genauso wie in AutoIt benutzt werden.
Sie können Zahlen speichern, können aber auch Zeichenketten (=Strings) "speichern".
Wobei genau genommen Speichern diese Variablen garnichts außer die Adresse an der die Werte liegen.
Erstellen wir also eine Zeichenkette in ASM und speichern sie in einer Variable und holen uns anschließend
wieder den Wert dieser Variable haben wir lediglich den ersten Buchstaben unserer Zeichenkette.

Wir speichern in unserer Variable also nur die Adresse, wo unsere Werte liegen.

Nehmen wir an wir weisen unserer Variable den Wert "Hallo" zu.
Wenn wir jetzt alle Zeichen haben wollen (und nicht nur "H"), dann müssen wir das anders machen.

Mithilfe einer Tabelle sollte das etwas klarer werden:

Unsere Variable heißt jetzt einmal "var1" (in ASM wird kein $ vor den Variablen benötigt).

VariableAdresseWert
var10H
var18a
var116l
var124l
var132o

Wir sehen also unsere Variable "var1" nimmt insgesamt 5 (0-4)Byte Speicherplatz ein.
Aber warum ausgerechnet 5 Byte? Und nicht 8 oder 10?

Die Adresse, die wir oben in der Tabelle angeben ist in Bits gehalten, wobei 8 Bit immer 1 Byte sind.
Buchstaben jeglicher Art brauchen immer 1 Byte um sie darstellen zu können.
Wie ihr hoffentlich von AutoIt aus wisst, wird jedem Buchstaben eine Zahl zugewiesen, so hat der Buchstabe
"E" z.b. die Zahl 69.

Wenn wir uns die obere Tabelle mit der Adresse in Bytes anschauen, dann sieht man eine gewisse Ähnlichkeit zu AutoIt.

VariableAdresseWert
var10H
var11a
var12l
var13l
var14o

Man sieht, unsere Zeichenkette ist in Wirklichkeit ein Array mit der Größe 5.
Das heißt unsere Variable "var1" speichert nur die Adresse vom 1. Element, also 0.
Wenn wir jetzt das "a" haben wollen, müssen wir unsere Adresse der Variable um 1Byte erhöhen.

Variablen benutzt man ähnlich wie Register, nur bei Variablen wird nicht mit den Adressen gerechnet, sondern
mit den Speicherwerten.

Schauen wir uns die Tabelle am Anfang an:

Register/VariableAdresseWert
eax00
edx00
edi00
var18H

Code:
mov eax, [var1] ; Wert der Adresse von var1 kopieren in eax
mov edx, [var1+2] ; Wert der Adresse von var1 +2 kopieren in edx
mov edi, var1 ; Adresse von var1 verschieben in edi
Und unsere Tabelle nach dem Code:

Register/VariableAdresseWert
eaxH0
edxl0
edi8H
var18H

Jetzt wissen wir wie wir Variablen benutzen und was Variablen wirklich sind, aber wie erstellen wir Variablen?

Das Erstellen der Variablen ist für einen AutoItler wohl eine krasse Umstellung,
aber wir schaffen das trotzdem.

Wichtig ist zuerst einmal, dass Variablen in ASM immer erstellt (=deklariert) werden müssen.

In AutoIt kann man es sich ja aussuchen, wie man das haben möchte, entweder so:

PHP Code:
$var=
oder so:

PHP Code:
Local $var
$var
=
In AutoIt muss man die Variable nicht zwangsweise mit Local/Global/Dim erstellen, man kann sie auch so benutzen.
In ASM ist es Pflicht die Variable zu erstellen.
Außerdem muss die Erstellung der Variablen immer ganz am Ende des ASM-Programmes passieren.

Scheinbar wissen wir jetzt genug über Variablen...
Oder vielleicht auch nicht...

Variablen in ASM haben immer eine "Grenze", die beim Erstellen (Deklarieren) der Variablen mit angegeben werden muss.
Somit können wir dem Computer z.b. sagen: "Ich möchte eine Variable erstellen, die nur Zahlen von -127 bis +127 halten kann".
Aber wir können das dem Computer nicht nur sagen, wir müssen es sogar.
Wir müssen uns also festlegen wie groß wir unsere Variablen gerne hätten, in AutoIt passiert das alles von alleine.
Das kann ganz schön mühsam sein, aber mit der Zeit wird es zur Routine und man regt sich auf, dass AutoIt soetwas nicht hat.

Was das bringt werden sich sicherlich einige Fragen.

Nun, damit können wir genau steuern wie viel Speicherplatz wir belegen.
Haben wir eine Variable in AutoIt, die nur 1 und 0 speichern soll, dann braucht die Variable trotzdem
8 Byte Speicherplatz. Und das ist bei jeder Variable so.
Auf den neuen Rechnern mag das für unsere Zwecke wohl völlig egal sein, aber
man sollte immer im Hinterkopf behalten, dass ASM eine der ersten Programmiersprachen war und da
gab es nunmal noch keine 8GB Arbeitsspeicher, da war man froh, wenn man 1MB hatte.

Wir müssen uns damit leider trotzdem noch rumschlagen.

Fast genau so schlimm wie die Register fand ich immer das Erstellen der Variablen, ihr werdet gleich sehen warum (oder auch nicht ).

Eine Variable erstellt man in ASM ganz grob so:

Code:
Variablenname Datentyp Startwert

Unser Variablenname ist egal, der kann frei gewählt werden (es gelten die selben Bedingungen wie in AutoIt,
keine Sonderzeichen usw.)
Der Datentyp ist das Ding, was dem Computer sagt wie groß unsere Variable werden soll, also ob sie
Werte von 10000000000000000 bis 0 speichern soll oder nur Kommazahlen oder nur Zahlen zwischen 1 und 0...
Unser Startwert ist der Wert, den die variable am Anfang bekommen soll.

Ein konkretes Beispiel sieht in ASM so aus:
Code:
test db 50
"test" ist unser Variablenname, "db" ist unser Datentyp und "50" ist unser Startwert.

db kann zahlen von -128 bis +127 abspeichern.

Es gibt aber noch einige mehr Datentypen, hier einmal eine Auflistung einiger Datentypen (wie immer ist die
Groß und Kleinschreibung egal):


BezeichnungBedeutungGröße in BitsWertebereich
DBByte/Char8-128 bis +127
DWWord16-32768 bis +32767
DDDouble Word32-2.147.483.648 bis +2.147.483.647
DQQuad Word64-2^63 bis +2^63-1
DPFar Pointer48-2^47 bis +2^47-1
TBYTETen Byte80-2^79 bis +2^79-1
(Tabelle von )

Wollen wir jetzt also in einer Variable einen Wert von 90000 speichern, dann sollten wir
DD (Double Word) hernehmen und nicht gleich DQ (Quad Word), um Speicher zu sparen.

Schauen wir uns das alles in einem kleinen Code einmal an:

Code:
mov eax, [MyVar2]
add eax, [MyVar]
MyVar dd 65
MyVar2 dd 9000
eax hat nach dem ersten mov Befehl den Wert 9000 und am Ende 9065.
Ich denke das sollte nicht all zu schwer zu verstehen sein.

Wie alles in Assembler wird uns das ganze jetzt aber zusätzlich erschwert,
wenn wir eine Variable haben, die nur eine Größe von 16 Bit hat und den Wert dieser Variable
in ein Register schreiben wollen, dann können wir das nicht so machen:

Code:
mov eax, [MyVar]
MyVar dw 65
Denn wir können zwei unterschiedliche Größen nicht einfach addieren.
Wir können nicht in einer Zahl, die bis zu 32Bit lang sein kann (eax) eine Zahl mit nur 16Bit länge speichern.

Aber wenn wir uns zurück erinnern, hat jedes Register Unterregister.
So auch eax, es besteht zur Hälfte aus ax.
Und ax ist 16 Bit groß, genau so wie unsere Variable, also können wir da getrost den Wert rein verschieben.
Aber zeurst müssen wir eax auf 0 setzen, sonst könnten undefinierte Zahlen bei rauskommen:
Code:
mov eax, 0
mov ax, [MyVar]
MyVar dw 65
Und voila eax hat den Wert 65.

Andersrum ist es natürlich genauso, wollen wir einen 64-Bit Wert in ein Register speichern, dann müssen
wir da auch erst wieder etwas tricksen.
Aber das ist sogar angenehmer als unser oberes Problem, man muss einfach nur davor schreiben welchen
Datentyp man gerne hätte:

Code:
mov eax, dword[MyVar]
MyVar dq 65
Wobei man hier nicht einfach dq schreiben kann, sondern dafür gibt es auch wieder besondere keywörter:

BezeichnungKeyword
DBbyte
DWword
DDdword
DQqword

Es ist nicht schlimm, wenn ihr die ganzen Zusammenhänge nicht auf Anhieb verstanden habt, lest es euch einfach
noch ein zwei mal durch und google eventuell.

-------------------------------------------------------------------------------------------------


3. Erste Assembler Schritte
3.7. Sonstige wichtige Befehle

Weitere wichtige Befehle sind:

Mul/Div und Loop:

Mul ist der Befehl für Multiplizieren und Div für Dividieren.
Die Syntax sieht folgendermaßen aus:

Code:
Mul Source
Code:
Div Source
Das einzige außergewöhnliche an Mul und Div ist, dass es keine Destination gibt, sondern nur Source.
Destination ist automatisch eax.

ASM äquivalenter AutoIt-Code:
PHP Code:
$eax $eax*Source 
Um kurz auf Kapitel 3.5. zurück zu kommen.
Hier sieht man schon den ersten Verwendungszweck von Push.
Hat eax einen wichtigen Wert, dann muss dieser Wert irgendwo gespeichert werden,
bevor mit dem Multiplizieren weiter gemacht werden kann. Ansonsten verschwindet der Wert.


Nun fehlt uns nur noch der Befehl Loop.
Der Befehl Loop ist mit diesem Assembler-Code gleich zu setzen:

Code:
Sprungmarke:
; Code...
dec ecx
cmp ecx, 0
jne Sprungmarke
Dasselbe mit Loop:

Code:
Sprungmarke:
; Code...
Loop Sprungmarke
Der Loop-Befehl nimmt sich automatisch das Register ecx und verringert es bei jedem Schleifen Durchlauf um 1.
Wenn der Wert von ecx ungleich ("jne") 0 ist, dann wird zur Sprungmarke gesprungen.
Ansonsten geht es normal im Programmcode weiter.

Weitere wichtige Befehle findet ihr hier, wobei ihr die Registernamen meist um ein "e" am Anfang ergänzen müsst:



-------------------------------------------------------------------------------------------------


4. Assembler-Codes
4.1. Berechnen der Fakultät einer ganzen Zahl

So jetzt legen wir mit einem kleinen "sinnvollem" Programm los.
Wir wollen nur den Wert von 10! (also 10 Fakultät) berechnen.
Fakültät von 10 bedeutet nichts anderes als das:
Quote:
10*9*8*7*6*5*4*3*2*1
Das lässt sich sogar relativ einfach in Assembler umsetzen:

Code:
mov eax, 10
mov ecx, eax
dec ecx
fakul:
mul ecx
LOOP fakul
Zuerst verschieben wir in unser eax Register den Wert 10, anschließend legen wir die Anzahl
der Schleifen-Durchläufe mit dem ecx Register fest.
Wir brauchen für die Fakultät nur 10-1 Durchläufe, deswegen auch "dec ecx".

Anschließend durchlaufen wir unsere Schleife solange, bis ecx gleich 0 ist.
Und da Mul automatisch den Wert von eax nimmt, ihn mit ecx multipliziert und ihn wieder in eax legt,
brauchen wir gar nicht groß schieben/speichern.


-------------------------------------------------------------------------------------------------


4. Assembler-Codes
4.2. Potenzieren einer ganzen natürlichen Zahl mit ganzen Exponenten

Es läuft ähnlich ab wie bei der Fakultät, wer sich selbst einmal probieren will, der kann die Lösung
(im Spoiler) auch später nach sehen:



-------------------------------------------------------------------------------------------------


5. AutoIt und Inline-Assembler
5.1. Erstes Programm mit Assembler und AutoIt

AutoIt an sich kann kein Inline-ASM, aber dank einer UDF lässt sich das ganze schön in AutoIt einbauen.
Wenn ihr die Rar-Datei mit der Datei "FASM.au3" noch nicht heruntergeladen habt, dann solltet ihr das jetzt machen,
denn ohne geht es ab jetzt nicht mehr.

Zuerst einmal ganz grob:
Die UDF erzeugt für uns aus den Assembler-Befehlen Maschinencode, den wir dann
ausführen lassen können.

Dann fangen wir einmal unser 1. AutoIt Inline-ASM Skript an.

Zuerst brauchen wir natürlich die FASM.au3.
Wir includen sie also.

PHP Code:
#include <FASM.au3>

$Fasm FasmInit()
FasmReset($Fasm
Die 3 Zeilen da oben sind die Grundlagen für das weitere Arbeiten mit ASM in AutoIt.

Zuerst includen wir unsere FASM.au3 und anschließend initialisieren wir
unseren Compiler, danach wird der ASM-Code mithilfe von "FasmReset($Fasm)" resetted, um
undefinierte Verhalten auszuschließen.

Das war es im Grunde schon, jetzt können wir anfangen unseren ASM-Code hinzuzufügen:

PHP Code:
#include <FASM.au3>

$Fasm FasmInit()
FasmReset($Fasm)
FasmAdd($Fasm"use32")
FasmAdd($Fasm"mov eax, 3")
FasmAdd($Fasm"ret"
Mir müssen unserem Assembler aber erst einmal ein paar Sachen mitteilen:
PHP Code:
FasmAdd($Fasm"use32"
Dieser ASM-Befehl legt fest, dass wir den 32-Bit-Modus benutzen wollen.
Ich würde immer den 32Bit Modus nehmen, auch wenn das Betriebssystem 64Bit hat.
Denn 32Bit-Programme laufen auch auf 64Bit, aber andersrum nicht.

Anschließend kommt unser eigentlicher ASM-Code:
PHP Code:
FasmAdd($Fasm"mov eax, 3"
Es wird also 3 in eax kopiert.
Und wir müssen unseren ASM-Code auch wieder abschließen, das machen wir mit einem "ret".
Wenn unser Assembler bei "ret" ankommt, ist der ASM-Code zu Ende und es wird mit dem AutoIt-Skript
weitergemacht.

Um das ganze jetzt ausführen zu lassen, könnte ich eine Funktion schreiben, aber manchmal ist es
besser etwas selbst zu erarbeiten als sich alles geben zu lassen.

Um unsere ASM-Code jetzt ausführen zu lassen brauchen wir ersteinmal den kompilierten ASM-Code, den
bekommen wir damit:
PHP Code:
$code=FasmGetBinary($Fasm
In $code steht jetzt also unser Maschinencode.

Als nächstes brauchen wir einen Speicherplatz, der ähnlich wie eine Variable in ASM ist.
Wir brauchen also ein Array an Buchstaben.
Das machen wir aber nicht indem wir jetzt ein Array erstellen und alle Buchstaben reinspeichern,
nein wir nehmen "DllStructCreate".

Dieser Befehle reserviert eigentlich nur Speicher im C/C++ bzw. ASM-Stil.

Und weil der Befehl im ASM/C-Style ist müssen wir auch die Größe im ASM/C-Style angeben:

PHP Code:
$Codebuffer=DllStructCreate("byte["&stringlen($code)/2-1&"]"
Wir reservieren jetzt also Speicher für unseren Maschinencode, aber warum reservieren wir nur
Länge_des_Codes/2 Byte an speicher?

Der Maschinencode ist wenn er aus der FasmGetBinary(...)-Funktion kommt automatisch in Hexadezimalschreibweise,
der Code wird aber nicht im Hexadezimal-Stil abgespeichert und da 2 Hexzahlen immer ein Buchstabe/Zeichen sind,
brauchen wir nur die Hälfte.

Das "byte" im AutoIt-befehl sollte uns ja bereits von ASM bekannt vorkommen.
Jeder Buchstabe braucht genau ein Byte um dargestellt werden zu können.

Nachdem wir unsere Variable im C/C++ Stil, eine sog. Structure, jetzt erstellt haben, müssen wir sie aber
auch mit unserem Code füllen:
PHP Code:
dllstructsetdata($CodeBuffer,1,$code
Der erste Parameter ist unsere zuvor erstellte Structure, der 2. Parameter sagt nur bei welchem Element wir
anfangen wollen zu kopieren. Wir wollen beim 1. anfangen.
Und der letzte Parameter "$code" ist unser Maschinencode.

Nachdem wir das geschafft haben, ist der Großteil schon geschafft.
Jetzt müssen wir unseren Code nur noch aufrufen:

PHP Code:
DllCall("user32.dll""int""CallWindowProcW""ptr"DllStructGetPtr($CodeBuffer), "int"0"int"0"int"0"int"0
Das sieht kompliziert aus, nicht?
Aber wir schaffen auch das:

DllCall ruft eine Funktion einer Dll auf.
Damit AutoIt weiß in welcher Dll er die Funktion suchen soll, müssen wir ihm das sagen:
"user32.dll".

Der 2. Parameter ist im Grunde nur der Datentyp des Rückgabewertes.
Da wir im moment noch keinen Rückgabewert haben, kann uns das vorerst egal sein.
Der 3. Parameter ist die Funktion, die wir aufrufen wollen.
Die Funktion "CallWindowProcW" macht nichts anderes als Maschinencode auszuführen, hier wird also
unser eigentlicher Maschinencode ausgeführt.

Anschließend müssen wir der Funktion noch mitteilen welchen Maschinencode sie ausführen soll.
Aber wir kennen das ja bereits, wir können keine Zeichenketten übergeben, sondern müssen
die Adresse des ersten Wertes übergeben.
Unser Maschinencode steht ja in unserer Structure "$CodeBuffer", wir brauchen jetzt nur noch die Adresse vom 1. Wert.
Diese Adresse lässt sich mit DllStructGetPtr(...) herausfinden.
Damit die Funktion jetzt weiß, dass wir eine Adresse übergeben und keine nutzlose Zahl, müssen wir
davor noch mithilfe von "ptr" (=Pointer) der Funktion sagen, dass sie jetzt eine Adresse bekommt und
dass wir den Wert wollen, der an der Adresse steht.

Die restlichen Parameter sind Eingangsparameter für unseren ASM-Code, aber dazu später mehr.


-------------------------------------------------------------------------------------------------


5. AutoIt und Inline-Assembler
5.2. 2 Zahlen in ASM addieren


Zuerst einmal müssen wir uns überlegen wie unser ASM-Code aussehen soll, bei uns wird er so aussehen:

Code:
use32
add eax,edi
ret
Danach folgt die Aufgabe das in AutoIt einzubetten:

PHP Code:
#include <FASM.au3>

$Fasm FasmInit()
FasmReset($Fasm)
FasmAdd($Fasm"use32")
FasmAdd($Fasm"add eax,edi")
FasmAdd($Fasm"ret")

$bytecode=FasmGetBinary($Fasm)
$tCodebuffer=dllstructcreate("byte["&stringlen($Bytecode)/2-1&"]")
dllstructsetdata($tCodeBuffer,1,$Bytecode)
$RetDllCall("user32.dll""int""CallWindowProcW""ptr"DllStructGetPtr($tCodeBuffer), "int"12"int"33"int"0"int"0
Bisher hat sich nur das "$Ret" geändert, wir wollen ja, dass der addierte Wert irgendwo gespeichert wird, also
machen wir das in "$Ret".

Die eigentliche Frage ist jetzt wie man in unser ASM-Programm 2 von uns auswählbare Zahlen einfügt.
Aber zeurst erweitern wir unseren Code so:
PHP Code:
#include <FASM.au3>

$zahl1=Inputbox("Zahl","Zahl1")
$zahl2=Inputbox("Zahl","Zahl2")

$Fasm FasmInit()
FasmReset($Fasm)
FasmAdd($Fasm"use32")
FasmAdd($Fasm"add eax,edi")
FasmAdd($Fasm"ret")

$bytecode=FasmGetBinary($Fasm)
$tCodebuffer=dllstructcreate("byte["&stringlen($Bytecode)/2-1&"]")
dllstructsetdata($tCodeBuffer,1,$Bytecode)
$RetDllCall("user32.dll""int""CallWindowProcW""ptr"DllStructGetPtr($tCodeBuffer), "int"$zahl1"int"$zahl2"int"0"int"0
Wir haben jetzt die 2 Inputboxen hinzugefügt und wir haben unseren DllCall-Befehl etwas verändert.
Wir wollten für unseren Assemblercode ja 2 Eingangsparameter, nämlich $zahl1 und $zahl2, also haben
wir das auch gleich reingesetzt.
Das "int" davor ist wieder nur der Datentyp, er sagt uns also, dass es eine Zahl ist und zwar eine ganze Zahl
mit einer maximalen Größe von 32Bit.

Wenn wir unsere Funktion ("CallWindowProcW") aufrufen, werden alle Adressen der Eingangsparameter auf dem Stack
gespeichert und bleiben da auch erst einmal.
Damit wir jetzt aber wissen wie wir unsere Werte trotzdem benutzen können, wird die Adresse des
Stackpointers (dem Register esp) zu der Adresse des ersten Eingangparameters gesetzt.
Jetzt muss man wissen, dass eine Adresse immer 4Byte (=32Bit) groß ist.

Um die Werte jetzt also benutzen zu können müssen wir nur die Adresse von "esp" nehmen und
je nachdem welchen Parameter wir wollen die Adresse erhöhen.

Unser fertige Code sähe dann also so aus:
PHP Code:
#include <FASM.au3>

$zahl1=Inputbox("Zahl","Zahl1")
$zahl2=Inputbox("Zahl","Zahl2")

$Fasm FasmInit()
FasmReset($Fasm)
FasmAdd($Fasm"use32")
FasmAdd($Fasm"mov eax, [esp+4]")
FasmAdd($Fasm"mov edi, [esp+8]")
FasmAdd($Fasm"add eax, edi")
FasmAdd($Fasm"ret")

$bytecode=FasmGetBinary($Fasm)
$tCodebuffer=dllstructcreate("byte["&stringlen($Bytecode)/2-1&"]")
dllstructsetdata($tCodeBuffer,1,$Bytecode)
$RetDllCall("user32.dll""int""CallWindowProcW""ptr"DllStructGetPtr($tCodeBuffer), "int"$zahl1"int"$zahl2"int"0"int"0)
MsgBox(0,"Ergebnis",$Ret[0]) 

Das Register "esp" zeigt also jetzt an die erste Adresse unserer Eingangsparameter, aber warum müssen
wir esp dann um 4 erhöhen, obwohl wir doch den 1. Eingangsparameter haben wollen?

Nunja, das ist schnell erklärt, streng genommen ist unser erster Eingangsparameter nämlich:
"DllStructGetPtr($tCodeBuffer)", wenn wir esp nicht um 4Byte (=Größe der Adressen) erhöhen würden, dann
bekämen wir die Adresse von unserem Maschinencode.

Also müssen wir +4 machen und +8 für unseren nächsten Eingangsparameter und hätten wir noch einen Parameter,
dann müssten wir + 12 machen.

Und nun zum DllCall:

DllCall liefert immer ein Array zurück, wobei das Array eigentlich nur aus den auf dem Stack liegenden Werte besteht.
Das heißt $Ret[1]=$zahl1, $Ret[2]=$zahl2, $Ret[3]=0 ...
Und $Ret[0] wäre unsere Adresse an der unser Maschinencode steht, wenn nicht das ret da wäre,
das automatisch den Wert von eax an die Stelle der Adresse des Maschinencodes setzt.
$Ret[0] ist also unser eax und da in eax unser Ergebnis gespeichert wurde, ersparen wir uns Arbeit.


-------------------------------------------------------------------------------------------------


5. AutoIt und Inline-Assembler
5.3. Einen kleinen Taschenrechner mit einfachen Parser schreiben

Zuerst einmal sollten wir das Wort "Parser" klären.
Ein Parser ist nichts anderes als ein Programm, das eine Zeichenkette in ihre Bestandteile
aufsplittet und dann je nachdem welche Bestandteile vorhanden sind ein Ergebnis zurück liefert.

Wir wollen uns in diesem Beispiel nur auf das Parsen von Additionen und Subtraktion ohne Klammern und ohne Kommata beschränken.
Alles andere würde zu weit führen.
Unser ASM-Programm soll also, wenn wir das Eingeben:

Quote:
10+5+23+88+6-8
Das Ergebnis 124 zurückgeben.

Bevor wir drauf losschreiben, müssen wir uns eine Art Pseudo-Code überlegen.
Ich mach das immer sehr gerne indem ich mir die Frage stelle:
"Woran erkennst du, dass da jetzt 124 rauskommt?"

Die Antwort darauf ist recht banal:
"Ich sehe die Zahlen und die Plus/Minus-Zeichen"

Die nächste Frage muss dann sein:
"Woran erkenne ich, dass die Zahl jetzt 10 ist und nicht 1+0?"

Antwort:
"Die Zahlen werden automatisch aneinander gereiht, wenn kein Zeichen dazwischen ist"

Damit haben wir uns klar gemacht was die Grundlagen sind.
Wir brauchen ein Programm, das zuerst einmal alles aufsplittet und danach alles je nach Art des Zeichens/Buchstabens zusammenfügt.
In AutoIt-Code sähe das so aus (Ihr solltet zuerst das Skript verstehen, bevor ihr weiter mit dem ASM-Teil macht):
PHP Code:
Func Parse($var)
    
Dim $zahlen[20] ; Maximal 20 Zahlen können Addiert/Subtrahiert werden
    Dim $zeichen
[19] ; Maximal 19 Zeichen können in der Rechnung vorkommen

    $splited 
StringSplit($var""2) ; Wir brauchen jedes Zeichen einzeln

    $mom_zeichen 
Momentane Anzahl an gefundenen Zeichen
    $mom_zahl 
Momentane Anzahl an gefundenen Zahlen

    $zeichen
[0] = "" Den Inhalt des ersten Elements auf "" setzen
    $zahlen
[0] = "" Den Inhalt des ersten Elements auf "" setzen

    
For $i 0 To UBound($splited) - 1
        
If Asc($splited[$i]) >= Asc("0") And Asc($splited[$i]) <= Asc("9"Then
        
Wenn wir eine Zahl gefunden habendann wird sie in unserem Array "$zahlengespeichert
            $zahlen
[$mom_zahl] &= $splited[$i]
        Else
            
$mom_zahl += Wenn wir ein Zeichen gefunden habendann ist die vorherige Zahl zu Ende
            $zahlen
[$mom_zahl] = "" Der Inhalt muss auf "" gesetzt werden
            $zeichen
[$mom_zeichen] = $splited[$i] ; Wir speichern unser Zeichen in unserem Array
            
$mom_zeichen += Und erhöhen unsere Anzahl an gefundenen Zeichen um 1
        
EndIf
    
Next

    $ergebnis 
$zahlen[0] ; Unser Ausgangspunkt ist das zuerst gefundene Ergebnis

    
For $i 0 To UBound($zeichen) - Solange wie wir Zeiche habenkönnen wir auch rechnen lassen
        
If $zahlen[$i 1] <> "" Then Wenn wir eine Zahl haben und kein leeres Feld
            
If $zeichen[$i] = "+" Then Wenn unser Zeichen an der Stelle $i ein "+" ist
                $ergebnis 
+= $zahlen[$i 1] ; wird die momentane Zahl auf unser Ergebnis drauf gezählt
            
ElseIf $zeichen[$i] = "-" Then Wenn unser Zeichen an der Stelle $i ein "-" ist
                $ergebnis 
-= $zahlen[$i 1] ; wird die momentane Zahl von unserem Ergebniss abgezogen
            
EndIf
        EndIf
    
Next

    
return $ergebnis Das Ergebnis wird zurückgegeben
EndFunc   
;==>Parse 
Fortsetzung folgt im 2. Post (ein Post unter diesem).
Attached Files
File Type: rar Inline-Assembler AutoIt.rar (56.5 KB, 824 views)
Shadow992 is offline  
Thanks
35 Users
Old 04/23/2011, 11:34   #2
 
elite*gold: 77
Join Date: May 2008
Posts: 5,131
Received Thanks: 5,225
[AutoIt & Assembler] Assembler lernen und in AutoIt benutzen

5. AutoIt und Inline-Assembler
5.3. Einen kleinen Taschenrechner mit einfachen Parser schreiben

Fortsetzung:

Als ich meinen Assembler-Code zu Hälfte fertig hatte, ist mir erst aufgefallen, dass das noch viel zu viel
für einen Anfänger ist.
Ich habe aber nicht aufgehört, sondern habe weiter gemacht, um das Tutorial vollständig zu halten.
Wenn ihr davon nicht alles versteht, dann ist das nicht schlimm, es ist wohl etwas zu viel für einen Anfänger.
Aber lange Rede kurzer Sinn, ich präsentiere einen Parser für Addition und Subtraktion:
PHP Code:
#include <FASM.au3>

MsgBox(0,"",Parse("5+8-100+4-2"))

Func Parse($var)
Dim $Fasm FasmInit()

FasmReset($Fasm)
FasmAdd($Fasm"use32")
FasmAdd($Fasm"mov edx,dword[esp+4]") ; Wir wollen die Adresse unseres ersten Elementes
FasmAdd
($Fasm"mov edx,[edx]") ; Da wir jetzt aber die Adresse einer Adrese habenmüssen wir noch einmal kopieren
FasmAdd
($Fasm"mov ecx, 0")

Es wird überprüftob das momentane Zeichen eine Zahl is
FasmAdd
($Fasm"FindeZahlen:")
FasmAdd($Fasm"cmp byte[edx], '0'")
FasmAdd($Fasm"jl FindeZeichen")
FasmAdd($Fasm"cmp byte[edx], '9'")
FasmAdd($Fasm"ja FindeZeichen")

FasmAdd($Fasm"xor eax , eax") ; Setze eax zu 0
FasmAdd
($Fasm"mov al , byte[edx]") ;Kopiere das Zeichen von [edxin al
FasmAdd
($Fasm"sub eax, 48") ; Wandle die Zahl in eine richtige Zahl um
FasmAdd
($Fasm"push eax") ; eax wird für später gespeichert
FasmAdd
($Fasm"inc ecx") ; ecx speichert die Anzahl der Pops, die wir später machen müssen
FasmAdd
($Fasm"inc edx") ; Die Adresse vom nächsten Zeichen wird in edx gespeichert
FasmAdd
($Fasm"jmp Ende") ; Da wir eine Zahl gefunden habenkönnen wir den anchfolgenden Code weglassen

FasmAdd
($Fasm"FindeZeichen:") ; Wenn wir keine Zahl gefunden habendann haben wir ein Zeichen
FasmAdd
($Fasm"xor eax, eax") ; eax zu 0 setzen
FasmAdd
($Fasm"mov al, [mom_zeichen+esi]") ; Die momentane Anzahl gefundener Zeichen in al kopieren
FasmAdd
($Fasm"mov edi, eax") ; eax in edi kopieren
FasmAdd
($Fasm"xor eax , eax") ; eax auf 0 setzen
FasmAdd
($Fasm"mov al,[edx]") ; unser Zeichen an der Adresse edx wird in al kopiert
FasmAdd
($Fasm"mov [esi+zeichen+edi],al") ; Unser gefundenes Zeichen in al wird zu unserer Zeichensammlung hinzugefügt
FasmAdd
($Fasm"inc [mom_zeichen+esi]") ; Wir haben ein Zeichen gefundenalso muss die Anzahl erhöht werden
FasmAdd
($Fasm"inc edx") ; Wir erhöhen die Adresse von edx um 1damit wir das nächste Zeichen im String bekommen

FasmAdd
($Fasm"ZahlErstellen_Mit_Reset:")
FasmAdd($Fasm"xor eax, eax")
FasmAdd($Fasm"mov [temp+esi], ecx") ; Anzahl an Pops
FasmAdd
($Fasm"ZahlErstellen:")
FasmAdd($Fasm"pop edi") ; Unsere Zahl wurde auf dem Stack gespeichertdeswegen müssen wir sie uns holen

FasmAdd
($Fasm"push [temp+esi]") ; Wir müssen unsere Variable speichern
FasmAdd
($Fasm"Sub [temp+esi],ecx") ; Differenz wird ermittelt um herauszufindenwie oft wir unsere Zahl mit 10 malnehmen müssen
FasmAdd
($Fasm"cmp [temp+esi], 0") ; Wenn die Differenz 0 istmüssen wir nichts mit 10 mal nehmen
FasmAdd
($Fasm"je Ueberspring_Mul") ; Also überspringen wir das multiplizieren
FasmAdd
($Fasm"Potenzieren:")
FasmAdd($Fasm"imul edi,edi,10")
FasmAdd($Fasm"dec [temp+esi]")
FasmAdd($Fasm"cmp [temp+esi],0")
FasmAdd($Fasm"jne Potenzieren")
FasmAdd($Fasm"Ueberspring_Mul:")
FasmAdd($Fasm"pop [temp+esi]") ; Unsere Variable bekommt ihren alten Wert wieder

FasmAdd
($Fasm"add eax, edi") ; In edi ist unsere Zahl
FasmAdd
($Fasm"push eax") ; Wir speichern eax
FasmAdd
($Fasm"xor eax, eax") ; eax 0
FasmAdd
($Fasm"mov al, [mom_zahl+esi]")
FasmAdd($Fasm"mov edi, eax")
FasmAdd($Fasm"pop eax")
FasmAdd($Fasm"mov [zahlen+esi+4*edi], eax") ; Unsere zahl wird im zahlen array gespeichert
FasmAdd
($Fasm"dec ecx") ; ecx wird verringertda wir jetzt schon einmal gepoppt haben
FasmAdd
($Fasm"cmp ecx, 0")
FasmAdd($Fasm"jne ZahlErstellen")
FasmAdd($Fasm"inc [mom_zahl+esi]")

FasmAdd($Fasm"Ende:") ; Sprungmarke Ende
FasmAdd
($Fasm"cmp byte[edx], 0") ; Wenn ein Nullcharacter gefunden wurdedann kann man das suchen abbrechen
FasmAdd
($Fasm"jne FindeZahlen")

FasmAdd($Fasm"cmp ecx, 0") ; Wenn ecx noch nicht 0 istalso wenn wir noch einmal poppen müssen
FasmAdd
($Fasm"jne ZahlErstellen_Mit_Reset") ; dann springen wir zu ZahlErstellen_Mit_Reset

FasmAdd
($Fasm"xor ecx, ecx") ; ecx 0
FasmAdd
($Fasm"mov eax, [zahlen+esi]") ; eax = Die erste gefundene Zahl

FasmAdd
($Fasm"Berechnung:")
FasmAdd($Fasm"cmp byte[zeichen+esi+ecx], '-'") ; Wenn unser Zeichen ein Minus istwird subtrahiert
FasmAdd
($Fasm"je Subtrahieren")

FasmAdd($Fasm"Addieren:") ; Ansonsten wird addiert
FasmAdd
($Fasm"add eax, [zahlen+esi+4+4*ecx]")
FasmAdd($Fasm"jmp Ende2") ; Wir wollen nicht noch einmal Subtrahieren lassenalso überspringen wir Subtrahieren

FasmAdd
($Fasm"Subtrahieren:")
FasmAdd($Fasm"sub eax, [zahlen+esi+4+4*ecx]")

FasmAdd($Fasm"Ende2:")
FasmAdd($Fasm"inc ecx")
FasmAdd($Fasm"cmp byte[zeichen+esi+ecx], ' '")
FasmAdd($Fasm"jne Berechnung")

FasmAdd($Fasm"ret")
FasmAdd($Fasm"zahlen dd 20 dup (0)") ; Ein Array mit der Größe von 20 Elementen mit dem Startwert 0
FasmAdd
($Fasm"zeichen db 19 dup (' ')") ; Ein Array mit der Größe von 19 Elementen mit dem Startwert " "
FasmAdd($Fasm"mom_zeichen db 0")
FasmAdd($Fasm"mom_zahl db 0")
FasmAdd($Fasm"temp dd 0")

$tCodeBuffer DllStructCreate("byte[828]")
DllStructSetData($tCodeBuffer1String(FasmGetBinary($Fasm)))
"str*" ist ein Zeichenarraywir übergeben wieder nur die Adresse das ersten Elementes der Zeichenkette
$ret
=DllCall("user32.dll""ptr""CallWindowProcW""ptr"DllStructGetPtr($tCodeBuffer), "str*"$var"int"0"int"0"int"0)
$ret[0]=StringTrimLeft($ret[0],2)
Return 
dec($ret[0])
EndFunc 
Ich finde, dass das auf jeden Fall gut aussieht, einfach einmal ausdrucken und übers Klo hängen, macht sich besser als jedes Bild.
Aber keine Angst im nächsten Kapitel wird es wieder viel einfacher und auch übersichtlicher.


-------------------------------------------------------------------------------------------------


5. AutoIt und Inline-Assembler
5.4. Eine einfache Verschlüsselungsroutine schreiben

Das meiste steht zwar in den Kommentaren, aber ich muss trotzdem noch etwas erklären:

Wenn wir eine Zeichenkette (=String) von unserem ASM-Programm in AutoIt zurückgeben wollen,
dann müssen wir das wieder im ASM-Style machen und dafür brauchen wir mal wieder unser DllStructCreate.

Unsere Structure muss nur so groß sein wie unsere Zeichenkette am Anfang, sicherheitshalber reservieren wir
aber lieber ein Byte mehr als benötigt:

PHP Code:

Func Encrypt
($text)

$struct DllStructCreate("byte["&StringLen($text)+1&"]")

EndFunc 
Damit haben wir es im Grunde schon geschafft, wir müssen jetzt nur noch bedenken, dass
ASM an sich keine Zeichenketten nimmt, sondern nur die Adresse des ersten Buchstabens dieser
Zeichenkette, also brauchen wir wieder einmal die Adresse der Zeichenkette:

PHP Code:
DllStructGetPtr($struct
Wenn wir jetzt alles zusammen kopieren und unseren ASM-Code hinzufügen, sieht es so aus:

PHP Code:
#include <FASM.au3>

MsgBox(0,"",Encrypt("hi"))

Func Encrypt($text)
$struct DllStructCreate("byte["&StringLen($text)+1&"]")

$Fasm FasmInit()

FasmReset($Fasm)
FasmAdd($Fasm"use32")
FasmAdd($Fasm"mov edx,dword[esp+4]") ; Wir wollen die Adresse unseres ersten Eingangsparameters
Jetzt haben wir aber immer noch die Adresse einer Adressealso noch einmal mov
FasmAdd
($Fasm"mov edx,[edx]")
FasmAdd($Fasm"mov edi,dword[esp+8]") ; [esp+8ist die Adressewo unsere Zeichenkette drin gespeichert wird
FasmAdd
($Fasm"Encrypt:")

FasmAdd($Fasm"cmp byte[edx], 0") ; Der Computer erkennt das Ende einer Zeichenkette durch einen sog.
Null-Characterdieses Zeichen hat den Wert 0
FasmAdd
($Fasm"je Ende")
Wenn wir am Ende der Zeichenkette sinddann springe wir ans Ende

FasmAdd
($Fasm"add byte[edx],1") ; Wir addieren auf unsere Buchstaben 1 drauf,
das ist eine sogCaesar chiffrierungjeder Buchstabe wird einfach nur um 1 erhöht
Somit ist das A ein B das B ein C das C ein D usw.
FasmAdd($Fasm"mov ecx,[edx]") ; Wir können leider keine 2 Registerspeicherwerte gleichzeitg verschieben,
deswegen müssen wir den Umweg nehmen und es zuerst als Adresse speichern
FasmAdd
($Fasm"mov [edi],ecx") ; Der verschobene Buchstabe wird jetzt in unsere neue Zeichenkette kopiert
FasmAdd
($Fasm"inc edi") ; Die Stelle an der der verschlüsselte Text gespeichert werden sollwird um 1 erhöht,
da wir die alten Buchstaben ja nicht überschreiben wollen
FasmAdd
($Fasm"inc edx") ; Die Adresse vom nächsten zu verschlüsselnden Buchstaben edx+1

FasmAdd
($Fasm"jmp Encrypt") ; Eine Endlosschleife

FasmAdd
($Fasm"Ende:")
FasmAdd($Fasm"ret")

$tCodeBuffer DllStructCreate("byte[128]")
DllStructSetData($tCodeBuffer1String(FasmGetBinary($Fasm)))
ClipPut(FasmGetBinary($Fasm))
DllCall("user32.dll""ptr""CallWindowProcW""ptr"DllStructGetPtr($tCodeBuffer), "str*"$text"ptr"DllStructGetPtr($struct), "int"0"int"0)
$decrypted BinaryToString(DllStructGetData($struct1), 1)

Return 
$decrypted
EndFunc 

-------------------------------------------------------------------------------------------------


6. AutoIt-Skripts in Assembler-Codes umschreiben


-------------------------------------------------------------------------------------------------


7. Quellen

http://de.wikipedia.org/wiki/C_(Programmiersprache)




Shadow992 is offline  
Thanks
21 Users
Old 04/23/2011, 14:16   #3
 
elite*gold: 0
Join Date: Mar 2009
Posts: 3,963
Received Thanks: 1,584
N1 Shadow passt Perfekt hatte mich heute damit auch schon Beschäftigt.

Sieht gut aus ich les mir das mal durch.

EDIT:

Ist echt gut ;D.
Jedoch bleibe ich vorerst bei Vb.

Hast AutoIt aber gut mit Assembler verglichen.


Lg
Algaten™ is offline  
Thanks
1 User
Old 04/23/2011, 16:36   #4
 
elite*gold: 1
Join Date: Feb 2009
Posts: 1,726
Received Thanks: 729
auch wenn ich es schon kann bin ich froh das es nun endlich draußen ist.

---------------------------------------------------------------------------------

Quote:
Die meisten Register haben eine Größe von 32-Bit
stimmt nicht so ganz. Jedes 32Bit Register (mit E beginnend) hat auch einen kleinen Bruder (16Bit)

---------------------------------------------------------------------------------

Zum Thema Stack: Es sei angemerkt das sich nicht nur die Register als solches Sichern lassen, sondern auch einzelne Werte

Code:
PUSH 5
POP EAX
Register Wert
EAX 5

Das gleiche geht übrigens auch mit Funktionen.

Ich würde dir gerne bei deinem Tutorial helfen, da ich meine mich langsam sehr gut in Assembler eingefunden zu haben
HardCore.1337 is offline  
Old 04/23/2011, 16:55   #5
 
elite*gold: 0
Join Date: Mar 2008
Posts: 747
Received Thanks: 245
Quote:
Eine Vorraussetzung wäre auf jeden Fall grob zu wissen wie ein Computer
funktioniert. Wer immer noch denkt, dass im Computer kleine Männchen
herum laufen, der kann sofort aufhören weiter zu lesen.
Auch gewisse Kenntnisse über elektrischen Strom sind von Vorteil.
Assembler ist nur verständlich, wenn man auch weiß wie ein Computer fubnktioniert.
Hast du den teil irgendwo abgeschrieben? Der kommt mir so bekannt vor.

Quote:
Assembler besteht aus relativ wenig Befehlen.
Assembler kommt mit rund 30 Befehlen klar (wobei man diese wohl noch einmal auf 20 reduzieren könnte)
und AutoIt hat wohl momentan geschätzte 200 Befehle.
Vieleicht unterstützt AutoIt nur rund 30 befehle aber ansich sind es viel mehr.

Quote:
Push und Pop sind die wohl, meiner Meinung nach, wichtigsten Befehle in Assembler.
Eigentlich ja eher der MOV befehl da man z.b. push und pop durch Mov ersetzten kann. Zudem ist MOV im zusamenhang mit dem Stack wichtig um auf Lokale Variablen und Parameter zuzugreifen, das solltest du auch in deinem tutorial ergänzen.
Akorn is offline  
Thanks
1 User
Old 04/23/2011, 17:05   #6
 
elite*gold: 1
Join Date: Feb 2009
Posts: 1,726
Received Thanks: 729
Quote:
Assembler besteht aus relativ wenig Befehlen.
Assembler kommt mit rund 30 Befehlen klar (wobei man diese wohl noch einmal auf 20 reduzieren könnte)
und AutoIt hat wohl momentan geschätzte 200 Befehle.
Quote:
Vieleicht unterstützt Assemblernur rund 30 befehle aber ansich sind es viel mehr.
Stimmt, wenn man sich alleine MMX, 3DNow! und die FPU Befehle ansieht.
HardCore.1337 is offline  
Old 04/23/2011, 17:11   #7
 
elite*gold: 0
Join Date: Mar 2008
Posts: 747
Received Thanks: 245
Quote:
Originally Posted by HardCore.1337 View Post
Stimmt, wenn man sich alleine MMX, 3DNow! und die FPU Befehle ansieht.
Jagut die kommen noch dazu aber auch ohne diese sind es weit aus mehr.
Ich mein der 8086 hatte doch schon 80 befehle. Und die heutigen haben weit über 100.
Akorn is offline  
Old 04/23/2011, 17:27   #8
 
elite*gold: 77
Join Date: May 2008
Posts: 5,131
Received Thanks: 5,225
Quote:
Originally Posted by HardCore.1337 View Post
auch wenn ich es schon kann bin ich froh das es nun endlich draußen ist.

---------------------------------------------------------------------------------

stimmt nicht so ganz. Jedes 32Bit Register (mit E beginnend) hat auch einen kleinen Bruder (16Bit)

---------------------------------------------------------------------------------

Zum Thema Stack: Es sei angemerkt das sich nicht nur die Register als solches Sichern lassen, sondern auch einzelne Werte

Code:
PUSH 5
POP EAX
Register Wert
EAX 5

Das gleiche geht übrigens auch mit Funktionen.

Ich würde dir gerne bei deinem Tutorial helfen, da ich meine mich langsam sehr gut in Assembler eingefunden zu haben
@32-Bit
Vielleicht etwas ungeschickt ausgedrückt, ich habe ja später noch geschrieben, dass viele Register wiederum aus Registern bestehen und da steht ja auch dabei, dass diese dann nur 16-Bit bzw. 8-Bit groß sind. Sollte ich wohl etwas differenzieren.

@Stack
Sollte irgendwie klar sein.


Quote:
Originally Posted by Akorn View Post
Hast du den teil irgendwo abgeschrieben? Der kommt mir so bekannt vor.

Vieleicht unterstützt AutoIt nur rund 30 befehle aber ansich sind es viel mehr.

Eigentlich ja eher der MOV befehl da man z.b. push und pop durch Mov ersetzten kann. Zudem ist MOV im zusamenhang mit dem Stack wichtig um auf Lokale Variablen und Parameter zuzugreifen, das solltest du auch in deinem tutorial ergänzen.
Nö, wenn ich etwas abschreibe, dann gebe ich die Quelle direkt unten drunter mit an und setze es in Quote.

@Mov
Es stand doch da, dass er meiner Meinung nach der wichtigste befehl ist, nach deiner Meinung hat keiner gefragt. ^^

Quote:
Originally Posted by HardCore.1337 View Post
Stimmt, wenn man sich alleine MMX, 3DNow! und die FPU Befehle ansieht.
Quote:
Originally Posted by Akorn View Post
Jagut die kommen noch dazu aber auch ohne diese sind es weit aus mehr.
Ich mein der 8086 hatte doch schon 80 befehle. Und die heutigen haben weit über 100.
Mein 8088er hat geschätze 30 Stück:
Shadow992 is offline  
Old 04/23/2011, 18:04   #9
 
elite*gold: 0
Join Date: Mar 2008
Posts: 747
Received Thanks: 245
[QOUTE]
Mein 8088er hat geschätze 30 Stück:
[/QUOTE]

Das sagt Wiki zum 8086
Quote:
Befehle: ca. 100 im Format „[Präfix] Mnemonik [Operand 1][, Operand 2]“ ([…] nicht immer nötig)
Quote:
@Mov
Es stand doch da, dass er meiner Meinung nach der wichtigste befehl ist, nach deiner Meinung hat keiner gefragt. ^^
Es ging mir auch weniger darum zu sagen was meiner meinung nach der wichtigste befehl ist sondern darum das du in deinem tutorial auch was über das benutzen des Stacks mittels MOV schreiben solltest.
Akorn is offline  
Old 04/23/2011, 18:20   #10
 
elite*gold: 77
Join Date: May 2008
Posts: 5,131
Received Thanks: 5,225
Quote:
Es ging mir auch weniger darum zu sagen was meiner meinung nach der wichtigste befehl ist sondern darum das du in deinem tutorial auch was über das benutzen des Stacks mittels MOV schreiben solltest.
Wird später im Inline-Assembler Teil gebraucht und wird dementsprechend auch erst dort erklärt.
Shadow992 is offline  
Old 04/23/2011, 19:05   #11

 
elite*gold: 47110
Join Date: Jun 2009
Posts: 28,879
Received Thanks: 25,302
Ansich schönes und sachlich richtiges Tutorial, bis auf ein paar kleine Punkte, die teilweise auch schon angesprochen wurden:

Quote:
Originally Posted by Shadow992 View Post
Mein 8088er hat geschätze 30 Stück:
Nun gut, aber ASM selbst unterstützt natürlich sehr viel mehr (fast jeder mögliche Wert, den ein Byte haben kann, ist an einen Opcode vergeben + Präfixe + Instruktionen, die mit 0F beginnen).

Quote:
Originally Posted by HardCore.1337 View Post
stimmt nicht so ganz. Jedes 32Bit Register (mit E beginnend) hat auch einen kleinen Bruder (16Bit)
Nein, dieser "kleine Bruder", wie du ihn nennst, ist Teil des Registers.
Aus historischen Gründen kann man ihn eben seperat ansprechen (die oberen 16 Bit des eax Registers ja nicht).


Zu den bedingten Sprüngen habe ich eine kleine Sache anzumerken:

Erstmal wäre es gut, wenn du die Namen ein Mal ausschreiben würdest, damit man sich die Funktion selbst herleiten und auch besser merken kann (Leute können sich Namen besser als irgendwelche scheinbar zusammenhanglosen Abkürzungen merken).
Außerdem ist die Erklärung der Funktionen sachlich nicht ganz korrekt.
Du solltest, wenn du schon auf die Funktionsweise eines Prozessors und die Register eingehst, auch das Flag-Register ansprechen. Denn eigentlich sind die Bedingungen für die Sprünge diese Flags.
Dass man jnz (jump if not zero) zb. für den Vergleich mit 0 nutzen kann, kommt nur daher, dass eben das Zero-Flag gesetzt wird, wenn die vorherige Operation das Ergebnis 0 verursacht (und cmp führt eben eine Subtraktion zweier Werte durch (wobei das Ergebnis verworfen wird) und setzt die Flags, falls dabei eben 0 herauskommt (die Werte gleich sind)).

Das heißt, du solltest vielleicht eine Beschreibung des Flag-Registers hinzufügen und dann die Beschreibung der einzelnen bedingten Sprünge und von cmp noch mal etwas überarbeiten.

Quote:
Auch gewisse Kenntnisse über elektrischen Strom sind von Vorteil.
Da muss ich übrigens widersprechen. Es ist zwar von Vorteil, zu wissen, wie der Computer funktioniert (Aufbau und Anordnung der Bauteile) und schonmal etwas von der Arbeitsweise der CPU gehört zu haben ist auch nicht schlecht (genau wie Kenntnisse über die Funktion des RAMs), aber die Stromkreise muss man nun wirklich nicht kennen, nichtmal ansatzweise. Es gibt wirklich keinen Zusammenhang zwischen den physikalischen Schaltungen und der Sprache ASM.


Wie schon am Anfang gesagt, schönes Tutorial
Mich würde mal interessieren, wie das funktioniert, mit dem Inline ASM in AutoIt. Wird das zur Compile-Zeit assembliert, in die .exe gespeichert und dann später ausgeführt? Dafür wäre doch ein Plugin für den Compiler nötig oder nicht? Oder wird es zur Laufzeit von der udf assembliert? Gleicht es dann nicht doch einer Interpreter-Funktion und ist dementsprechend langsam?
MrSm!th is offline  
Thanks
2 Users
Old 04/23/2011, 19:29   #12
 
elite*gold: 77
Join Date: May 2008
Posts: 5,131
Received Thanks: 5,225
Quote:
Originally Posted by MrSm!th View Post
Ansich schönes und sachlich richtiges Tutorial, bis auf ein paar kleine Punkte, die teilweise auch schon angesprochen wurden:


Nun gut, aber ASM selbst unterstützt natürlich sehr viel mehr (fast jeder mögliche Wert, den ein Byte haben kann, ist an einen Opcode vergeben + Präfixe + Instruktionen, die mit 0F beginnen).


Nein, dieser "kleine Bruder", wie du ihn nennst, ist Teil des Registers.
Aus historischen Gründen kann man ihn eben seperat ansprechen (die oberen 16 Bit des eax Registers ja nicht).


Zu den bedingten Sprüngen habe ich eine kleine Sache anzumerken:

Erstmal wäre es gut, wenn du die Namen ein Mal ausschreiben würdest, damit man sich die Funktion selbst herleiten und auch besser merken kann (Leute können sich Namen besser als irgendwelche scheinbar zusammenhanglosen Abkürzungen merken).
Außerdem ist die Erklärung der Funktionen sachlich nicht ganz korrekt.
Du solltest, wenn du schon auf die Funktionsweise eines Prozessors und die Register eingehst, auch das Flag-Register ansprechen. Denn eigentlich sind die Bedingungen für die Sprünge diese Flags.
Dass man jnz (jump if not zero) zb. für den Vergleich mit 0 nutzen kann, kommt nur daher, dass eben das Zero-Flag gesetzt wird, wenn die vorherige Operation das Ergebnis 0 verursacht (und cmp führt eben eine Subtraktion zweier Werte durch (wobei das Ergebnis verworfen wird) und setzt die Flags, falls dabei eben 0 herauskommt (die Werte gleich sind)).

Das heißt, du solltest vielleicht eine Beschreibung des Flag-Registers hinzufügen und dann die Beschreibung der einzelnen bedingten Sprünge und von cmp noch mal etwas überarbeiten.


Da muss ich übrigens widersprechen. Es ist zwar von Vorteil, zu wissen, wie der Computer funktioniert (Aufbau und Anordnung der Bauteile) und schonmal etwas von der Arbeitsweise der CPU gehört zu haben ist auch nicht schlecht (genau wie Kenntnisse über die Funktion des RAMs), aber die Stromkreise muss man nun wirklich nicht kennen, nichtmal ansatzweise. Es gibt wirklich keinen Zusammenhang zwischen den physikalischen Schaltungen und der Sprache ASM.


Wie schon am Anfang gesagt, schönes Tutorial
Mich würde mal interessieren, wie das funktioniert, mit dem Inline ASM in AutoIt. Wird das zur Compile-Zeit assembliert, in die .exe gespeichert und dann später ausgeführt? Dafür wäre doch ein Plugin für den Compiler nötig oder nicht? Oder wird es zur Laufzeit von der udf assembliert? Gleicht es dann nicht doch einer Interpreter-Funktion und ist dementsprechend langsam?
@Zero-Flag
Du musst bedenken, es sind AutoIt-Skripter...
Aber ich werde es der Vollständigheithalber hinzufügen.

@Sprünge
Die Idee mit dem Ausschreiben ist wirklich gut, werde ich auch sofort ändern.

@Inline-Asm

Es mag sich komisch anhören, aber es ist echter Assembler-Code und dort wird auch nichts interpretiert.

Die UDF macht aus den Befehle den dazugehörigen Maschinencode, diesen Maschinencode kann man anschließend mit CallWindowProcW aufrufen.

Ein kleines Skript dazu:

PHP Code:
    #include <FASM.au3>
    
$Fasm FasmInit()
    
FasmReset($Fasm)
    
FasmAdd($Fasm"use32")
    
FasmAdd($Fasm"mov eax, dword[MyVar2+esi]")
    
FasmAdd($Fasm"ret")
    
FasmAdd($Fasm"MyVar2 dq 90000")
    
$bytecode=FasmGetBinary($Fasm)
    
$tCodebuffer=dllstructcreate("byte["&stringlen($Bytecode)/2-1&"]") ;
    
dllstructsetdata($tCodeBuffer,1,$Bytecode)
    
$RetDllCall("user32.dll""int""CallWindowProcW""ptr"DllStructGetPtr($tCodeBuffer), "byte"12"int"33"int"0"int"0)
    
MsgBox(0,"Ergebnis",$Ret[0]&" "&$Ret[1]&" "&$Ret[2]&" "&$Ret[3])
    
FasmExit($Fasm
Wenn man das ganze ohne UDF starten will, muss man sich nur den Maschinencode
in eine Text-Datei kopieren lassen und man kann das ganze Skript auf das verkürzen:
PHP Code:
    $bytecode="0x8B4604C3905F010000000000"
    
$tCodebuffer=dllstructcreate("byte["&stringlen($Bytecode)/2-1&"]") ;
    
dllstructsetdata($tCodeBuffer,1,$Bytecode)
    
$RetDllCall("user32.dll""int""CallWindowProcW""ptr"DllStructGetPtr($tCodeBuffer), "byte"12"int"33"int"0"int"0)
    
MsgBox(0,"Ergebnis",$Ret[0]&" "&$Ret[1]&" "&$Ret[2]&" "&$Ret[3]) 
Der Assembler-Code wird also während dem Ausführen des AutoIt-Skriptes kompiliert und später wird nur noch der Maschinencode ausgeführt oder man lässt es eben im voraus compilieren und dann braucht man sowieso nur noch den Maschinencode.


Edit:
Es ist natürlich nicht genau so schnell wie reiner ASM-Code, weil eben zuvor noch ein paar AutoIt-Befehle ausgeführt werden müssen, aber bei größeren Skripts oder bei Endlosschleifen macht sich die Geschwindigkeit schon bemerkbar.
Shadow992 is offline  
Thanks
1 User
Old 04/23/2011, 20:39   #13

 
elite*gold: 47110
Join Date: Jun 2009
Posts: 28,879
Received Thanks: 25,302
Erstmal wieder ein kleiner sachlicher Fehler: es ist Maschinencode, Bytecode ist eine Art Semi-Maschinensprache, sprich der Code, in den zb. .NET sprachen kompiliert werden (selbst nach dem Kompiliervorgang lässt sich der Code ja nicht von der CPU ausführen, sondern muss von der VM interpretiert werden, die daraus dann Maschinencode macht)

(ja ich weiß, mein Perfektionismus nervt :P)

Na ok, das ergibt Sinn, wusste nicht, dass man mit CallWindowProc assemblierten Code ausführen kann. Schon klar, dann ist es zwar nicht schneller als der selbe Code in reinem ASM, da ja am Anfang ein bisschen AutoIt läuft und da ja der Code noch assembliert werden muss, aber danach der folgende Code ist schneller als der korrespondierende AutoIt Code, was dann das Assemblieren bei längerem Code (oder Schleifen) wieder ausgleicht. Interessante Idee.

Quote:
@Zero-Flag
Du musst bedenken, es sind AutoIt-Skripter...
Aber ich werde es der Vollständigheithalber hinzufügen.
Das stimmt, aber so viel schwerer ist es doch nicht, wenn man lernt, dass die Bedingungen für die Sprünge an die Flags gebunden sind
Denn sonst kommen sie noch auf die Idee, den Sprung ohne das cmp davor zu schreiben (wie du schon sagst, es sind AutoIt-Skripter).
Außerdem reicht es nicht, dass sie ASM in AutoIt einbauen wollen? Müssen sie dann auch noch sachlich falsches über ASM "wissen"? =(

Naja wie gesagt, die Idee zum Tutorial und das Tutorial selbst sind ziemlich gut, das Tutorial Schreiben scheinst du zu beherrschen
MrSm!th is offline  
Thanks
2 Users
Old 04/23/2011, 20:47   #14
 
elite*gold: 77
Join Date: May 2008
Posts: 5,131
Received Thanks: 5,225
Quote:
Originally Posted by MrSm!th View Post
Erstmal wieder ein kleiner sachlicher Fehler: es ist Maschinencode, Bytecode ist eine Art Semi-Maschinensprache, sprich der Code, in den zb. .NET sprachen kompiliert werden (selbst nach dem Kompiliervorgang lässt sich der Code ja nicht von der CPU ausführen, sondern muss von der VM interpretiert werden, die daraus dann Maschinencode macht)

(ja ich weiß, mein Perfektionismus nervt :P)
Wieder etwas gelernt.
Quote:
Originally Posted by MrSm!th View Post
Na ok, das ergibt Sinn, wusste nicht, dass man mit CallWindowProc assemblierten Code ausführen kann. Schon klar, dann ist es zwar nicht schneller als der selbe Code in reinem ASM, da ja am Anfang ein bisschen AutoIt läuft und da ja der Code noch assembliert werden muss, aber danach der folgende Code ist schneller als der korrespondierende AutoIt Code, was dann das Assemblieren bei längerem Code (oder Schleifen) wieder ausgleicht. Interessante Idee.
Genau das ist die Idee und besonders bei Spielen, Verschlüsselungen und Hashes kann man ASM mit AutoIt benutzen.

Quote:
Originally Posted by MrSm!th View Post
Außerdem reicht es nicht, dass sie ASM in AutoIt einbauen wollen?
Scheint wohl, als müsstest du dich bald auf ASM+AutoIt Vergewaltigungen einstellen.
Aber du wirst damit klar kommen, ganz bestimmt.

Quote:
Originally Posted by MrSm!th View Post
Naja wie gesagt, die Idee zum Tutorial und das Tutorial selbst sind ziemlich gut, das Tutorial Schreiben scheinst du zu beherrschen
Danke dir.
Shadow992 is offline  
Old 04/24/2011, 00:25   #15
 
elite*gold: 42
Join Date: Jun 2008
Posts: 5,427
Received Thanks: 1,886
Quote:
Originally Posted by Shadow992 View Post
Scheint wohl, als müsstest du dich bald auf ASM+AutoIt Vergewaltigungen einstellen.
Dann flame ich dich! :<
MoepMeep is offline  
Thanks
5 Users
Reply


Similar Threads Similar Threads
Assembler
10/21/2010 - Main - 3 Replies
Was ist die beste Programiersprache um nach dem erfolgreichen lernen auf Assembler umzusteigen?c++,c#,basic,dolphi (oder wie des heißt:D),.....? Freue mich auf gute Antworten Obsti
Assembler
04/19/2010 - General Coding - 9 Replies
Hallo und guten Morgen|Tag|Abend, ich schreibe gerade an einen TeleportHack in CS:S. So nun hab ich die Addressen die mithilfe von WriteProcessMemory geändert werden. Das Problem ist, das das spiel so schnell die werte ändert, dass ich mich nur ca. 10ingame Meter bewege und dan sofort wieder zurück.
Assembler
02/26/2010 - General Coding - 4 Replies
hey leute, ich wollte gern Anfangen in Assembler (MASM) zu proggen (hab schon einbisschen Kenntnisse in C++ und Python) hab auch schon den MASM64 Assembler gedownloadet (hab einen 64bit). ich hab auch ein kleines hello_wolrd! programm geschrieben, hab es dann mit Notepad++ als hello_world.asm abgespeichert, aber jetzt weiß ich nicht mehr weiter^^, (wie "linke" ich die Datei???) würde mich freuen, wenn mir jemand helfen könnte^^ *kennt jemand noch ein gutes MASM-Tutorial? (in Deutsch...
Assembler
08/04/2009 - General Coding - 9 Replies
Hallo, kennt jemand ein gutes oder gute Tutorials über Assembler?? Bin kein Pro in Sachen Programmieren, also sollte es nicht so schwer sein. (ich weiss, dass es nicht leicht ist ASM zu lernen) Vielleicht kann mir jemand die Programme sagen, die ich brauche um ein ASM Programm zuschreiben?? Danke im Voraus!!!!!! :handsdown::handsdown::confused:
Au3 und Assembler?
01/08/2009 - GW Bots - 18 Replies
Hi, ich frage mich ob man Autoit mit Assembler verbinden kann, also inlineassembler betreiben kann? Weis villeicht jemand wie das gehen könnte?



All times are GMT +1. The time now is 04:27.


Powered by vBulletin®
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

BTC: 33E6kMtxYa7dApCFzrS3Jb7U3NrVvo8nsK
ETH: 0xc6ec801B7563A4376751F33b0573308aDa611E05

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2021 elitepvpers All Rights Reserved.