crt_printf zerstört Programmroutine



  • Danke dir für die schnelle Antwort.
    Allerdings habe ich noch ein paar Fragen:
    1. Gibt es eine Liste mit allen Datentypen, die masm akzeptiert?
    2. Wie kann ich einzelne Bytes per mov mit Offsets kopieren?
    z.B:
    meintext db "hallo", 0
    meinbuchstabe byte 0

    mov meinbuchstabe, meintext+0 ;ersten buchstaben in das byte schreiben
    mov meinbuchstabe, meintext+1 ;zweiten buchstaben in das byte schreiben

    Leider wird dies nicht akzeptiert. Wie lautet die richtige Syntax dazu?



  • 1. masm kennt alle x86-spezifischen Datentype (z.B. DWORD,REAL4,REAL8,...)
    2. byte in ein Register laden und anschließend an die Zieladresse schreiben

    mov al,meintext[0]
    mov meinbuchstabe,al
    

    Das hat im übrigen nichts mit dem Syntax zu tun, sondern liegt an der x86-Archetektur, die immer nur eine Speicheroperanten pro Befehl erlaubt. (Ausnahmen push/pop)



  • Danke dir nochmal für die gute Antwort 👍
    Wenn man schonmal ein Forum findet, wo die Nutzer sogar aktiv bei "schwierigen" Fragen antworten muss ich das mal ausnutzen 😉

    Ich habe noch ein bisschen im Forum gestöbert und habe versucht eine Datei auszulesen.
    Leider funktioniert die Readfile-Funktion nicht wirklich. OllyDbg stoppt immer bei der FileRead-Funktion und anschliessend krepiert das programm:

    ;fenster.asm
    .386
    .MODEL flat,stdcall
    option casemap:none
    
    INCLUDE \masm32\include\windows.inc
    INCLUDE \masm32\include\user32.inc
    INCLUDE \masm32\include\kernel32.inc
    INCLUDELIB \masm32\lib\user32.lib
    INCLUDELIB \masm32\lib\kernel32.lib
    includelib  \masm32\lib\msvcrt.lib
    include     \masm32\include\msvcrt.inc
    include     \masm32\macros\ucmacros.asm
    
    .DATA
    filename db "meinetxt.txt", 0
    zaehleranzeige db "Datei: %s", 13, 10, 0
    dwZaehler dd 0
    .DATA?            ;uninitialisierte Daten
    filed HANDLE ?
    filesize dword ?
    allocatedmem HGLOBAL ?
    .CODE
    start:
        invoke CreateFile, addr filename, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL
        mov filed, eax ;HANDLE vom Rückgabewert abspeichern
        invoke GetFileSize, filed, NULL
        mov filesize, eax ;dateigrösse abspeichern
        invoke GlobalAlloc, NULL, filesize
        mov allocatedmem, eax
        invoke ReadFile, filed, allocatedmem, filesize, NULL, NULL
        ;=====>
        ;invoke crt_printf, zaehleranzeige, allocatedmem
        invoke CloseHandle, filed
        invoke GlobalFree, allocatedmem
    invoke ExitProcess, 0
    END start
    

    Ausserdem hätte ich noch eine Frage zu Pointer:
    Was bewirkt das Macro "addr" und wo liegt der Unterschied zu Offset? Schließlich muss ich in C++, wenn ich einen C-String übergeben will, nicht &buffer schreiben.

    €dit: Gibt es einen äquivalenten Befehl zu char[100]? Ich möchte nur einen leeren Adressraum von 100 Bytes haben. Allerdings ist es sinnlos in diesem Fall GlobalMem zu benutzen, da ich diesen Buffer immer brauche.



  • RadFile schlägt fehl, da du eine ungültigen Zeiger übergibst (-> msdn). Der ADDR-Operator erlaubt es lokale variablen zu adressieren:

    invoke myFunction,ADDR var
    

    wird zu:

    lea eax,var ; var ist dabei Irgendetwas wie z.B. [ebp-4]
    push eax
    call myFunction
    

    Wenn du eine Statischen Puffer anlegen willst:

    .data?
    puffer BYTE 100 dup (?) ; die Klammern unbedingt angeben (Syntax)
    

    Hier mal wie ich es machen würde - die Sache ist (für mich) ziemlich trivial. Von daher würde ich hier die macros benutzen, die das MASM SDK mitliefert. Diese sind nichts weiter als WinAPI-wraper. Hilfe zu den macros findest du unter \masm32\help\hlhelp.chm (oder in macros.asm)

    include \masm32\include\masm32rt.inc
    
    .code
    main proc
    LOCAL buffer[100]:BYTE	; loakel puffer (auf dem stack)
    LOCAL hFile:HANDLE
    LOCAL ccBuffer:DWORD
    LOCAL pBuffer:PCHAR
    LOCAL cbWritten:DWORD
    
        .if fopen("meinetxt.txt") != INVALID_HANDLE_VALUE
            mov hFile,eax
            mov ccBuffer,fsize(eax)	; Dateigröße
            .if eax
                mov pBuffer,alloc(eax)
                .if fread(hFile,pBuffer,ccBuffer)
                    print "txt: '"
                    mov edx,rv(GetStdHandle,STD_OUTPUT_HANDLE)
                    invoke WriteConsole,edx,pBuffer,ccBuffer,ADDR cbWritten,0
                    print "'",13,10
                .else
                    print "unexpected behaviour",13,10
                .endif
            .else
                print "empty file",13,10
            .endif		
            fclose hFile
        .else
            print "can't open file",13,10	
        .endif
    
        inkey
        exit
    
    main endp
    end main
    


  • ok, im Code fehlt noch

    free pBuffer
    

    an der richtigen Stelle 😉



  • Danke euch nochmals 👍 (Mal gucken, wie of ich das noch schreiben werde)
    Mittlerweile habe ich das Problem des Auslesens auch selbst gelöst.
    Ich hatte mich in der msdn verlesen:

    This parameter can be NULL only when the lpOverlapped parameter is not NULL.

    Das "only" habe ich leider ignoriert.

    Das Schlüsselwort "addr" habe ich allerdings immer noch nicht ganz verstanden. ich habe in meinem Programm sehr of "addr" verwendet und trotzdem taucht kein einziges Mal der Befehl lea auf.
    Und warum muss ich dieses Schlüsselwort auch bei C-Strings verwenden. Schliesslich verweist ein C-String immer auf das erste Byte des Strings, oder?



  • @night@ schrieb:

    ich habe in meinem Programm sehr of "addr" verwendet und trotzdem taucht kein einziges Mal der Befehl lea auf.

    masm erkennt, ob du eine lokale oder global Variable mit dem ADDR-Operator benutzt: bei globalen Var. ist es (i.a.R.) nicht nötig mit LEA zu Arbeiten.

    @night@ schrieb:

    Schliesslich verweist ein C-String immer auf das erste Byte des Strings, oder?

    Wenn du das Label eines Strings angibst (bei invoke), interpretiert masm es so, dass du die ersten 4 Bytes des Strings als DWORD haben möchtest. Wenn du die Adresse haben willst, musst du explizit den OFFSET oder ADDR Operator verwenden.



  • Danke, jetzt habe ich es verstanden. Muss ich denn in manchen Fällen anstatt von addr offset verwenden?

    Ausserdem hänge ich (mal wieder) an einem Problem.
    Ich spiele gerade mit der Funktion GetCursorPos herum und möchte eine x-Position in einer globalen Variable speichern. Nur leider weigert sich masm den Kopiervorgang vorzunehmen.

    ;fenster.asm
    .386
    .MODEL flat,stdcall
    option casemap:none
    
    INCLUDE \masm32\include\windows.inc
    INCLUDE \masm32\include\user32.inc
    INCLUDE \masm32\include\kernel32.inc
    INCLUDELIB \masm32\lib\user32.lib
    INCLUDELIB \masm32\lib\kernel32.lib
    includelib  \masm32\lib\msvcrt.lib
    include     \masm32\include\msvcrt.inc
    include     \masm32\macros\ucmacros.asm
    
    long    TYPEDEF DWORD
    GetCoordsofCurve PROTO 
    
    .DATA
    ausgeben db "%d", 0
    zaehleranzeige db "Datei: ", 13, 10, 0
    dwZaehler dd 0
    .DATA?            ;uninitialisierte Daten
    ScreenXleft dword ?
    ScreenXright dword ?
    ScreenYtop dword ?
    ScreenYnottom dword ?
    .CODE
    start:
    
    invoke GetCoordsofCurve
    invoke ExitProcess, 0
    
    GetCoordsofCurve PROC 
        local pStruct:POINT
        schleifena:
            invoke GetAsyncKeyState, VK_CONTROL
            cmp eax, 0
            jne schleifenende
            jmp schleifena
        schleifenende:
        invoke GetCursorPos, addr pStruct
        mov ScreenXleft, pStruct.x ;hier hängts
        ret
    GetCoordsofCurve ENDP
    
    END start
    

    Das Problem liegt also hier:
    mov ScreenXleft, pStruct.x

    ScreenXleft = dword
    pStruct.x = long

    Gibt es da überahupt einen Unterschied?



  • Es kann nur einen Speicheroperanden geben. Du hast aber in der Zeile zwei. Also entweder push pStruct.x und pop ScreenXleft oder über ein Register (lea, mov).

    Die Schleife lässt sich übrigens vereinfachen (falls du sie nicht abändern möchtest):

    schleifena:
            invoke GetAsyncKeyState, VK_CONTROL
            cmp eax, 0
            je schleifenna
    


  • ADDR kann man immer verwende, OFFSET nur mit Ausdrücken, die schon während der Übersetzung\dem Linken bekannt sind.
    Zu deinem Problem: wie schon gesagt, in der x86-Archetektur gibt es kein Befehle, die 2 Speicheroperanten haben (Ausnahmen bestätigen die Regel ^^) - du musst immer über ein Register gehen. In deinem Fall gib es einen kleine macro der es erlaub 32Bit Werte im Speicher zu übertragen:

    m2m ScreenXleft,pStruct.x
    

    wird Übersetzt zu:

    push pStruct.x
    pop ScreenXleft
    


  • Jetzt habe ich alle Befehle mov Befehle mit 2 Speicheroperanden mit m2m ausgetauscht. An den anfang habe ich jetzt geschrieben:
    m2m MACRO
    , weil es sonst wieder an Fehlern gehagelt hätte.
    Nur leider bekomme ich jetzt folgenden Fehler:
    D:\masm32\projects\Project1\Project.asm(97) : fatal error A1008: unmatc
    hed macro nesting

    ;fenster.asm
    .386
    .MODEL flat,stdcall
    option casemap:none
    
    INCLUDE \masm32\include\windows.inc
    INCLUDE \masm32\include\user32.inc
    INCLUDE \masm32\include\kernel32.inc
    INCLUDELIB \masm32\lib\user32.lib
    INCLUDELIB \masm32\lib\kernel32.lib
    includelib  \masm32\lib\msvcrt.lib
    include     \masm32\include\msvcrt.inc
    include     \masm32\macros\ucmacros.asm
    includelib \masm32\include\gdi32.lib
    include \masm32\include\gdi32.inc
    
    long    TYPEDEF DWORD
    m2m MACRO
    GetCoordsofCurve PROTO 
    mainProc PROTO 
    ;20
    .DATA
    DCParam db "DISPLAY",0 ;wird für CreateDC benötigt
    ausgeben db "%d", 0
    zaehleranzeige db "Datei: ", 13, 10, 0
    dwZaehler dd 0
    .DATA?            ;uninitialisierte Daten
    ScreenXleft dword ?
    ScreenXright dword ?
    ScreenYtop dword ?
    ScreenYbottom dword ?
    .CODE
    start:
        invoke GetCoordsofCurve
    invoke ExitProcess, 0
    
    mainProc PROC 
        local myDC:HDC
        local yZaehler:dword 
        local xZaehler:dword
        m2m yZaehler, ScreenYtop ;40
        m2m xZaehler, SreenXleft
        ;===============================>hier gehts los
        invoke CreateDC, addr DCParam, NULL, NULL, NULL
        mov myDC, eax ;DC erstellen
        ;======>
        dec ScreenYtop ;um einen kleinen Denkfehler vorzubeugen ;)
    schleifenanfang:
    mov yZaehler, ScreenYtop
        schleifenanfangY:
            m2m xZaehler, ScreenXleft ;resetten
            cmp yZaehler, ScreenYbottom
            je schleifenanfang
            inc yZaehler
            schleifenanfangX:
                ;pixel auslesen
                cmp xZaehler, ScreenXright ;falls der Bildschirm einmal abgewandert wurde
                je schleifenanfangY
                inc xZaehler ;nächster pixel
                jmp schleifenanfangX
        ret
    mainProc ENDP
    
    GetCoordsofCurve PROC  ;sammelt informationen über bildschirm
        local pStruct:POINT
        schleifenaXleft: ;links oben
            invoke GetAsyncKeyState, VK_CONTROL
            cmp eax, 0
            jne schleifenendeXLeft
            jmp schleifenaXleft
        schleifenendeXLeft:
        invoke GetCursorPos, addr pStruct
        m2m ScreenXleft, pStruct.x
        m2m ScreenYtop, pStruct.y
        ;===========================>YBottom
         schleifenaYBottom: ;rechts unten
            invoke GetAsyncKeyState, VK_CONTROL
            cmp eax, 0
            jne schleifenendeYBottom
            jmp schleifenaYBottom
        schleifenendeYBottom:
        invoke GetCursorPos, addr pStruct
        m2m ScreenYbottom, pStruct.y
        m2m ScreenXright, pStruct.x
        ret
    GetCoordsofCurve ENDP
    
    END start
    

    Tschuldigung, dass ich euch jetzt mit Fragen löchere, aber ich habe noch ein paar grobe Verständnissfehler^^

    €dit: Gibt es eigentlich die Option die Zeilennummerierung bei masm32 einzuschalten? Assembler erscheint mir sowieso wie ein Wall of Text, aber ohne Nummerierung kann ich mit den Fehlern meist gar nichts anfangen...

    €dit2: Sieht so aus als ob ich das Makro falsch definiert habe...



  • du brauchst den macro nicht zu Definieren - includier einfach \masm32\macros\macros.asm

    m2m macro op1,op2
        push op2
        pop op2
    endm
    

    Zur Zeilennummerierung: einfach den Quellcode in einem Texteditor öffnen, der eine Zeilenummerierung anbietet.



  • Jetzt funktioniert endlich alles wie es soll. Aufgrund des Denkfehlers bei mov und cmp wurde ich massenhaft mit Fehlern zugeschüttet.
    Mittlerweile habe ich auch einigermaßen verstanden, wie man Macros selbst definiert.
    Ausserdem bist du jetzt für mich ein Genie. Danke dir nochmal für deine Hilfe 🙂

    €dit: Mhmm. nach Aviras Meinung bin ich jetzt ein Virenprogrammierer...


Anmelden zum Antworten