Debuggen von ausführbaren Programmen (aber ohne Symboltabelle und ohne Source) unter Linux

  • Hallo,

    verstehe irgendwie 'gdb' nicht.

    Ich möchte wie unter MS-DOS (da geht's halt mit DEBUG) eine beliebige, ausführbare Datei Schritt für Schritt ausführen.

    Der Debugger 'gdb' kann das normalerweise, aber das ELF-Executable hat weder Symboltabelle noch habe ich die Quelldatei dazu.

    Trotzdem muss es ja möglich sein, Schritt für Schritt eine ausführbare Datei auszuführen.

    Nach kurzer Recherche sollte 'info file' die Ausgabe mit der Start-Adresse ausspucken.

    Dann kann man den 'breakpoint' setzen (vorangestelltes * bei Adressen statt Symbolen) und mit 'run' ausführen.

    Ausgeführt wird auch was, aber der Breakpoint wird nicht erkannt/durchlaufen.

    Siehe Bild... wie mache ich es richtig ?

    Irgendwie erzeugt hier der Monitor ein Moiré Muster, dachte immer TFT Monitore machen das nicht... ich hoffe aber man kann es trotzdem lesen...

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • ThoralfAsmussen : Das war schon fast wieder gut, aber als Witz ;)


    Nein, aber mal im Ernst, was soll 'start' machen ? Bei mir kommt nur "undefined command" als Antwort.


    'n' (= next) geht nur, wenn das Programm tatsächlich gestartet ist. Nur wird das halt nicht mit 'start' gemacht, sondern mit 'run'.

    'start' wäre als breakpoint ok (so wäre auch 'main' passend), wenn das Programm "symbols" noch drin hätte. Hat es aber nicht.


    Ich muss nur einen passenden breakpoint setzen, aber das klappt nicht mit den Angaben, die aus 'info files' rauskommen.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Ok, herausgefunden. Der benötigte breakpoint ist nicht mit der Sektion .text identisch sondern mit .init ...

    Also führt ein folgendes 'run' auch nicht mehr das komplette Programm aus, sondern der Instruction Pointer steht auf der breakpoint Adresse.

    Dann kann mit 'stepi' eine Instruktion oder mit 'nexti' eine Instruktion inklusive einer Subroutine ausgeführt werden.

    Nur 'next' (bzw. 'n') geht nicht, weil wie bereits erwähnt das Programm keine Symbole hat.

    Mit 'disass' und zwei Adressen als Bereich kann man dann auch den Teil anzeigen, der gerade interessant ist.

    Bei der Gelegenheit habe ich auch herausgefunden, wie ich Screenshots machen kann (mit 'xwd', danach mit gimp in PNG umwandeln).


    Schön auch, das gdb alle breakpoints sich merkt, wenn man einen nicht braucht, kann man den erstmal via 'disable' ausschalten, ohne dass er gleich gelöscht ist. Löschen von breakpoints geht natürlich auch. Register anschauen geht dann auch mit 'info registers'.

    Ist alles nicht so komfortabel, aber geht erstmal.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • 'start' macht wohl das gleiche wie run, aber setzt anscheinend einen breakpoint bei main().


    Bei mir funktioniert das zumindest anfangs mal, breakpoint habe ich mit "b funktionsname" gesetzt. Dort wird dann gehalten und man kann mit info Sachen abfragen. Aber es bedient sich schon komisch. Wahrscheinlich so ein Tool, wo man erstmal die Kürzel draufhaben muß.



    Die Anleitung gibt es wohl als "info gdb", aber vielleicht gab es das bei dem Uralt Unix da noch nicht, wer weiß. Man findet aber einen Ausdruck Debugger.pdf davon.


    Die man Page in alter Ausgabe, findet man u.a. da

    https://nixdoc.net/man-pages/Linux/man1/gdb.1.html


    Keine Ahung, ob Dir das PDF weiterhilft. Vielleicht ja doch.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • Da ist noch eine hübsche und ältere Anleitung


    https://ftp.gnu.org/old-gnu/Ma…html_chapter/gdb_toc.html



    Habe auch nochmal geschaut, was das so tut (nicht, daß ich das brauchen könnte). Was schön geht ist "start" in Kombination mit "c" (continue). Die breakpoints auf die Funktionsnamen lassen sich setzen - mit "b line" oder "b rectangle" - dann wird immer vorm Malen des nächsten Elements angehalten. Wenn die natürlich nicht bekannt sind ... wirst Du eventuell erstmal mit einem disassmebler die Adressen rausbekommen müssen, wo Du anhalten willst. "disass" in gdb geht hier auch und zeigt 3 Zeilen Code an.


    Sehr schön an "c" ist, daß man mit "c 5" z.B. 5 breaks weiterspringen kann. Der Stop kommt dann erst in Runde 6.




    Nochwas zur Benutzung. "xwd" macht sich sehr schön in Kombination mit ImageMagick, was meist eh installiert ist. (GIMP geht natürlich auch) Üblicherweise legt man sich dann ein " xwd | convert - Shoot.png " in ein alias oder gleich auf eine Tastenkombination. Wenn man Datum dazu haben will " xwd | convert - Shoot#`date +%Y-%m-%d#%H-%m`.png ", das sieht nicht schön aus, taugt aber.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

    Einmal editiert, zuletzt von ThoralfAsmussen ()

  • Habe mal nach ImageMagick in einer passenden alten Version (pre 5.0) gesucht, also das war gar nicht so einfach.

    In archive.org findet man natürlich jede Menge Links, aber alle auf ftp-Server Verzeichnisse verweisend.

    Leider archiviert archive.org aber überhaupt keine ftp-Server.... so was wäre cool, ein archive.org für FTP-Server, ist aber wohl im Jahr 2022 zu spät, für die Jahre 1998-2002 was zu tun.

    Wenn man aber ein Dateiname kennt, findet sich durch das gezielte Suchen danach doch noch was, auch wenn es schon eine 23 Jahre alte Version ist.

    Auf metu.edu.tr habe ich ein Mirror Verzeichnis für "ImageMagick-4.2.8.tar.gz" gefunden, jetzt muss ich es erst noch kompilieren können.

    ThoralfAsmussen - ich suche keine neuen Versionen für neue Linux-Versionen, das muss zur Distribution passen (also bspw. wäre auch ein rpm Paket für Red Hat 5.2 passend - gleiches Baujahr wie die genutzte Caldera Linux 1.3 Version, gleicher Paketierer, also rpm).


    P.S.: Auf https://ftp.gwdg.de/pub/x11/x.org/contrib/applications/ findet man auch das alte Zeug ;)

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Red hat 5.2 hat auch die libc5 in der Distro drin. Keine Ahnung, ich probier's mal aus...


    Edit: Nein, geht nicht. libc6 wird tatsächlich benötigt :(


    failed dependencies:

    ld-linux.so.2 is needed by ImageMagick-4.1.0-1

    libc.so.6 is needed by ImageMagick-4.1.0-1

    libjpeg.so.62 is needed by ImageMagick-4.1.0-1

    libm.so.6 is needed by ImageMagick-4.1.0-1

    libnsl.so.1 is needed by ImageMagick-4.1.0-1

    libpng.so.2 is needed by ImageMagick-4.1.0-1


    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

    Einmal editiert, zuletzt von Peter z80.eu ()

  • Red hat 5.2 hat auch die libc5 in der Distro drin. Keine Ahnung, ich probier's mal aus... Edit: Nein, geht nicht. libc6 wird tatsächlich benötigt :(

    Aus Linux Quake HOWTO:

    Zitat
    [ ... ] Newer Linux distributions like RedHat 5.1 and Debian 2.0 use the incompatible glibc as their default C library. Both RedHat 5 and Debian 2 have libc5 compatibility packages that allow you to run libc5-based applications. [ ... ]

    ... vielleicht wäre hier RedHat oder Debian doch die "bessere" Wahl ...

  • Je neuer der Rechner, umso neuer auch die eingesetzte Software.

    Historisch korrekt für einen Rechner aus dem Jahr 1996/1997 ist halt keine neuere Linux Distribution. Man kann auch gimp benutzen, das ist auf dem Rechner ja vorhanden. ImageMagick ist ja kein muss, deswegen werde ich nicht erneut stundenlang versuchen, was zu installieren.

    Ich wollte ein vorhandenes ELF Executable welches aus der alten Linux Distri, die auf der FB vorhanden war, debuggen, was die Front-LEDs der Watchguard FB100 zum "Blinken" bringt. Das habe ich bzw. ich weiss wie ich es hinkriege.

    Eine Diskussion über "welches Linux oder welches Betriebssytem" schöner wäre, ist wahrscheinlich total fruchtlos, wenn man eigentlich zum Ziel hat, etwas "historisch korrekt" zu nutzen.

    Ja, Red Hat 5.2 wäre wohl für libc6 basierte Programme besser gewesen. Aber da fällt mir dazu der Spruch von Steinbrück mit der Fahrradkette ein...

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Nachdem du jetzt in der Lage bist, das Programm auf einen (sehr frühen) Breakpoint laufen zu lassen, wirst du gleich auf ein anderes Problemchen stoßen - Nämlich, dass du dich erst mal durch den Startup-Code und die Library-Initialisierungen wühlen musst. Bis das eigentliche Programm anfängt, kommt hier normalerweise erstmal ziemlich viel.


    Ich würde, wenn mir das Ernst wäre, erstmal das binary mit Ghidra analysieren, um rauszufinden, wo denn wohl main() sein könnte.

  • Nein, alles gut, ich arbeite genauso wie beim Hacken/Cracken anderer Programme... Step by step mit Ausführung von Subroutinen (via ni), wenn in der jeweiligen Subroutine dann etwas komplett ausgeführt wird, merke ich mir die Adresse des letzten Befehls, und starte neu mit dieser Adresse als Breakpoint, dann in die Subroutine rein mit si, dann weiter bis zum nächsten call, bis ich auf den Code stoße der das bewirkt, was ich untersuchen wollte.

    Also wie eine Zwiebel wo ich Schale für Schale nach innen gehe.

    Den Code habe ich so innerhalb von einer halben Stunde herausgelöst. Der Rest macht die Routine dann, schwieriger sind nur Anti-Debug-Maßnahmen mit selbstmodifizierendem Code.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Ist vielleicht jetzt schon ein bisschen spät, aber von Debian gibt’s auch Archive von ganz alten Versionen. Da passt dann alles zusammen.

    Das Genie beherrscht das Chaos

  • Kann man denn .deb (also Debian InstallationsPakete) mit rpm installieren ?? Caldera Open Linux nutzte .rpm Pakete....

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Es gibt das Programm "alien". Das kann Pakete wandeln - dann klappt das auch mit "fremden" Sachen.



    Alternativ evtl. mal da http://www.ibiblio.org/pub/his…hat-4.2/i386/RedHat/RPMS/ nachschauen. Gibt freundlicherweise weiter oben auch noch andere Uralt Ausgaben zwecks Historismus.


    Man wird mindestens noch die Bildbibliotheken brauchen (png, jpg usf)



    Im Anhang sind natürlich keine bmp's :

  • Genau da (Red Hat Linux 4.2) habe ich sie auch schon hergeholt, die hat noch alles mit libc5, der Wechsel kam mit Red Hat Linux 5.0.

    Aber trotzdem ein echtes Dankeschön für die Mühe, das (auch) herauszufinden.

    Es gibt auch keine Fehler beim rpm-Installieren, funktioniert soweit. Naja, ist schon etwas einfacher als mit gimp.


    Was die LEDs der FB100 angeht, habe ich ein merkwürdiges Phänomen.

    Das ist die Subroutine, die immer wieder beim Ansteuern der LEDs benutzt wird:


    8048650: 55 pushl %ebp

    8048651: 89 e5 movl %esp,%ebp

    8048653: 8a 45 10 movb 0x10(%ebp),%al

    8048656: ba 7a 03 00 00 movl $0x37a,%edx

    804865b: ee outb %al,(%dx)

    804865c: 8a 4d 0c movb 0xc(%ebp),%cl

    804865f: f6 d1 notb %cl

    8048661: 88 c8 movb %cl,%al

    8048663: ba 78 03 00 00 movl $0x378,%edx

    8048668: ee outb %al,(%dx)

    8048669: 8a 4d 10 movb 0x10(%ebp),%cl

    804866c: fe c9 decb %cl

    804866e: 88 c8 movb %cl,%al

    8048670: ba 7a 03 00 00 movl $0x37a,%edx

    8048675: ee outb %al,(%dx)

    8048676: 89 ec movl %ebp,%esp

    8048678: 5d popl %ebp

    8048679: c3 ret


    Ich habe daher den Breakpoint immer auf 0x8048650 gesetzt.

    Bei 0x804865b, 0x8048668 und 8048675 wird der Reihe nach die I/O-Adresse 0x378, dann 0x37a und zum Schluß wieder 0x378 angesprochen.

    Beim ersten Aufruf steht das Register AL beim jeweiligen OUTB in der folgenden Reihenfolge auf den Wert 09, FF und 08.

    Danach leuchten 6 LEDs.

    Erst beim 7. Durchlauf ändert sich etwas, eine zusätzliche LED (disarmed) leuchtet.

    Das Register AL beim OUTB wird dafür in der folgenden Reihenfolge pro OUTB auf den Wert 09, C0 und 08 gesetzt.

    Jetzt leuchten 7 LEDs.

    Wenn alles ausgeschaltet wird, wird das Register AL in der folgenden Reihenfolge pro OUTB auf 09,BF und 08 gesetzt.

    Dann gehen alle LEDs aus.


    Daraus habe ich ein kleines QBASIC Programm gemacht:


    DECLARE SUB DELAY ()

    '-- fb100led.bas ------------------------------------------------

    Zahl% = 9

    OUT &H378, Zahl%

    Zahl% = &HFF

    OUT &H37A, Zahl%

    Zahl% = 8

    OUT &H378, Zahl%

    CALL DELAY

    Zahl% = 9

    OUT &H378, Zahl%

    Zahl% = &HC0

    OUT &H37A, Zahl%

    Zahl% = 8

    OUT &H378, Zahl%

    CALL DELAY

    Zahl% = 9

    OUT &H378, Zahl%

    Zahl% = &HBF

    OUT &H37A, Zahl%

    Zahl% = 8

    OUT &H378, Zahl%


    PRINT "I/O Adresse "; &H378; " und "; &H37A; " wurden 3x angesprochen"


    SUB DELAY

    StartZeit = TIMER

    VergangeneZeit = 0!

    WHILE VergangeneZeit < 1

    VergangeneZeit = TIMER - StartZeit

    WEND

    END SUB


    Aber beim Ausführen passiert (im Gegensatz zum Linux Programm) nichts.

    Danach habe ich Ctrl-Alt-Del gedrückt um wieder das Linux zu booten (LILO sei Dank kann ich ja wählen).

    JETZT ERST leuchten die LEDs....

    Wenn einiges vom Linux geladen wurde, gehen die LEDs wieder aus.

    Keine Ahnung welchen Denkfehler ich gemacht habe.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

  • Und noch ein Fehlschlag, ich dachte ich probier's mal unter Linux mit Assembler.

    Dazu habe ich erstmal den nasm in einer alten Version gesucht und als Source tar Paket auch gefunden.

    Erstmal nachgeschaut wie man den kompiliert, ging aber dann ganz einfach (mit ./configure wird ein passendes makefile generiert).

    Als nasm lauffähig war, folgendes als Source für nasm genutzt:


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

    section .data

    smsg: db 'Switch on LEDs of FB100',10 ; start message

    smsglen: equ $-smsg ; Length of the string


    section .text

    global _start


    _start:

    mov eax,4 ; The system call for write (sys_write)

    mov ebx,1 ; File descriptor 1 - standard output

    mov ecx,smsg ; Put the offset of startmessage in ecx

    mov edx,smsglen ; smsglen is a constant, so we don't need to say

    ; mov edx,[smsglen] to get it's actual value

    int 80h ; Call the kernel


    mov al,09h

    mov dx,0378h

    out dx,al


    mov al,0ffh

    mov dx,037ah

    out dx,al


    mov al,08h

    mov dx,0378h

    out dx,al


    mov eax,1 ; The system call for exit (sys_exit)

    mov ebx,0 ; Exit with return code of 0 (no error)

    int 80h

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


    Dann noch assembliert und zum elf-Executable gelinkt:

    nasm -f elf led.asm

    ld -s -o led led.o


    Ein ./led bringt aber dann ein Segmentation Fault :( Was darf man nicht unter Linux - etwa 'out'-Befehle nutzen ?


    Edit: Ok, ist ja "user mode", nein, darf man nicht. Mit https://man7.org/linux/man-pages/man2/ioperm.2.html kriegt man die passende Funktion dazu.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

    Einmal editiert, zuletzt von Peter z80.eu ()

  • Hier der funktionierende Assembler Code für Linux (und "nasm"):


    section .data

    smsg: db 'Switch on LEDs of FB100',10 ; start message

    smsglen: equ $-smsg ; Length of the string


    section .text

    global _start


    _start:

    mov eax,4 ; The system call for write (sys_write)

    mov ebx,1 ; File descriptor 1 - standard output

    mov ecx,smsg ; Put the offset of startmessage in ecx

    mov edx,smsglen ; smsglen is a constant, so we don't need to say

    ; mov edx,[smsglen] to get it's actual value

    int 80h ; Call the kernel


    mov eax,101 ; sys_ioperm

    mov ebx,0378h ; I/O address start

    mov ecx,3 ; number of subsequent ports

    mov edx,1 ; turn permission on (value must be not 0)

    int 80h ; Call the kernel


    mov al,09h

    mov dx,037ah

    out dx,al


    mov al,0ffh

    mov dx,0378h

    out dx,al


    mov al,08h

    mov dx,037ah

    out dx,al


    mov eax,101 ; sys_ioperm

    mov ebx,0378h ; I/O address start

    mov ecx,3 ; number of subsequent ports

    mov edx,0 ; turn permission off

    int 80h ; Call the kernel


    mov eax,1 ; The system call for exit (sys_exit)

    mov ebx,0 ; Exit with return code of 0 (no error)

    int 80h


    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.

    Einmal editiert, zuletzt von Peter z80.eu ()

  • Und hier das Gleiche (und ein bisschen mehr) in QBASIC unter DOS:


    DECLARE SUB DELAY ()

    '-- fb100led.bas ------------------------------------------------

    Zahl% = 9

    OUT &H37A, Zahl%

    Zahl% = &HFF

    OUT &H378, Zahl%

    Zahl% = 8

    OUT &H37A, Zahl%

    '-- 6 LEDs were switched on

    CALL DELAY

    Zahl% = 9

    OUT &H37A, Zahl%

    Zahl% = &HC0

    OUT &H378, Zahl%

    Zahl% = 8

    OUT &H37A, Zahl%

    '-- at least 7 LEDs were switched on

    CALL DELAY

    Zahl% = 9

    OUT &H37A, Zahl%

    Zahl% = &HBF

    OUT &H378, Zahl%

    Zahl% = 8

    OUT &H37A, Zahl%

    '-- all LEDs were switched off

    PRINT "I/O Adresse "; &H378; " und "; &H37A; " wurden angesprochen"


    SUB DELAY

    StartZeit = TIMER

    VergangeneZeit = 0!

    WHILE VergangeneZeit < 1

    VergangeneZeit = TIMER - StartZeit

    WEND

    END SUB


    Damit lassen sich die LEDs im Frontpanel der Watchguard FB 100 auch ansteuern.

    "The biggest communication problem is we do not listen to understand. We listen to reply." - Stephen Covey


    Webseite und Blog ist immer noch - seit fast 20 Jahren - online.