Mittwoch, 28. Mai 2014

Floppy-Boot-Sektor debuggen unter Windows

Der folgende Text beschreibt wie man auch unter Windows einen Floppy-Boot-Sektor debuggen kann. Dazu braucht man die folgenden Programme.

Editor
Ein einfacher Editor, der auch ein bisschen Syntax einfärben kann, ist Notepad++.
Terminal
Ein brauchbares Terminal, das auch in der Lage ist, Tabs anzuzeigen ist ConEmu. Man benötigt meistens vier Fenster: Emulator, Monitor, Debugger und Compiler.
Assembler
Um einen Boot-Sektor debuggen zu können, muss man ihn erst einmal erzeugen. Das geht mit NASM ganz gut.
Emulator
Am einfachsten kann man einen Boot-Sektor in einem Emulator debuggen. Der wohl mächtigste Emulator ist Qemu. Fertige Binaries für Windows gibt es bei Stefan Weil.
Debugger
Qemu arbeitet am besten mit dem GNU Debugger GDB zusammen. Fertige Binaries für Windows gibt es bei Equation Solution.

Wie man die Programme installiert und die PATH-Variable setzte dürfte vermutlich jedem klar sein, der Boot-Sektoren debuggen will, weshalb ich darauf nicht weiter eingehe.

Boot-Sektor

Somit stellt sich als nächstes die Frage, wie ein Boot-Sektor erstellt werden kann. Das Geheimnis des Boot-Sektors ist relativ schnell erzählt. Es sind 512 Bytes Code, an deren Ende sich die Bytes 55h und AAh befinden. Da Intel den Speicher im Little-Endian-Format organisiert handelt es sich um das 16 Bit-Wort AA55h. Der Boot-Sektor wird vom BIOS an die Adresse 7C00 geladen und ausgeführt. Beim Start steht CS auf 0 und IP auf 7C00. Free Source Codes shows two example boot sectors: one doing nothing and one printing some dots on the the screen. This is the listing of the one printing dots.

     1                                   _Text SEGMENT PUBLIC USE16
     2          ******************       warning: ignoring unknown section attribute: "USE16"
     3                                  ;************************************************************
     4                                  ; Program entry point
     5                                  ; Currently we are at 0:7C00
     6                                  ;************************************************************
     7                                  org 0
     8                                  EntryPoint:
     9                                      ; Would have preferred 07C0:0000
    10                                      ; Dealing with an offset that starts at 0 is easier
    11                                      ; So do a far jump to 07C0:????
    12                                  
    13 00000000 EA[2700]C007                jmp 0x07C0:AfterData
    14                                  
    15                                  ; Your Data goes here!
    16 00000005 57656C636F6D652074-         BOOT_MSG db 'Welcome to BOOT SECTOR CODE!',10,13,0
    17 0000000E 6F20424F4F54205345-
    18 00000017 43544F5220434F4445-
    19 00000020 210A0D00           
    20 00000024 2E2000                      ACTIVITY db '. ',0
    21                                  
    22                                  AfterData:
    23                                  ; update DS to be 7C0 instead of 0
    24 00000027 0E                      push CS
    25 00000028 1F                      pop DS
    26                                  
    27                                  ; update ES also
    28 00000029 0E                      push CS
    29 0000002A 07                      pop ES
    30                                  
    31                                  ; create stack
    32 0000002B B80000                  mov ax, 0x0000
    33 0000002E 8ED0                    mov ss, ax
    34 00000030 BCFFFF                  mov sp, 0xFFFF
    35                                  
    36                                  ; display boot message...
    37 00000033 8D36[0500]              lea si, [BOOT_MSG]
    38 00000037 E81500                  call Print
    39                                  
    40                                  ; Go into a hang printing dots
    41                                  DIE_LOOP:
    42 0000003A 8D36[2400]              lea si, [ACTIVITY]
    43 0000003E E80E00                  call Print
    44 00000041 B9FFFF                  mov cx, 0xffff
    45                                  delay1:
    46 00000044 BBFF0F                  mov bx, 0xfff
    47                                  delay2:
    48 00000047 4B                      dec bx
    49 00000048 75FD                    jnz delay2
    50 0000004A 49                      dec cx
    51 0000004B 75F7                    jnz delay1
    52 0000004D EBEB                    jmp DIE_LOOP
    53                                  
    54                                  ;************************************************************
    55                                  ; Procedure print
    56                                  ; prints a zero terminated string pointed to by si
    57                                  ;************************************************************
    58                                  Print:
    59 0000004F 50                      push ax
    60 00000050 B40E                    mov ah, 14 ; BIOS code for screen display
    61 00000052 FC                      cld
    62                                  print_loop:
    63 00000053 AC                      lodsb ; moving the character to be displayed to al
    64 00000054 08C0                    or al, al ; checking if the char is NULL
    65 00000056 7404                    jz printdone
    66 00000058 CD10                    int 10h ; Calling BIOS routine
    67 0000005A EBF7                    JMP print_loop
    68                                  
    69                                  printdone:
    70 0000005C 58                      pop ax
    71 0000005D C3                      ret
    72                                  ; End of print procedure...
    73                                  
    74                                  
    75                                  ; Make the file 512 bytes long
    76 0000005E 00<rept>                TIMES 510-($-$$) DB 0 
    77                                  
    78                                  ; Add the boot signature
    79 000001FE 55AA                    dw 0AA55h

Das obige Listing entsteht beim übersetzten des Quelltextes:

nasm boot.asm -l boot.lst -o boot.bin

Debug-Emulation

Der Boot-Sektor kann direkt von Qemu als Floppy-Image zum booten verwendet werden. Wenn man das aktuelle Terminal durch den Aufruf von Qemu nicht blockieren will, kann man sich ein Batch-Script machen und Qemu mit "start /b" starten.

start /b qemu-system-i386 -gdb tcp:127.0.0.1:1234 -monitor telnet:127.0.0.1:1235,server,nowait -S -localtime -fda boot.bin -boot a -no-fd-bootchk

Die Option -gdb öffnet Port 1234 und ermöglicht den Remote-Zugriff durch den Debugger. Das geht im GDB mit folgendem Befehl.

target remote localhost:1234

Und die Option -monitor ermöglicht es mit Telnet auf den Qemu-Monitor zugreifen zu können.

telnet localhost 1235

Da die virtuelle Maschine über die Option -S im gestoppten Modus gestartet wurde, muss man im GDB das System mit c erst starten. Wenn alles richtig funktioniert, werden im Qemu-Fenster der Reihe nach einzelne Punkte ausgegeben.

Dienstag, 6. Mai 2014

Wolfs-Rechtschreibprüfung

Gerne hätte ich gewusst, wie Microsoft auf die Idee kam, dass ich "wollte" durch "Wolfs" ersetzten müsste.

Wie gut dass es noch keinen Sprachassistenten von Microsoft gibt.

Montag, 5. Mai 2014

Negative Look Ahead in less

The Unix tool 'less' is often used to view log files on Unix systems. But sometimes it is hard to find the right place. Less supports extended regular expressions to search through the log file. Extended means that Less supports unlike many other Unix tools "look ahead" expressions. This is very useful if you try to find the occurrence of "50" but not "500". The following expression will search for a "50" not followed by a second "0":
/50(?!0)