Die Community zu .NET und Classic VB.
Menü

Visual Basic und Assembler - Seite 4

 von 

Grundzüge der Assemblerprogrammierung
<< Vorherige Seite

Kleine Helferlein  

MASM ermöglicht das Erzeugen von Makros ebenso wie das Ersetzen von Programmcode durch Konstanten. Ersetzungen können in eine Datei ausgelagert und in Programme per INCLUDE-Anweisung eingebunden werden - das erspart viel Schreibarbeit!

Programmein- und ausstieg (Beispielmakro)

Programmeinstieg und -ausstieg sind stets gleich. Es werden Register gesichert und wiederhergestellt sowie zum aufrufenden Programm zurückgekehrt, wobei die von CallWindowProc übergebenen 4 Parameter vom Stapel zu löschen sind. Um dies nicht immer wieder schreiben zu müssen, ist es sinnvoll, dafür Makros anzulegen.

mac    MACRO   MacName:req, INT3:=<1>

IF    @Instr(1,<MacName>,<SAVE>) GT 0

    IF INT3
        int     3
    ENDIF
    
    push    ebp
    mov    ebp, esp
    push    ebx
    push    esi
    push    edi

ELSEIF    @Instr(1,<MacName>,<RESTSP>) GT 0
    lea    esp,[ebp-12]
    sbb    eax,eax
    pop    edi
    pop    esi
    pop    ebx
    pop    ebp
    ret    16

ELSEIF    @Instr(1,<MacName>,<REST>) GT 0
    sbb    eax,eax
    pop    edi
    pop    esi
    pop    ebx
    pop    ebp
    ret    16
ELSE
                    .err    <Unknown command <MacName>>
ENDIF
ENDM

Eine ausführliche Erläuterung zu den einzelnen Codeabschnitten ist im Worddokument enthalten (siehe Download).

Parameterdefinition/Lokale Variablen

Da die von CallWindowProc übergebenen vier Parameter stets an derselben Stelle zu finden sind, bietet es sich der besseren Lesbarkeit wegen an, für [EBP+x] Code-Ersetzungen zu benutzen:

PA1             EQU     <[ebp+8]>
PA2             EQU     <[ebp+12]>
PA3             EQU     <[ebp+16]>
PA4             EQU     <[ebp+20]>

Das EQU-Statement besagt: PA1/PA2 ... equals to ... Der nachfolgende Text ist von spitzen Klammern umgeben, wird also einfach als Ersetzungstext interpretiert und während der Assemblierung für PA1/PA2 ... eingesetzt. Im ASM-Code kann daher MOV EAX,PA1 anstelle von MOV EAX,[EBP+8] geschrieben werden. Von dieser Möglichkeit sollte viel Gebrauch gemacht werden, um den ASM-Text übersichtlich zu gestalten.

Dasselbe gilt für Lokale Variablen, also z.B. Integer, die im Programmverlauf erzeugt und bearbeitet werden: Wird ein Wert auf dem Stapel abgelegt, so steht er direkt unterhalb der gesicherten Register und kann daher per [EBP-x] angesprochen werden:

Off1    EQU    16
stack1    EQU    <[ebp-Off1]>
stack2    EQU    <[ebp-Off1-4]>
stack3    EQU    <[ebp-Off1-8]>
stack4    EQU    <[ebp-Off1-12]>
...
...

Im ASM-Code kann dann stehen:

    PUSH     10    ; stack1 => counter
LoopAdr:    ...
    ...
    DEC    stack1
    JNZ    LoopAdr

Übernahme des Codes in VB

Am einfachsten kann Programmcode mit dem QEditor erstellt werden (gehört zum Lieferumfang von MASM), der zugleich menügesteuert EXE-Dateien generiert. Ein größeres Problem bereitet die aufrufbare Einbindung des EXE-Codes in ein VB-Programm. Um dies zu erleichtern, habe ich eine Routine geschrieben, die EXE-Dateien ausliest und VB-Code generiert, der die Binärwerte in einem Long-Array speichert.

Die Routine besteht aus zwei Funktionen:

EXE2ARR
Mit EXE2ARR werden das Auslesen der EXE-Datei und die Umwandlung in ein Long-Array bewerkstelligt (Beispiel 4).

EXE2ASM
Die Funktion EXE2ASM benutzt EXE2ARR, um das Long-Array zu erstellen, und erzeugt entsprechenden VB-Code, der in die Zwischenablage kopiert wird, von wo er an beliebiger Stelle im VB-Programm eingefügt werden kann (Beispiel 5).

Das Ergebnis sieht z.B. so aus:

Static asm(13) As Long    ' c:\…\cpuwait.exe 13.09.03 23:00:08 (GMT)

    If asm(0) = 0 Then
        asm(0) = &HE0C1310F:  asm(1) = &H244C8B03
        asm(2) = &H89018904:  asm(3) = &HC0330451
        asm(4) = &H89184189:  asm(5) = &H310F1C41
        asm(6) = &H1184183:   asm(7) = &H1C5183
        asm(8) = &H511B012B:  asm(9) = &H8418904
        asm(10) = &H2B0C5189: asm(11) = &H511B1041
        asm(12) = &HC2E37214: asm(13) = &H10
    End If

In der Testphase eines Programms ist es natürlich lästig, nach jeder Änderung des ASM-Codes neuen VB-Code erzeugen und in den Programmtext einbinden zu müssen. Hier liegt der Grund für die Trennung oben gen. Funktionen. Während EXE2ASM geeignet ist, ausgetesteten Code in ein VB-Programm zu übernehmen, eignet sich EXE2ARR vor allem in der Testphase, weil die EXE-Datei bei jedem Aufruf erneut eingelesen wird, so dass Änderungen am ASM-Code sofort verfügbar sind:

Function Test()
    Dim asm() As Long
    If EXE2ARR("<filespec>", asm, , delInt3) = False Then Stop
End Function

Hier wird bei jedem Aufruf der Funktion Test ein undimensioniertes Array vom Typ Long erzeugt und der Binärcode der Datei <filespec> in dieses Array geschrieben. Tritt beim Einlesen ein Fehler auf, stopt die Programmausführung, andernfalls kann mit CallWindowProc wie unten beschrieben verfahren werden.

<< Vorherige Seite
Grundzüge der Assemblerprogrammierung